问:
HTTP Origin header (https://myapp.com) didn't match request.base_url (http://myapp.com)
I'm using Rails 6, Devise for authentication and testing my app on Google Chrome. I can log in successfully. However when the user tries to log out by clicking on the Log Out button, it doesn't log out and only redirects to the home page.

I have the application containerised using Docker and Docker Compose and I'm using PostgreSQL for the database, ElasticSearch for search and NGINX for the web server.

This appears to be a caching or cookie issue. When I delete the _myapp_session cookie in Google Chrome Developer Tools in the Storage section under the Application tab, then refresh, the issue is fixed and the user is logged out.

UPDATE: The issue was being caused by:

```<code>HTTP Origin header (https://myapp.com) didn't match request.base_url (http://myapp.com)
</code>```

Here's the logs from NGINX server console (frontend_1) when visiting the website, logging in and then making the log out request.

```<code>frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:19:57 +0000] "GET / HTTP/1.1" 200 6087 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:19:58 +0000] "GET /assets/application-29dded2730529466cbe16f8bf7dff8cd81c27f5c29357a0ee19ce611c7fae223.css HTTP/1.1" 200 24974 "https://myapp.ie/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:19:58 +0000] "GET /packs/js/application-e72ce6426a0e2e571ed2.js HTTP/1.1" 200 18152 "https://myapp.ie/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:19:58 +0000] "GET /packs/js/counter-a7c63b11c8fcb5e204df.js HTTP/1.1" 200 642 "https://myapp.ie/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
web_1            | I, [2021-01-30T13:19:58.193455 #1]  INFO -- : Started GET "/assets/glassfacade.jpg" for 37.228.235.151 at 2021-01-30 13:19:58 +0000
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:19:58 +0000] "GET /assets/glassfacade.jpg HTTP/1.1" 304 0 "https://myapp.ie/assets/application-29dded2730529466cbe16f8bf7dff8cd81c27f5c29357a0ee19ce611c7fae223.css" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:19:58 +0000] "GET /service-worker.js HTTP/1.1" 304 0 "https://myapp.ie/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
web_1            | I, [2021-01-30T13:20:07.240769 #1]  INFO -- : Started GET "/users/sign_in" for 37.228.235.151 at 2021-01-30 13:20:07 +0000
web_1            | I, [2021-01-30T13:20:07.242349 #1]  INFO -- : Processing by Devise::SessionsController#new as HTML
web_1            | I, [2021-01-30T13:20:07.270212 #1]  INFO -- :   Rendering devise/sessions/new.html.erb within layouts/application
web_1            | I, [2021-01-30T13:20:07.277828 #1]  INFO -- :   Rendered devise/shared/_links.html.erb (Duration: 1.8ms | Allocations: 674)
web_1            | I, [2021-01-30T13:20:07.278818 #1]  INFO -- :   Rendered devise/sessions/new.html.erb within layouts/application (Duration: 7.8ms | Allocations: 1788)
web_1            | I, [2021-01-30T13:20:07.280610 #1]  INFO -- :   Rendered layouts/nav/_public.html.erb (Duration: 0.5ms | Allocations: 245)
web_1            | I, [2021-01-30T13:20:07.281343 #1]  INFO -- :   Rendered layouts/_footer.html.erb (Duration: 0.0ms | Allocations: 5)
web_1            | I, [2021-01-30T13:20:07.282268 #1]  INFO -- : Completed 200 OK in 39ms (Views: 14.5ms | ActiveRecord: 7.6ms | Allocations: 15604)
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:20:07 +0000] "GET /users/sign_in HTTP/1.1" 200 5629 "https://myapp.ie/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
web_1            | I, [2021-01-30T13:20:09.081121 #1]  INFO -- : Started POST "/users/sign_in" for 37.228.235.151 at 2021-01-30 13:20:09 +0000
web_1            | I, [2021-01-30T13:20:09.082596 #1]  INFO -- : Processing by Devise::SessionsController#create as HTML
web_1            | I, [2021-01-30T13:20:09.083112 #1]  INFO -- :   Parameters: {"authenticity_token"=>"/ANjiDtsz6E4C8/jmmZ+i1hGi7fxQ2W3I/mxKKCKwapYEeJiK5QSRplAbyTWO541xDZc9Er9MB0Whbyz97SB0w==", "user"=>{"email"=>"myapp@gmail.com", "password"=>"[FILTERED]"}}
web_1            | D, [2021-01-30T13:20:09.091385 #1] DEBUG -- :   User Load (1.7ms)  SELECT "users".* FROM "users" WHERE "users"."email" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["email", "myapp@gmail.com"], ["LIMIT", 1]]
web_1            | D, [2021-01-30T13:20:09.337144 #1] DEBUG -- :    (0.3ms)  BEGIN
web_1            | D, [2021-01-30T13:20:09.339573 #1] DEBUG -- :   User Update (1.5ms)  UPDATE "users" SET "current_sign_in_at" = $1, "last_sign_in_at" = $2, "sign_in_count" = $3, "updated_at" = $4 WHERE "users"."id" = $5  [["current_sign_in_at", "2021-01-30 13:20:09.334709"], ["last_sign_in_at", "2021-01-30 12:40:17.072091"], ["sign_in_count", 72], ["updated_at", "2021-01-30 13:20:09.336027"], ["id", 3]]
web_1            | D, [2021-01-30T13:20:09.341133 #1] DEBUG -- :    (0.6ms)  COMMIT
web_1            | I, [2021-01-30T13:20:09.344229 #1]  INFO -- : Redirected to http://myapp.ie/
web_1            | I, [2021-01-30T13:20:09.344743 #1]  INFO -- : Completed 302 Found in 261ms (ActiveRecord: 4.3ms | Allocations: 5188)
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:20:09 +0000] "POST /users/sign_in HTTP/1.1" 302 97 "https://myapp.ie/users/sign_in" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:20:09 +0000] "GET / HTTP/1.1" 301 169 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
web_1            | I, [2021-01-30T13:20:09.451080 #1]  INFO -- : Started GET "/" for 37.228.235.151 at 2021-01-30 13:20:09 +0000
web_1            | I, [2021-01-30T13:20:09.452431 #1]  INFO -- : Processing by PublicController#main as HTML
web_1            | I, [2021-01-30T13:20:09.454279 #1]  INFO -- :   Rendering public/main.html.erb within layouts/application
web_1            | I, [2021-01-30T13:20:09.455073 #1]  INFO -- :   Rendered properties/_search.html.erb (Duration: 0.3ms | Allocations: 126)
web_1            | I, [2021-01-30T13:20:09.455572 #1]  INFO -- :   Rendered properties/_location_search.html.erb (Duration: 0.0ms | Allocations: 5)
web_1            | D, [2021-01-30T13:20:09.467424 #1] DEBUG -- :    (11.1ms)  SELECT COUNT(*) FROM "properties"
web_1            | D, [2021-01-30T13:20:09.493249 #1] DEBUG -- :    (24.3ms)  SELECT COUNT(*) FROM "units"
web_1            | D, [2021-01-30T13:20:09.502977 #1] DEBUG -- :    (8.0ms)  SELECT COUNT(*) FROM "leases"
web_1            | D, [2021-01-30T13:20:09.545248 #1] DEBUG -- :    (40.5ms)  SELECT SUM("units"."area") FROM "units"
web_1            | I, [2021-01-30T13:20:09.546565 #1]  INFO -- :   Rendered public/main.html.erb within layouts/application (Duration: 91.9ms | Allocations: 1925)
web_1            | D, [2021-01-30T13:20:09.548941 #1] DEBUG -- :   User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 3], ["LIMIT", 1]]
web_1            | I, [2021-01-30T13:20:09.550025 #1]  INFO -- :   Rendered layouts/nav/_public.html.erb (Duration: 2.3ms | Allocations: 480)
web_1            | I, [2021-01-30T13:20:09.550538 #1]  INFO -- :   Rendered layouts/_footer.html.erb (Duration: 0.0ms | Allocations: 5)
web_1            | I, [2021-01-30T13:20:09.551270 #1]  INFO -- : Completed 200 OK in 98ms (Views: 12.8ms | ActiveRecord: 84.3ms | Allocations: 3343)
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:20:09 +0000] "GET / HTTP/1.1" 200 6293 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
web_1            | I, [2021-01-30T13:20:09.691278 #1]  INFO -- : Started GET "/assets/glassfacade.jpg" for 37.228.235.151 at 2021-01-30 13:20:09 +0000
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:20:09 +0000] "GET /assets/glassfacade.jpg HTTP/1.1" 304 0 "https://myapp.ie/assets/application-29dded2730529466cbe16f8bf7dff8cd81c27f5c29357a0ee19ce611c7fae223.css" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:20:11 +0000] "GET /service-worker.js HTTP/1.1" 304 0 "https://myapp.ie/service-worker.js" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
web_1            | I, [2021-01-30T13:20:12.198820 #1]  INFO -- : Started GET "/about" for 37.228.235.151 at 2021-01-30 13:20:12 +0000
web_1            | I, [2021-01-30T13:20:12.200636 #1]  INFO -- : Processing by PublicController#about as HTML
web_1            | I, [2021-01-30T13:20:12.202063 #1]  INFO -- :   Rendering public/about.html.erb within layouts/application
web_1            | I, [2021-01-30T13:20:12.203238 #1]  INFO -- :   Rendered public/about.html.erb within layouts/application (Duration: 0.7ms | Allocations: 81)
web_1            | D, [2021-01-30T13:20:12.205584 #1] DEBUG -- :   User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 3], ["LIMIT", 1]]
web_1            | I, [2021-01-30T13:20:12.206563 #1]  INFO -- :   Rendered layouts/nav/_public.html.erb (Duration: 2.4ms | Allocations: 489)
web_1            | I, [2021-01-30T13:20:12.207090 #1]  INFO -- :   Rendered layouts/_footer.html.erb (Duration: 0.0ms | Allocations: 5)
web_1            | I, [2021-01-30T13:20:12.207775 #1]  INFO -- : Completed 200 OK in 7ms (Views: 5.5ms | ActiveRecord: 0.3ms | Allocations: 1520)
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:20:12 +0000] "GET /about HTTP/1.1" 200 5118 "https://myapp.ie/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
web_1            | I, [2021-01-30T13:20:13.659115 #1]  INFO -- : Started DELETE "/users/sign_out" for 37.228.235.151 at 2021-01-30 13:20:13 +0000
web_1            | I, [2021-01-30T13:20:13.660569 #1]  INFO -- : Processing by Devise::SessionsController#destroy as HTML
web_1            | I, [2021-01-30T13:20:13.661108 #1]  INFO -- :   Parameters: {"authenticity_token"=>"i/QcCh+oNqxaSVc8zFsi/AquQe4gZrde5Q27jQPofDqf24T3SiQtVDfuQn5064O0CpKIjcYSadJLcnxbxjMsMA=="}
web_1            | D, [2021-01-30T13:20:13.663275 #1] DEBUG -- :   User Load (0.4ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 3], ["LIMIT", 1]]
web_1            | W, [2021-01-30T13:20:13.664093 #1]  WARN -- : HTTP Origin header (https://myapp.ie) didn't match request.base_url (http://myapp.ie)
web_1            | I, [2021-01-30T13:20:13.668687 #1]  INFO -- : Redirected to http://myapp.ie/
web_1            | I, [2021-01-30T13:20:13.669386 #1]  INFO -- : Completed 302 Found in 8ms (ActiveRecord: 0.4ms | Allocations: 1567)
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:20:13 +0000] "POST /users/sign_out HTTP/1.1" 302 97 "https://myapp.ie/about" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:20:13 +0000] "GET / HTTP/1.1" 301 169 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
web_1            | I, [2021-01-30T13:20:13.743342 #1]  INFO -- : Started GET "/" for 37.228.235.151 at 2021-01-30 13:20:13 +0000
web_1            | I, [2021-01-30T13:20:13.744745 #1]  INFO -- : Processing by PublicController#main as HTML
web_1            | I, [2021-01-30T13:20:13.746818 #1]  INFO -- :   Rendering public/main.html.erb within layouts/application
web_1            | I, [2021-01-30T13:20:13.747823 #1]  INFO -- :   Rendered properties/_search.html.erb (Duration: 0.3ms | Allocations: 122)
web_1            | I, [2021-01-30T13:20:13.748429 #1]  INFO -- :   Rendered properties/_location_search.html.erb (Duration: 0.0ms | Allocations: 5)
web_1            | D, [2021-01-30T13:20:13.761225 #1] DEBUG -- :    (12.0ms)  SELECT COUNT(*) FROM "properties"
web_1            | D, [2021-01-30T13:20:13.788611 #1] DEBUG -- :    (25.5ms)  SELECT COUNT(*) FROM "units"
web_1            | D, [2021-01-30T13:20:13.798794 #1] DEBUG -- :    (8.5ms)  SELECT COUNT(*) FROM "leases"
web_1            | D, [2021-01-30T13:20:13.857923 #1] DEBUG -- :    (57.4ms)  SELECT SUM("units"."area") FROM "units"
web_1            | I, [2021-01-30T13:20:13.859815 #1]  INFO -- :   Rendered public/main.html.erb within layouts/application (Duration: 112.4ms | Allocations: 1912)
web_1            | D, [2021-01-30T13:20:13.862652 #1] DEBUG -- :   User Load (0.5ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 3], ["LIMIT", 1]]
web_1            | I, [2021-01-30T13:20:13.864165 #1]  INFO -- :   Rendered layouts/nav/_public.html.erb (Duration: 2.9ms | Allocations: 456)
web_1            | I, [2021-01-30T13:20:13.864897 #1]  INFO -- :   Rendered layouts/_footer.html.erb (Duration: 0.0ms | Allocations: 5)
web_1            | I, [2021-01-30T13:20:13.865864 #1]  INFO -- : Completed 200 OK in 120ms (Views: 15.4ms | ActiveRecord: 103.8ms | Allocations: 3267)
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:20:13 +0000] "GET / HTTP/1.1" 200 6214 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
web_1            | I, [2021-01-30T13:20:15.624864 #1]  INFO -- : Started GET "/about" for 37.228.235.151 at 2021-01-30 13:20:15 +0000
web_1            | I, [2021-01-30T13:20:15.626281 #1]  INFO -- : Processing by PublicController#about as HTML
web_1            | I, [2021-01-30T13:20:15.627529 #1]  INFO -- :   Rendering public/about.html.erb within layouts/application
web_1            | I, [2021-01-30T13:20:15.627986 #1]  INFO -- :   Rendered public/about.html.erb within layouts/application (Duration: 0.0ms | Allocations: 5)
web_1            | D, [2021-01-30T13:20:15.630172 #1] DEBUG -- :   User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 3], ["LIMIT", 1]]
web_1            | I, [2021-01-30T13:20:15.631174 #1]  INFO -- :   Rendered layouts/nav/_public.html.erb (Duration: 2.3ms | Allocations: 488)
web_1            | I, [2021-01-30T13:20:15.631643 #1]  INFO -- :   Rendered layouts/_footer.html.erb (Duration: 0.0ms | Allocations: 5)
web_1            | I, [2021-01-30T13:20:15.632284 #1]  INFO -- : Completed 200 OK in 5ms (Views: 4.6ms | ActiveRecord: 0.3ms | Allocations: 1333)
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:20:15 +0000] "GET /about HTTP/1.1" 200 5118 "https://myapp.ie/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:20:15 +0000] "GET /service-worker.js HTTP/1.1" 304 0 "https://myapp.ie/service-worker.js" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
</code>```

My Devise controllers are all standard (I haven't edited them).

Here's my Application Controller

```<code>class ApplicationController < ActionController::Base

    # To clear cache to allow logging out.
    before_action :set_cache_headers

    protect_from_forgery prepend: true

    # To enable sign in to function correctly.
    skip_before_action :verify_authenticity_token, :only => :create

    before_action :configure_permitted_parameters, if: :devise_controller?

    def index

    end

    def set_cache_headers
        response.headers["Cache-Control"] = "no-cache, no-store"
        response.headers["Pragma"] = "no-cache"
        response.headers["Expires"] = "Mon, 01 Jan 1990 00:00:00 GMT"
    end

    protected

    # Restrict parameters for sign up input.
    def configure_permitted_parameters
        added_attrs = [:first_name, :last_name, :email, :encrypted_password, :password_confirmation, :remember_me]
        devise_parameter_sanitizer.permit(:sign_up, keys: added_attrs)
        devise_parameter_sanitizer.permit(:account_update, keys: added_attrs)
        devise_parameter_sanitizer.permit(:sign_in, keys: added_attrs)
    end

end
</code>```

Here's my Application.html.erb

```<code><!DOCTYPE html>
<html>
  <head>
    <title>MyApp</title>
    <link rel="manifest" href="manifest.webmanifest">
    <link rel="apple-touch-icon" href="/apple-touch-icon.png">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="theme-color" content="#ff8a00">
    <meta name="msapplication-navbutton--color" content="#ff8a00">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="default">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
    <link href="https://fonts.googleapis.com/css?family=Text+Me+One&display=swap" rel="stylesheet">
  </head>

  <body id="<%= controller.controller_name %>" class="<%= controller.action_name %> <%= "show-sidebar" if @show_sidebar.present? %>">
    <div class="wrapper">
      <% if @show_sidebar.nil? %>
        <header>
          <%= render "layouts/nav/public" %>
        </header>
        <%= yield %>
      <% else %>
        <%= render "layouts/nav/dashboard" %>

        <div class="container-fluid">
          <div class="row">
            <%= render "layouts/nav/sidebar" %>
            <main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-md-4 mt-4">
              <%= yield %>
            </main>
          </div>
        </div>
      <% end %>
      <div class="push"></div>
    </div>

    <%= render "layouts/footer" %>

    <div id="notifications"><%= notice %></div>

    <!-- PWA Step 1 - Registration -->
    <script type="text/javascript">
    if ('serviceWorker' in navigator) {
      window.addEventListener('load', function() {
        navigator.serviceWorker.register('/service-worker.js').then(function(registration) {
          // Registration was successful
          console.log('ServiceWorker registration successful with scope: ', registration.scope);
        }, function(err) {
          // registration failed :(
          console.log('ServiceWorker registration failed: ', err);
        });
      });
    }
    </script>
    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/feather-icons/4.9.0/feather.min.js"></script>
    <script>feather.replace()</script>
    <%= javascript_pack_tag "counter" %>
  </body>
</html>
</code>```

Here's the part of the view that displays the Log In / Log Out link.

```<code><ul class="navbar-nav mr-auto" id="right-nav-menu">
      <li class="nav-item">
      <% if notice %>
        <p class="nav-link"><%= notice %></p>
      <% end %>
      <% if alert %>
        <p class="nav-link"><%= alert %></p>
      <% end %>
      </li>
      <li class="nav-item">
      <% if user_signed_in? %>
        <strong class="nav-link"><p><%= current_user.first_name %> <%= current_user.last_name %></p></strong>
      <% end %>
      </li>
      <% if user_signed_in? %>
        <li class="nav-item">
          <strong><%= link_to 'Edit Profile', edit_user_registration_path, :class => 'nav-link' %></strong>
        </li>
        <li class="nav-item">
          <strong><%= link_to "Log Out", destroy_user_session_path, method: :delete, :class => 'nav-link' %></strong>
        </li>
      <% else %>
        <li class="nav-item">
          <strong><%= link_to "Log In", new_user_session_path, :class => 'nav-link' %></strong>
        </li>
        <li class="nav-item">
          <strong><%= link_to "Sign Up", new_user_registration_path, :class => 'nav-link'  %></strong>
        </li>
      <% end %>
    </ul>
</code>```

I'm not sure if there's any other code that would be helpful to resolve but if so, please let me know and I will add to the above. Appreciate any help.

答:
In my humble opinion, there is a better option:

```<code>proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Ssl on;
</code>```

Found here: https://stackoverflow.com/a/57182441/3505166

Body:
I'm using Rails 6, Devise for authentication and testing my app on Google Chrome. I can log in successfully. However when the user tries to log out by clicking on the Log Out button, it doesn't log out and only redirects to the home page.

I have the application containerised using Docker and Docker Compose and I'm using PostgreSQL for the database, ElasticSearch for search and NGINX for the web server.

This appears to be a caching or cookie issue. When I delete the _myapp_session cookie in Google Chrome Developer Tools in the Storage section under the Application tab, then refresh, the issue is fixed and the user is logged out.

UPDATE: The issue was being caused by:

HTTP Origin header (https://myapp.com) didn't match request.base_url (http://myapp.com)

Here's the logs from NGINX server console (frontend_1) when visiting the website, logging in and then making the log out request.

frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:19:57 +0000] "GET / HTTP/1.1" 200 6087 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:19:58 +0000] "GET /assets/application-29dded2730529466cbe16f8bf7dff8cd81c27f5c29357a0ee19ce611c7fae223.css HTTP/1.1" 200 24974 "https://myapp.ie/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:19:58 +0000] "GET /packs/js/application-e72ce6426a0e2e571ed2.js HTTP/1.1" 200 18152 "https://myapp.ie/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:19:58 +0000] "GET /packs/js/counter-a7c63b11c8fcb5e204df.js HTTP/1.1" 200 642 "https://myapp.ie/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
web_1            | I, [2021-01-30T13:19:58.193455 #1]  INFO -- : Started GET "/assets/glassfacade.jpg" for 37.228.235.151 at 2021-01-30 13:19:58 +0000
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:19:58 +0000] "GET /assets/glassfacade.jpg HTTP/1.1" 304 0 "https://myapp.ie/assets/application-29dded2730529466cbe16f8bf7dff8cd81c27f5c29357a0ee19ce611c7fae223.css" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:19:58 +0000] "GET /service-worker.js HTTP/1.1" 304 0 "https://myapp.ie/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
web_1            | I, [2021-01-30T13:20:07.240769 #1]  INFO -- : Started GET "/users/sign_in" for 37.228.235.151 at 2021-01-30 13:20:07 +0000
web_1            | I, [2021-01-30T13:20:07.242349 #1]  INFO -- : Processing by Devise::SessionsController#new as HTML
web_1            | I, [2021-01-30T13:20:07.270212 #1]  INFO -- :   Rendering devise/sessions/new.html.erb within layouts/application
web_1            | I, [2021-01-30T13:20:07.277828 #1]  INFO -- :   Rendered devise/shared/_links.html.erb (Duration: 1.8ms | Allocations: 674)
web_1            | I, [2021-01-30T13:20:07.278818 #1]  INFO -- :   Rendered devise/sessions/new.html.erb within layouts/application (Duration: 7.8ms | Allocations: 1788)
web_1            | I, [2021-01-30T13:20:07.280610 #1]  INFO -- :   Rendered layouts/nav/_public.html.erb (Duration: 0.5ms | Allocations: 245)
web_1            | I, [2021-01-30T13:20:07.281343 #1]  INFO -- :   Rendered layouts/_footer.html.erb (Duration: 0.0ms | Allocations: 5)
web_1            | I, [2021-01-30T13:20:07.282268 #1]  INFO -- : Completed 200 OK in 39ms (Views: 14.5ms | ActiveRecord: 7.6ms | Allocations: 15604)
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:20:07 +0000] "GET /users/sign_in HTTP/1.1" 200 5629 "https://myapp.ie/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
web_1            | I, [2021-01-30T13:20:09.081121 #1]  INFO -- : Started POST "/users/sign_in" for 37.228.235.151 at 2021-01-30 13:20:09 +0000
web_1            | I, [2021-01-30T13:20:09.082596 #1]  INFO -- : Processing by Devise::SessionsController#create as HTML
web_1            | I, [2021-01-30T13:20:09.083112 #1]  INFO -- :   Parameters: {"authenticity_token"=>"/ANjiDtsz6E4C8/jmmZ+i1hGi7fxQ2W3I/mxKKCKwapYEeJiK5QSRplAbyTWO541xDZc9Er9MB0Whbyz97SB0w==", "user"=>{"email"=>"myapp@gmail.com", "password"=>"[FILTERED]"}}
web_1            | D, [2021-01-30T13:20:09.091385 #1] DEBUG -- :   User Load (1.7ms)  SELECT "users".* FROM "users" WHERE "users"."email" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["email", "myapp@gmail.com"], ["LIMIT", 1]]
web_1            | D, [2021-01-30T13:20:09.337144 #1] DEBUG -- :    (0.3ms)  BEGIN
web_1            | D, [2021-01-30T13:20:09.339573 #1] DEBUG -- :   User Update (1.5ms)  UPDATE "users" SET "current_sign_in_at" = $1, "last_sign_in_at" = $2, "sign_in_count" = $3, "updated_at" = $4 WHERE "users"."id" = $5  [["current_sign_in_at", "2021-01-30 13:20:09.334709"], ["last_sign_in_at", "2021-01-30 12:40:17.072091"], ["sign_in_count", 72], ["updated_at", "2021-01-30 13:20:09.336027"], ["id", 3]]
web_1            | D, [2021-01-30T13:20:09.341133 #1] DEBUG -- :    (0.6ms)  COMMIT
web_1            | I, [2021-01-30T13:20:09.344229 #1]  INFO -- : Redirected to http://myapp.ie/
web_1            | I, [2021-01-30T13:20:09.344743 #1]  INFO -- : Completed 302 Found in 261ms (ActiveRecord: 4.3ms | Allocations: 5188)
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:20:09 +0000] "POST /users/sign_in HTTP/1.1" 302 97 "https://myapp.ie/users/sign_in" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:20:09 +0000] "GET / HTTP/1.1" 301 169 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
web_1            | I, [2021-01-30T13:20:09.451080 #1]  INFO -- : Started GET "/" for 37.228.235.151 at 2021-01-30 13:20:09 +0000
web_1            | I, [2021-01-30T13:20:09.452431 #1]  INFO -- : Processing by PublicController#main as HTML
web_1            | I, [2021-01-30T13:20:09.454279 #1]  INFO -- :   Rendering public/main.html.erb within layouts/application
web_1            | I, [2021-01-30T13:20:09.455073 #1]  INFO -- :   Rendered properties/_search.html.erb (Duration: 0.3ms | Allocations: 126)
web_1            | I, [2021-01-30T13:20:09.455572 #1]  INFO -- :   Rendered properties/_location_search.html.erb (Duration: 0.0ms | Allocations: 5)
web_1            | D, [2021-01-30T13:20:09.467424 #1] DEBUG -- :    (11.1ms)  SELECT COUNT(*) FROM "properties"
web_1            | D, [2021-01-30T13:20:09.493249 #1] DEBUG -- :    (24.3ms)  SELECT COUNT(*) FROM "units"
web_1            | D, [2021-01-30T13:20:09.502977 #1] DEBUG -- :    (8.0ms)  SELECT COUNT(*) FROM "leases"
web_1            | D, [2021-01-30T13:20:09.545248 #1] DEBUG -- :    (40.5ms)  SELECT SUM("units"."area") FROM "units"
web_1            | I, [2021-01-30T13:20:09.546565 #1]  INFO -- :   Rendered public/main.html.erb within layouts/application (Duration: 91.9ms | Allocations: 1925)
web_1            | D, [2021-01-30T13:20:09.548941 #1] DEBUG -- :   User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 3], ["LIMIT", 1]]
web_1            | I, [2021-01-30T13:20:09.550025 #1]  INFO -- :   Rendered layouts/nav/_public.html.erb (Duration: 2.3ms | Allocations: 480)
web_1            | I, [2021-01-30T13:20:09.550538 #1]  INFO -- :   Rendered layouts/_footer.html.erb (Duration: 0.0ms | Allocations: 5)
web_1            | I, [2021-01-30T13:20:09.551270 #1]  INFO -- : Completed 200 OK in 98ms (Views: 12.8ms | ActiveRecord: 84.3ms | Allocations: 3343)
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:20:09 +0000] "GET / HTTP/1.1" 200 6293 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
web_1            | I, [2021-01-30T13:20:09.691278 #1]  INFO -- : Started GET "/assets/glassfacade.jpg" for 37.228.235.151 at 2021-01-30 13:20:09 +0000
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:20:09 +0000] "GET /assets/glassfacade.jpg HTTP/1.1" 304 0 "https://myapp.ie/assets/application-29dded2730529466cbe16f8bf7dff8cd81c27f5c29357a0ee19ce611c7fae223.css" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:20:11 +0000] "GET /service-worker.js HTTP/1.1" 304 0 "https://myapp.ie/service-worker.js" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
web_1            | I, [2021-01-30T13:20:12.198820 #1]  INFO -- : Started GET "/about" for 37.228.235.151 at 2021-01-30 13:20:12 +0000
web_1            | I, [2021-01-30T13:20:12.200636 #1]  INFO -- : Processing by PublicController#about as HTML
web_1            | I, [2021-01-30T13:20:12.202063 #1]  INFO -- :   Rendering public/about.html.erb within layouts/application
web_1            | I, [2021-01-30T13:20:12.203238 #1]  INFO -- :   Rendered public/about.html.erb within layouts/application (Duration: 0.7ms | Allocations: 81)
web_1            | D, [2021-01-30T13:20:12.205584 #1] DEBUG -- :   User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 3], ["LIMIT", 1]]
web_1            | I, [2021-01-30T13:20:12.206563 #1]  INFO -- :   Rendered layouts/nav/_public.html.erb (Duration: 2.4ms | Allocations: 489)
web_1            | I, [2021-01-30T13:20:12.207090 #1]  INFO -- :   Rendered layouts/_footer.html.erb (Duration: 0.0ms | Allocations: 5)
web_1            | I, [2021-01-30T13:20:12.207775 #1]  INFO -- : Completed 200 OK in 7ms (Views: 5.5ms | ActiveRecord: 0.3ms | Allocations: 1520)
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:20:12 +0000] "GET /about HTTP/1.1" 200 5118 "https://myapp.ie/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
web_1            | I, [2021-01-30T13:20:13.659115 #1]  INFO -- : Started DELETE "/users/sign_out" for 37.228.235.151 at 2021-01-30 13:20:13 +0000
web_1            | I, [2021-01-30T13:20:13.660569 #1]  INFO -- : Processing by Devise::SessionsController#destroy as HTML
web_1            | I, [2021-01-30T13:20:13.661108 #1]  INFO -- :   Parameters: {"authenticity_token"=>"i/QcCh+oNqxaSVc8zFsi/AquQe4gZrde5Q27jQPofDqf24T3SiQtVDfuQn5064O0CpKIjcYSadJLcnxbxjMsMA=="}
web_1            | D, [2021-01-30T13:20:13.663275 #1] DEBUG -- :   User Load (0.4ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 3], ["LIMIT", 1]]
web_1            | W, [2021-01-30T13:20:13.664093 #1]  WARN -- : HTTP Origin header (https://myapp.ie) didn't match request.base_url (http://myapp.ie)
web_1            | I, [2021-01-30T13:20:13.668687 #1]  INFO -- : Redirected to http://myapp.ie/
web_1            | I, [2021-01-30T13:20:13.669386 #1]  INFO -- : Completed 302 Found in 8ms (ActiveRecord: 0.4ms | Allocations: 1567)
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:20:13 +0000] "POST /users/sign_out HTTP/1.1" 302 97 "https://myapp.ie/about" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:20:13 +0000] "GET / HTTP/1.1" 301 169 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
web_1            | I, [2021-01-30T13:20:13.743342 #1]  INFO -- : Started GET "/" for 37.228.235.151 at 2021-01-30 13:20:13 +0000
web_1            | I, [2021-01-30T13:20:13.744745 #1]  INFO -- : Processing by PublicController#main as HTML
web_1            | I, [2021-01-30T13:20:13.746818 #1]  INFO -- :   Rendering public/main.html.erb within layouts/application
web_1            | I, [2021-01-30T13:20:13.747823 #1]  INFO -- :   Rendered properties/_search.html.erb (Duration: 0.3ms | Allocations: 122)
web_1            | I, [2021-01-30T13:20:13.748429 #1]  INFO -- :   Rendered properties/_location_search.html.erb (Duration: 0.0ms | Allocations: 5)
web_1            | D, [2021-01-30T13:20:13.761225 #1] DEBUG -- :    (12.0ms)  SELECT COUNT(*) FROM "properties"
web_1            | D, [2021-01-30T13:20:13.788611 #1] DEBUG -- :    (25.5ms)  SELECT COUNT(*) FROM "units"
web_1            | D, [2021-01-30T13:20:13.798794 #1] DEBUG -- :    (8.5ms)  SELECT COUNT(*) FROM "leases"
web_1            | D, [2021-01-30T13:20:13.857923 #1] DEBUG -- :    (57.4ms)  SELECT SUM("units"."area") FROM "units"
web_1            | I, [2021-01-30T13:20:13.859815 #1]  INFO -- :   Rendered public/main.html.erb within layouts/application (Duration: 112.4ms | Allocations: 1912)
web_1            | D, [2021-01-30T13:20:13.862652 #1] DEBUG -- :   User Load (0.5ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 3], ["LIMIT", 1]]
web_1            | I, [2021-01-30T13:20:13.864165 #1]  INFO -- :   Rendered layouts/nav/_public.html.erb (Duration: 2.9ms | Allocations: 456)
web_1            | I, [2021-01-30T13:20:13.864897 #1]  INFO -- :   Rendered layouts/_footer.html.erb (Duration: 0.0ms | Allocations: 5)
web_1            | I, [2021-01-30T13:20:13.865864 #1]  INFO -- : Completed 200 OK in 120ms (Views: 15.4ms | ActiveRecord: 103.8ms | Allocations: 3267)
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:20:13 +0000] "GET / HTTP/1.1" 200 6214 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
web_1            | I, [2021-01-30T13:20:15.624864 #1]  INFO -- : Started GET "/about" for 37.228.235.151 at 2021-01-30 13:20:15 +0000
web_1            | I, [2021-01-30T13:20:15.626281 #1]  INFO -- : Processing by PublicController#about as HTML
web_1            | I, [2021-01-30T13:20:15.627529 #1]  INFO -- :   Rendering public/about.html.erb within layouts/application
web_1            | I, [2021-01-30T13:20:15.627986 #1]  INFO -- :   Rendered public/about.html.erb within layouts/application (Duration: 0.0ms | Allocations: 5)
web_1            | D, [2021-01-30T13:20:15.630172 #1] DEBUG -- :   User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 3], ["LIMIT", 1]]
web_1            | I, [2021-01-30T13:20:15.631174 #1]  INFO -- :   Rendered layouts/nav/_public.html.erb (Duration: 2.3ms | Allocations: 488)
web_1            | I, [2021-01-30T13:20:15.631643 #1]  INFO -- :   Rendered layouts/_footer.html.erb (Duration: 0.0ms | Allocations: 5)
web_1            | I, [2021-01-30T13:20:15.632284 #1]  INFO -- : Completed 200 OK in 5ms (Views: 4.6ms | ActiveRecord: 0.3ms | Allocations: 1333)
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:20:15 +0000] "GET /about HTTP/1.1" 200 5118 "https://myapp.ie/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"
frontend_1       | 37.228.235.151 - - [30/Jan/2021:13:20:15 +0000] "GET /service-worker.js HTTP/1.1" 304 0 "https://myapp.ie/service-worker.js" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36" "-"

My Devise controllers are all standard (I haven't edited them).

Here's my Application Controller

class ApplicationController < ActionController::Base

    # To clear cache to allow logging out.
    before_action :set_cache_headers

    protect_from_forgery prepend: true

    # To enable sign in to function correctly.
    skip_before_action :verify_authenticity_token, :only => :create

    before_action :configure_permitted_parameters, if: :devise_controller?

    def index

    end

    def set_cache_headers
        response.headers["Cache-Control"] = "no-cache, no-store"
        response.headers["Pragma"] = "no-cache"
        response.headers["Expires"] = "Mon, 01 Jan 1990 00:00:00 GMT"
    end

    protected

    # Restrict parameters for sign up input.
    def configure_permitted_parameters
        added_attrs = [:first_name, :last_name, :email, :encrypted_password, :password_confirmation, :remember_me]
        devise_parameter_sanitizer.permit(:sign_up, keys: added_attrs)
        devise_parameter_sanitizer.permit(:account_update, keys: added_attrs)
        devise_parameter_sanitizer.permit(:sign_in, keys: added_attrs)
    end

end

Here's my Application.html.erb

<!DOCTYPE html>

    <title>MyApp</title>
    <link rel="manifest" href="manifest.webmanifest">
    <link rel="apple-touch-icon" href="/apple-touch-icon.png">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="theme-color" content="#ff8a00">
    <meta name="msapplication-navbutton--color" content="#ff8a00">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="default">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>

    <link href="https://fonts.googleapis.com/css?family=Text+Me+One&display=swap" rel="stylesheet">

  <body id="<%= controller.controller_name %>" class="<%= controller.action_name %> <%= "show-sidebar" if @show_sidebar.present? %>">

      <% if @show_sidebar.nil? %>

          <%= render "layouts/nav/public" %>

        <%= yield %>
      <% else %>
        <%= render "layouts/nav/dashboard" %>

            <%= render "layouts/nav/sidebar" %>

              <%= yield %>

      <% end %>

    <%= render "layouts/footer" %>

<%= notice %>

    <%= javascript_pack_tag "counter" %>

Here's the part of the view that displays the Log In / Log Out link.

      <% if notice %>

<%= notice %>

      <% end %>
      <% if alert %>

<%= alert %>

      <% end %>

      <% if user_signed_in? %>

<%= current_user.first_name %> <%= current_user.last_name %>

      <% end %>

      <% if user_signed_in? %>

          <%= link_to 'Edit Profile', edit_user_registration_path, :class => 'nav-link' %>

          <%= link_to "Log Out", destroy_user_session_path, method: :delete, :class => 'nav-link' %>

      <% else %>

          <%= link_to "Log In", new_user_session_path, :class => 'nav-link' %>

          <%= link_to "Sign Up", new_user_registration_path, :class => 'nav-link'  %>

      <% end %>

I'm not sure if there's any other code that would be helpful to resolve but if so, please let me know and I will add to the above. Appreciate any help.

Body:
In my humble opinion, there is a better option:

proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Ssl on;

Found here: https://stackoverflow.com/a/57182441/3505166


来源: stackexchange

问:
Google colab stuck on downloading Fashion_Mnist dataset
I have tried running my code from google collab for the fashion using this code but it is stuck on downloading the code. I also switched between the hardware accelerators but still nothing. Is there any workaround to this problem?</p>

答:
For Google Colab

At the top write !pip install mnist.
 Use import mnist.

Then simply store the images and labels:

```<code>train_images = mnist.train_images()
train_labels = mnist.train_labels()
test_images = mnist.test_images()
test_labels = mnist.test_labels()
</code>```

That's it!!!

ContentLicense: CC BY-SA 4.0

Body:
For Google Colab

At the top write !pip install mnist.
 Use import mnist.

Then simply store the images and labels:

train_images = mnist.train_images()
train_labels = mnist.train_labels()
test_images = mnist.test_images()
test_labels = mnist.test_labels()

That's it!!!


问:
When routing mswjs/data populates the database with new items and removes the previous one, making it inaccessible
I use next-redux-wrapper, MSW, @mswjs/data and redux-toolkit for storing my data in a store as well as mocking API calls and fetching from a mock Database.

I have the following scenario happening to me.

I am on page /content/editor and in the console and terminal, I can see the data was fetched from the mock database and hydrated from getStaticProps of Editor.js. So now IDs 1 to 6 are inside the store accessible.

Now I click on the PLUS icon to create a new project. I fill out the dialog and press "SAVE". a POST request starts, it's pending and then it gets fulfilled. The new project is now in the mock DB as well as in the store, I can see IDs 1 to 7 now.

Since I clicked "SAVE" and the POST request was successful, I am being routed to /content/editor/7 to view the newly created project.

Now I am on Page [id].js, which also fetched data from the mock DB and then it gets stored and hydrated into the redux store. The idea is, it takes the previous store's state and spreads it into the store, with the new data (if there are any).

Now the ID 7 no longer exists. And IDs 1 to 6 also don't exist anymore, instead, I can see in the console and terminal that IDs 8 to 13 were created, and the previous ones are no more.

Obviously, this is not great. When I create a new project and then switch the route, I should be able to access the newly created project as well as the previously created ones. But instead, they all get overwritten.

It either has something to do with the next-redux-wrapper or MSW, but I am not sure how to make it work. I need help with it. I will post some code now:

Code

getStaticProps

// path example: /content/editor
// Editor.js

export const getStaticProps = wrapper.getStaticProps(
  (store) =>
    async ({ locale }) => {
      const [translation] = await Promise.all([
        serverSideTranslations(locale, ['editor', 'common', 'thesis']),
        store.dispatch(fetchProjects()),
        store.dispatch(fetchBuildingBlocks()),
      ]);

      return {
        props: {
          ...translation,
        },
      };
    }
);
```
<pre class="lang-js prettyprint-override"><code>// path example: /content/editor/2
// [id].js
export const getStaticProps = wrapper.getStaticProps(
  (store) =>
    async ({ locale, params }) => {
      const { id } = params;

      const [translation] = await Promise.all([
        serverSideTranslations(locale, ['editor', 'common', 'thesis']),
        store.dispatch(fetchProjects()),
        // store.dispatch(fetchProjectById(id)), // issue: fetching by ID returns null
        store.dispatch(fetchBuildingBlocks()),
      ]);

      return {
        props: {
          ...translation,
          id,
        },
      };
    }
);
</code>```

Mock Database

Factory

I am going to shorten the code to the relevant bits. I will remove properties for a project, as well es helper functions to generate data.

const asscendingId = (() => {
  let id = 1;
  return () => id++;
})();

const isDevelopment =
  process.env.NODE_ENV === 'development' || process.env.STORYBOOK || false;

export const projectFactory = () => {
  return {
    id: primaryKey(isDevelopment ? asscendingId : nanoid),
    name: String,
    // ... other properties
  }
};

export const createProject = (data) => {
  return {
    name: data.name,
    createdAt: getUnixTime(new Date()),
    ...data,
  };
};

/**
 * Create initial set of tasks
 */
export function generateMockProjects(amount) {
  const projects = [];
  for (let i = amount; i >= 0; i--) {
    const project = createProject({
      name: faker.lorem.sentence(faker.datatype.number({ min: 1, max: 5 })),
      dueDate: date(),
      fontFamily: getRandomFontFamily(),
      pageMargins: getRandomPageMargins(),
      textAlign: getRandomTextAlign(),
      pageNumberPosition: getRandomPageNumberPosition(),
      ...createWordsCounter(),
    });
    projects.push(project);
  }
  return projects;
}
```
<h4>API Handler</h4>
<p>I will shorten this one to GET and POST requests only.</p>
<pre class="lang-js prettyprint-override"><code>import { db } from '../../db';

export const projectsHandlers = (delay = 0) => {
  return [
    rest.get('https://my.backend/mock/projects', getAllProjects(delay)),
    rest.get('https://my.backend/mock/projects/:id', getProjectById(delay)),
    rest.get('https://my.backend/mock/projectsNames', getProjectsNames(delay)),
    rest.get(
      'https://my.backend/mock/projects/name/:id',
      getProjectsNamesById(delay)
    ),
    rest.post('https://my.backend/mock/projects', postProject(delay)),
    rest.patch(
      'https://my.backend/mock/projects/:id',
      updateProjectById(delay)
    ),
  ];
};

function getAllProjects(delay) {
  return (request, response, context) => {
    const projects = db.project.getAll();
    return response(context.delay(delay), context.json(projects));
  };
}

function postProject(delay) {
  return (request, response, context) => {
    const { body } = request;
    if (body.content === 'error') {
      return response(
        context.delay(delay),
        context.status(500),
        context.json('Server error saving this project')
      );
    }

    const now = getUnixTime(new Date());
    const project = db.project.create({
      ...body,
      createdAt: now,
      maxWords: 10_000,
      minWords: 7000,
      targetWords: 8500,
      potentialWords: 1500,
      currentWords: 0,
    });
    return response(context.delay(delay), context.json(project));
  };
}
</code>```

// all handlers
import { buildingBlocksHandlers } from './api/buildingblocks';
import { checklistHandlers } from './api/checklist';
import { paragraphsHandlers } from './api/paragraphs';
import { projectsHandlers } from './api/projects';
import { tasksHandlers } from './api/tasks';

const ARTIFICIAL_DELAY_MS = 2000;

export const handlers = [
  ...tasksHandlers(ARTIFICIAL_DELAY_MS),
  ...checklistHandlers(ARTIFICIAL_DELAY_MS),
  ...projectsHandlers(ARTIFICIAL_DELAY_MS),
  ...buildingBlocksHandlers(ARTIFICIAL_DELAY_MS),
  ...paragraphsHandlers(ARTIFICIAL_DELAY_MS),
];
```
<pre class="lang-js prettyprint-override"><code>// database
import { factory } from '@mswjs/data';

import {
  buildingBlockFactory,
  generateMockBuildingBlocks,
} from './factory/buildingblocks.factory';
import {
  checklistFactory,
  generateMockChecklist,
} from './factory/checklist.factory';
import { paragraphFactory } from './factory/paragraph.factory';
import {
  projectFactory,
  generateMockProjects,
} from './factory/project.factory';
import { taskFactory, generateMockTasks } from './factory/task.factory';

export const db = factory({
  task: taskFactory(),
  checklist: checklistFactory(),
  project: projectFactory(),
  buildingBlock: buildingBlockFactory(),
  paragraph: paragraphFactory(),
});

generateMockProjects(5).map((project) => db.project.create(project));

const projectIds = db.project.getAll().map((project) => project.id);
generateMockTasks(20, projectIds).map((task) => db.task.create(task));
generateMockBuildingBlocks(10, projectIds).map((block) =>
  db.buildingBlock.create(block)
);

const taskIds = db.task.getAll().map((task) => task.id);
generateMockChecklist(20, taskIds).map((item) => db.checklist.create(item));
</code>```

Project Slice

I will shorten this one as well to the relevant snippets.

// projects.slice.js
import {
  createAsyncThunk,
  createEntityAdapter,
  createSelector,
  createSlice,
  current,
} from '@reduxjs/toolkit';
import { client } from 'mocks/client';
import { HYDRATE } from 'next-redux-wrapper';

const projectsAdapter = createEntityAdapter();
const initialState = projectsAdapter.getInitialState({
  status: 'idle',
  filter: { type: null, value: null },
  statuses: {},
});

export const fetchProjects = createAsyncThunk(
  'projects/fetchProjects',
  async () => {
    const response = await client.get('https://my.backend/mock/projects');
    return response.data;
  }
);

export const saveNewProject = createAsyncThunk(
  'projects/saveNewProject',
  async (data) => {
    const response = await client.post('https://my.backend/mock/projects', {
      ...data,
    });
    return response.data;
  }
);

export const projectSlice = createSlice({
  name: 'projects',
  initialState,
  reducers: {
    // irrelevant reducers....
  },
  extraReducers: (builder) => {
    builder
      .addCase(HYDRATE, (state, action) => {
        // eslint-disable-next-line no-console
        console.log('HYDRATE', action.payload);

        const statuses = Object.fromEntries(
          action.payload.projects.ids.map((id) => [id, 'idle'])
        );

        return {
          ...state,
          ...action.payload.projects,
          statuses,
        };
      })
      .addCase(fetchProjects.pending, (state, action) => {
        state.status = 'loading';
      })
      .addCase(fetchProjects.fulfilled, (state, action) => {
        projectsAdapter.addMany(state, action.payload);
        state.status = 'idle';
        action.payload.forEach((item) => {
          state.statuses[item.id] = 'idle';
        });
      })
      .addCase(saveNewProject.pending, (state, action) => {
        console.log('SAVE NEW PROJECT PENDING', action);
      })
      .addCase(saveNewProject.fulfilled, (state, action) => {
        projectsAdapter.addOne(state, action.payload);
        console.group('SAVE NEW PROJECT FULFILLED');
        console.log(current(state));
        console.log(action);
        console.groupEnd();
        state.statuses[action.payload.id] = 'idle';
      })
      // other irrelevant reducers...
      },
});
```

This should be all the relevant code. If you have questions, please ask them and I will try to answer them.

答:
I have changed how the state gets hydrated, so I turned this code:

      .addCase(HYDRATE, (state, action) => {
        // eslint-disable-next-line no-console
        console.log('HYDRATE', action.payload);

        const statuses = Object.fromEntries(
          action.payload.projects.ids.map((id) => [id, 'idle'])
        );

        return {
          ...state,
          ...action.payload.projects,
          statuses,
        };
      })
```
<p>Into this code:</p>
<pre class="lang-js prettyprint-override"><code>      .addCase(HYDRATE, (state, action) => {
        // eslint-disable-next-line no-console
        console.group('HYDRATE', action.payload);

        const statuses = Object.fromEntries(
          action.payload.projects.ids.map((id) => [id, 'idle'])
        );

        state.statuses = { ...state.statuses, ...statuses };
        projectsAdapter.upsertMany(state, action.payload.projects.entities);
      })
</code>```

I used the adapter to upsert all entries.

Body:
I use next-redux-wrapper, MSW, @mswjs/data and redux-toolkit for storing my data in a store as well as mocking API calls and fetching from a mock Database.

I have the following scenario happening to me.

I am on page /content/editor and in the console and terminal, I can see the data was fetched from the mock database and hydrated from getStaticProps of Editor.js. So now IDs 1 to 6 are inside the store accessible.

Now I click on the PLUS icon to create a new project. I fill out the dialog and press "SAVE". a POST request starts, it's pending and then it gets fulfilled. The new project is now in the mock DB as well as in the store, I can see IDs 1 to 7 now.

Since I clicked "SAVE" and the POST request was successful, I am being routed to /content/editor/7 to view the newly created project.

Now I am on Page [id].js, which also fetched data from the mock DB and then it gets stored and hydrated into the redux store. The idea is, it takes the previous store's state and spreads it into the store, with the new data (if there are any).

Now the ID 7 no longer exists. And IDs 1 to 6 also don't exist anymore, instead, I can see in the console and terminal that IDs 8 to 13 were created, and the previous ones are no more.

Obviously, this is not great. When I create a new project and then switch the route, I should be able to access the newly created project as well as the previously created ones. But instead, they all get overwritten.

It either has something to do with the next-redux-wrapper or MSW, but I am not sure how to make it work. I need help with it. I will post some code now:

Code

getStaticProps

// path example: /content/editor
// Editor.js

export const getStaticProps = wrapper.getStaticProps(
  (store) =>
    async ({ locale }) => {
      const [translation] = await Promise.all([
        serverSideTranslations(locale, ['editor', 'common', 'thesis']),
        store.dispatch(fetchProjects()),
        store.dispatch(fetchBuildingBlocks()),
      ]);

      return {
        props: {
          ...translation,
        },
      };
    }
);

// path example: /content/editor/2
// [id].js
export const getStaticProps = wrapper.getStaticProps(
  (store) =>
    async ({ locale, params }) => {
      const { id } = params;

      const [translation] = await Promise.all([
        serverSideTranslations(locale, ['editor', 'common', 'thesis']),
        store.dispatch(fetchProjects()),
        // store.dispatch(fetchProjectById(id)), // issue: fetching by ID returns null
        store.dispatch(fetchBuildingBlocks()),
      ]);

      return {
        props: {
          ...translation,
          id,
        },
      };
    }
);

Mock Database

Factory

I am going to shorten the code to the relevant bits. I will remove properties for a project, as well es helper functions to generate data.

const asscendingId = (() => {
  let id = 1;
  return () => id++;
})();

const isDevelopment =
  process.env.NODE_ENV === 'development' || process.env.STORYBOOK || false;

export const projectFactory = () => {
  return {
    id: primaryKey(isDevelopment ? asscendingId : nanoid),
    name: String,
    // ... other properties
  }
};

export const createProject = (data) => {
  return {
    name: data.name,
    createdAt: getUnixTime(new Date()),
    ...data,
  };
};

/**
 * Create initial set of tasks
 */
export function generateMockProjects(amount) {
  const projects = [];
  for (let i = amount; i >= 0; i--) {
    const project = createProject({
      name: faker.lorem.sentence(faker.datatype.number({ min: 1, max: 5 })),
      dueDate: date(),
      fontFamily: getRandomFontFamily(),
      pageMargins: getRandomPageMargins(),
      textAlign: getRandomTextAlign(),
      pageNumberPosition: getRandomPageNumberPosition(),
      ...createWordsCounter(),
    });
    projects.push(project);
  }
  return projects;
}

API Handler

I will shorten this one to GET and POST requests only.

import { db } from '../../db';

export const projectsHandlers = (delay = 0) => {
  return [
    rest.get('https://my.backend/mock/projects', getAllProjects(delay)),
    rest.get('https://my.backend/mock/projects/:id', getProjectById(delay)),
    rest.get('https://my.backend/mock/projectsNames', getProjectsNames(delay)),
    rest.get(
      'https://my.backend/mock/projects/name/:id',
      getProjectsNamesById(delay)
    ),
    rest.post('https://my.backend/mock/projects', postProject(delay)),
    rest.patch(
      'https://my.backend/mock/projects/:id',
      updateProjectById(delay)
    ),
  ];
};

function getAllProjects(delay) {
  return (request, response, context) => {
    const projects = db.project.getAll();
    return response(context.delay(delay), context.json(projects));
  };
}

function postProject(delay) {
  return (request, response, context) => {
    const { body } = request;
    if (body.content === 'error') {
      return response(
        context.delay(delay),
        context.status(500),
        context.json('Server error saving this project')
      );
    }

    const now = getUnixTime(new Date());
    const project = db.project.create({
      ...body,
      createdAt: now,
      maxWords: 10_000,
      minWords: 7000,
      targetWords: 8500,
      potentialWords: 1500,
      currentWords: 0,
    });
    return response(context.delay(delay), context.json(project));
  };
}

// all handlers
import { buildingBlocksHandlers } from './api/buildingblocks';
import { checklistHandlers } from './api/checklist';
import { paragraphsHandlers } from './api/paragraphs';
import { projectsHandlers } from './api/projects';
import { tasksHandlers } from './api/tasks';

const ARTIFICIAL_DELAY_MS = 2000;

export const handlers = [
  ...tasksHandlers(ARTIFICIAL_DELAY_MS),
  ...checklistHandlers(ARTIFICIAL_DELAY_MS),
  ...projectsHandlers(ARTIFICIAL_DELAY_MS),
  ...buildingBlocksHandlers(ARTIFICIAL_DELAY_MS),
  ...paragraphsHandlers(ARTIFICIAL_DELAY_MS),
];

// database
import { factory } from '@mswjs/data';

import {
  buildingBlockFactory,
  generateMockBuildingBlocks,
} from './factory/buildingblocks.factory';
import {
  checklistFactory,
  generateMockChecklist,
} from './factory/checklist.factory';
import { paragraphFactory } from './factory/paragraph.factory';
import {
  projectFactory,
  generateMockProjects,
} from './factory/project.factory';
import { taskFactory, generateMockTasks } from './factory/task.factory';

export const db = factory({
  task: taskFactory(),
  checklist: checklistFactory(),
  project: projectFactory(),
  buildingBlock: buildingBlockFactory(),
  paragraph: paragraphFactory(),
});

generateMockProjects(5).map((project) => db.project.create(project));

const projectIds = db.project.getAll().map((project) => project.id);
generateMockTasks(20, projectIds).map((task) => db.task.create(task));
generateMockBuildingBlocks(10, projectIds).map((block) =>
  db.buildingBlock.create(block)
);

const taskIds = db.task.getAll().map((task) => task.id);
generateMockChecklist(20, taskIds).map((item) => db.checklist.create(item));

Project Slice

I will shorten this one as well to the relevant snippets.

// projects.slice.js
import {
  createAsyncThunk,
  createEntityAdapter,
  createSelector,
  createSlice,
  current,
} from '@reduxjs/toolkit';
import { client } from 'mocks/client';
import { HYDRATE } from 'next-redux-wrapper';

const projectsAdapter = createEntityAdapter();
const initialState = projectsAdapter.getInitialState({
  status: 'idle',
  filter: { type: null, value: null },
  statuses: {},
});

export const fetchProjects = createAsyncThunk(
  'projects/fetchProjects',
  async () => {
    const response = await client.get('https://my.backend/mock/projects');
    return response.data;
  }
);

export const saveNewProject = createAsyncThunk(
  'projects/saveNewProject',
  async (data) => {
    const response = await client.post('https://my.backend/mock/projects', {
      ...data,
    });
    return response.data;
  }
);

export const projectSlice = createSlice({
  name: 'projects',
  initialState,
  reducers: {
    // irrelevant reducers....
  },
  extraReducers: (builder) => {
    builder
      .addCase(HYDRATE, (state, action) => {
        // eslint-disable-next-line no-console
        console.log('HYDRATE', action.payload);

        const statuses = Object.fromEntries(
          action.payload.projects.ids.map((id) => [id, 'idle'])
        );

        return {
          ...state,
          ...action.payload.projects,
          statuses,
        };
      })
      .addCase(fetchProjects.pending, (state, action) => {
        state.status = 'loading';
      })
      .addCase(fetchProjects.fulfilled, (state, action) => {
        projectsAdapter.addMany(state, action.payload);
        state.status = 'idle';
        action.payload.forEach((item) => {
          state.statuses[item.id] = 'idle';
        });
      })
      .addCase(saveNewProject.pending, (state, action) => {
        console.log('SAVE NEW PROJECT PENDING', action);
      })
      .addCase(saveNewProject.fulfilled, (state, action) => {
        projectsAdapter.addOne(state, action.payload);
        console.group('SAVE NEW PROJECT FULFILLED');
        console.log(current(state));
        console.log(action);
        console.groupEnd();
        state.statuses[action.payload.id] = 'idle';
      })
      // other irrelevant reducers...
      },
});

This should be all the relevant code. If you have questions, please ask them and I will try to answer them.

Body:
I have changed how the state gets hydrated, so I turned this code:

      .addCase(HYDRATE, (state, action) => {
        // eslint-disable-next-line no-console
        console.log('HYDRATE', action.payload);

        const statuses = Object.fromEntries(
          action.payload.projects.ids.map((id) => [id, 'idle'])
        );

        return {
          ...state,
          ...action.payload.projects,
          statuses,
        };
      })

Into this code:

      .addCase(HYDRATE, (state, action) => {
        // eslint-disable-next-line no-console
        console.group('HYDRATE', action.payload);

        const statuses = Object.fromEntries(
          action.payload.projects.ids.map((id) => [id, 'idle'])
        );

        state.statuses = { ...state.statuses, ...statuses };
        projectsAdapter.upsertMany(state, action.payload.projects.entities);
      })

I used the adapter to upsert all entries.


问:
In PyQt5 how to control the Windows close button event?
I would like to give a choice if the user is sure to close the app, when the Windows close button is being pressed? So far I've coded this, which prompting that the App is about to quit, but I couldn't catch the event or make the App wait until the user confirms. I'm pretty new to this, can anyone help PLEASE.
Here is my code,</p>

```<code>from PyQt5 import QtCore, QtGui, QtWidgets
import sys

class Ui_MainWindow(object):

    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        ##
        #......some more codes
        ##
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

        app.aboutToQuit.connect(self.closeEvent)

    def retranslateUi(self, MainWindow):
        ## codes

    def closeEvent(self):
        print("User has clicked the red x on the main window")
        ## HERE I WANT TO GIVE AN OPTION TO THE USER IF THEY REALLY WANT TO QUIT
        ## AND ON THIS TIME THE MAIN APP/ MAIN WINDOW NEEDS TO BE ON AS IT IS

if __name__ == "__main__":

    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()

    sys.exit(app.exec_())
</code>```

答:
For PyQt5:
There is 2 options in my solution, first one is for the "x" button, second one is for menu button, decide which better for you.
Based on Natan's answer exitEvent</p>
```<code>import sys
from PyQt5.QtWidgets import QApplication, QMessageBox, QMainWindow, QAction

class window(QMainWindow):
    def __init__(self):

        super().__init__()

    def createUI(self):

        self.setGeometry(500, 300, 700, 700)

        self.setWindowTitle("window")

        quit = QAction("Quit", self)
        quit.triggered.connect(self.exit_window)

        menubar = self.menuBar()
        fmenu = menubar.addMenu("File")
        fmenu.addAction(quit)

    def closeEvent(self, event):
        close = QMessageBox()
        close.setText("You sure?")
        close.setStandardButtons(QMessageBox.Yes | QMessageBox.Cancel)
        close = close.exec()

        if close == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

    def exit_window(self, event):
        close = QtWidgets.QMessageBox.question(self,
                                            "QUIT?",
                                            "Are you sure want to STOP and EXIT?",
                                            QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
        if close == QtWidgets.QMessageBox.Yes:
            # event.accept()
            sys.exit()
        else:
            pass

main = QApplication(sys.argv)
window = window()
window.createUI()
window.show()
sys.exit(main.exec_())
</code>```

ContentLicense: CC BY-SA 3.0

Body:
I would like to give a choice if the user is sure to close the app, when the Windows close button is being pressed? So far I've coded this, which prompting that the App is about to quit, but I couldn't catch the event or make the App wait until the user confirms. I'm pretty new to this, can anyone help PLEASE.
Here is my code,

from PyQt5 import QtCore, QtGui, QtWidgets
import sys

class Ui_MainWindow(object):

    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        ##
        #......some more codes
        ##
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

        app.aboutToQuit.connect(self.closeEvent)

    def retranslateUi(self, MainWindow):
        ## codes

    def closeEvent(self):
        print("User has clicked the red x on the main window")
        ## HERE I WANT TO GIVE AN OPTION TO THE USER IF THEY REALLY WANT TO QUIT
        ## AND ON THIS TIME THE MAIN APP/ MAIN WINDOW NEEDS TO BE ON AS IT IS

if __name__ == "__main__":

    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()

    sys.exit(app.exec_())

Body:
For PyQt5:
There is 2 options in my solution, first one is for the "x" button, second one is for menu button, decide which better for you.
Based on Natan's answer exitEvent

import sys
from PyQt5.QtWidgets import QApplication, QMessageBox, QMainWindow, QAction

class window(QMainWindow):
    def __init__(self):

        super().__init__()

    def createUI(self):

        self.setGeometry(500, 300, 700, 700)

        self.setWindowTitle("window")

        quit = QAction("Quit", self)
        quit.triggered.connect(self.exit_window)

        menubar = self.menuBar()
        fmenu = menubar.addMenu("File")
        fmenu.addAction(quit)

    def closeEvent(self, event):
        close = QMessageBox()
        close.setText("You sure?")
        close.setStandardButtons(QMessageBox.Yes | QMessageBox.Cancel)
        close = close.exec()

        if close == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

    def exit_window(self, event):
        close = QtWidgets.QMessageBox.question(self,
                                            "QUIT?",
                                            "Are you sure want to STOP and EXIT?",
                                            QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
        if close == QtWidgets.QMessageBox.Yes:
            # event.accept()
            sys.exit()
        else:
            pass

main = QApplication(sys.argv)
window = window()
window.createUI()
window.show()
sys.exit(main.exec_())


问:
How to use Array.fill to create 0...499 in JavaScript?
I want to use Array.fill method to create a sequence from 0...499 like

```<code>const arr = []
for(let i = 0; i < 500; i++)
   arr.push(i);
</code>```

Currently, I am using Array.from like:

```<code>const arr = Array.from(Array(500).keys())
</code>```

But how can I use just Array.fill to create the sequence? Is it even possible?

答:
You can use a one-line helper like this:

function createArrayWithNumbersFromRange(start: number, end: number): number[] {
  return [...Array(end - start + 1)].map((_, index) => start + index);
}
```

Body:
I want to use Array.fill method to create a sequence from 0...499 like

const arr = []
for(let i = 0; i < 500; i++)
   arr.push(i);

Currently, I am using Array.from like:

const arr = Array.from(Array(500).keys())

But how can I use just Array.fill to create the sequence? Is it even possible?


问:
strncpy making weird output
I'm trying to make an algorithm for strncpy

I read how it work in the manual and made my algorithm

then I made a test to see if there's any difference between my ft_strncpy and the real strncpy

#include <string.h>
#include <stdio.h>

char    *ft_strncpy(char *dest, char *src, unsigned int n)
{
    unsigned int    i;

    i = 0;
    while (i < n && src[i] != '\0')
    {
        dest[i] = src[i];
        i++;
    }
    while (i < n)
    {
        dest[i] = '\0';
        i++;
    }
    return (dest);
}

int main(void)
{
    char src1[] = "123456789q00000";
    char dest1[] = "zzz";
    printf("my output\n");
    printf("src1: %s\n", src1);
    ft_strncpy(dest1, src1, 8);
    printf("dest1: %s\n", dest1);

    printf("\nhow it should be\n");
    char src2[] = "123456789q00000";
    char dest2[] = "zzz";
    printf("src2: %s\n", src2);
    strncpy(dest2, src2, 8);
    printf("dest2: %s\n", dest2);
}
```
<p>the <code>how it should be</code> section supposed to be the right output of the real <code>strncpy</code>
but I'm having weird outputs just like in the code I provided<br>
I get this error</p>
<pre class="lang-c prettyprint-override"><code>*** buffer overflow detected ***: terminated
signal: aborted (core dumped)
</code>```

what I understood from the manual is

strncpy copies n first characters from *src to *dest

so a code like

    char src2[] = "123456789q00000";
    char dest2[] = "zzz";
    printf("src2: %s\n", src2);
    strncpy(dest2, src2, 10);
    printf("dest2: %s\n", dest2);
```

should output : 123456789q as the value of dest
I'm I missing smth here?

答:
Arrays in c are not dynamic so

I can't just initialize it with a string then try changing it to a bigger one

that will lead to an undefined behavior

besides there's a corner-case where it might not add the terminating null character so I won't be able to print it with printf because it's not a string anymore, it's an array.

conclusion: Be more cautious when modifying strings.

(answer by the help of @Someprogrammerdude and @n. 1.8e9-where's-my share m.)

Title: strncpy making weird output

Body:
I'm trying to make an algorithm for strncpy

I read how it work in the manual and made my algorithm

then I made a test to see if there's any difference between my ft_strncpy and the real strncpy

#include <string.h>
#include <stdio.h>

char    *ft_strncpy(char *dest, char *src, unsigned int n)
{
    unsigned int    i;

    i = 0;
    while (i < n && src[i] != '\0')
    {
        dest[i] = src[i];
        i++;
    }
    while (i < n)
    {
        dest[i] = '\0';
        i++;
    }
    return (dest);
}

int main(void)
{
    char src1[] = "123456789q00000";
    char dest1[] = "zzz";
    printf("my output\n");
    printf("src1: %s\n", src1);
    ft_strncpy(dest1, src1, 8);
    printf("dest1: %s\n", dest1);

    printf("\nhow it should be\n");
    char src2[] = "123456789q00000";
    char dest2[] = "zzz";
    printf("src2: %s\n", src2);
    strncpy(dest2, src2, 8);
    printf("dest2: %s\n", dest2);
}

the how it should be section supposed to be the right output of the real strncpy
but I'm having weird outputs just like in the code I provided

I get this error

*** buffer overflow detected ***: terminated
signal: aborted (core dumped)

what I understood from the manual is

strncpy copies n first characters from *src to *dest

so a code like

    char src2[] = "123456789q00000";
    char dest2[] = "zzz";
    printf("src2: %s\n", src2);
    strncpy(dest2, src2, 10);
    printf("dest2: %s\n", dest2);

should output : 123456789q as the value of dest
I'm I missing smth here?


问:
how to async/await redux-thunk actions?
action.js

```<code>export function getLoginStatus() {
  return async(dispatch) => {
    let token = await getOAuthToken();
    let success = await verifyToken(token);
    if (success == true) {
      dispatch(loginStatus(success));
    } else {
      console.log("Success: False");
      console.log("Token mismatch");
    }
    return success;
  }
}
</code>```

component.js

```<code>  componentDidMount() {
    this.props.dispatch(splashAction.getLoginStatus())
      .then((success) => {
        if (success == true) {
          Actions.counter()
        } else {
          console.log("Login not successfull");
        }
     });
   }
</code>```

However, when I write component.js code with async/await like below I get this error:

Possible Unhandled Promise Rejection (id: 0): undefined is not a function (evaluating 'this.props.dispatch(splashAction.getLoginStatus())')

component.js

```<code>  async componentDidMount() {
     let success = await this.props.dispatch(splashAction.getLoginStatus());
     if (success == true) {
       Actions.counter()
     } else {
       console.log("Login not successfull");
     }
   }
</code>```

How do I await a getLoginStatus() and then execute the rest of the statements?
Everything works quite well when using .then(). I doubt something is missing in my async/await implementation. trying to figure that out.

答: use dispatch(this.props.splashAction.getLoginStatus()) instead this.props.dispatch(splashAction.getLoginStatus())</p>

Title: how to async/await redux-thunk actions?

Body:
action.js

export function getLoginStatus() {
  return async(dispatch) => {
    let token = await getOAuthToken();
    let success = await verifyToken(token);
    if (success == true) {
      dispatch(loginStatus(success));
    } else {
      console.log("Success: False");
      console.log("Token mismatch");
    }
    return success;
  }
}

component.js

  componentDidMount() {
    this.props.dispatch(splashAction.getLoginStatus())
      .then((success) => {
        if (success == true) {
          Actions.counter()
        } else {
          console.log("Login not successfull");
        }
     });
   }

However, when I write component.js code with async/await like below I get this error:

Possible Unhandled Promise Rejection (id: 0): undefined is not a function (evaluating 'this.props.dispatch(splashAction.getLoginStatus())')

component.js

  async componentDidMount() {
     let success = await this.props.dispatch(splashAction.getLoginStatus());
     if (success == true) {
       Actions.counter()
     } else {
       console.log("Login not successfull");
     }
   }

How do I await a getLoginStatus() and then execute the rest of the statements?
Everything works quite well when using .then(). I doubt something is missing in my async/await implementation. trying to figure that out.


问:
A better way of doing this evaluation in Python
I have function that delivers a List with a single element of the form ax+b where a and b are (multi)digit characters and there is exactly one 'x'.

I then swap the x for a number and use eval on the result.

For example with the single element [64/243*x - 283/243] I apply

```<code>new_word=words.replace('x','7')
</code>```

to get [64/243*7 - 283/243]

which I then evaluate

```<code>z=eval(new_word)
</code>```

What I want to achieve is a loop where  I put various numbers in for 'x', with different List elements.

Before I do that, is there a better/slicker/faster way of evaluating something like  [64/243*x - 283/243] for different values of 'x' other than  using eval?

Or point me to the Old Question that you think is an answer to my question.

答:
You could generate a class that can display and evaluate a linear expression:

from fractions import Fraction
from random import randint

class Linear:

    def __init__(self):
        self.a = Fraction(randint(0, 10), randint(1, 10))
        self.b = Fraction(randint(0, 10), randint(1, 10))
        self.func = lambda x: self.a*x + self.b

    def __repr__(self):
        return f'Linear(a={self.a}, b={self.b})'

    def __str__(self):
        return f'{self.a}*x+{self.b}'

    def __call__(self,x):
        return self.func(x)

eq = Linear()
print(repr(eq))
for x in range(1,6):
    print(f'{eq} where x={x} => {eq(x)}')
```
<p>Output:</p>
<pre class="lang-none prettyprint-override"><code>Linear(a=3/5, b=4/5)
3/5*x+4/5 where x=1 => 7/5
3/5*x+4/5 where x=2 => 2
3/5*x+4/5 where x=3 => 13/5
3/5*x+4/5 where x=4 => 16/5
3/5*x+4/5 where x=5 => 19/5
</code>```

Body:
I have function that delivers a List with a single element of the form ax+b where a and b are (multi)digit characters and there is exactly one 'x'.

I then swap the x for a number and use eval on the result.

For example with the single element [64/243*x - 283/243] I apply

new_word=words.replace('x','7')

to get [64/243*7 - 283/243]

which I then evaluate

z=eval(new_word)

What I want to achieve is a loop where  I put various numbers in for 'x', with different List elements.

Before I do that, is there a better/slicker/faster way of evaluating something like  [64/243*x - 283/243] for different values of 'x' other than  using eval?

Or point me to the Old Question that you think is an answer to my question.

Body:
You could generate a class that can display and evaluate a linear expression:

from fractions import Fraction
from random import randint

class Linear:

    def __init__(self):
        self.a = Fraction(randint(0, 10), randint(1, 10))
        self.b = Fraction(randint(0, 10), randint(1, 10))
        self.func = lambda x: self.a*x + self.b

    def __repr__(self):
        return f'Linear(a={self.a}, b={self.b})'

    def __str__(self):
        return f'{self.a}*x+{self.b}'

    def __call__(self,x):
        return self.func(x)

eq = Linear()
print(repr(eq))
for x in range(1,6):
    print(f'{eq} where x={x} => {eq(x)}')

Output:

Linear(a=3/5, b=4/5)
3/5*x+4/5 where x=1 => 7/5
3/5*x+4/5 where x=2 => 2
3/5*x+4/5 where x=3 => 13/5
3/5*x+4/5 where x=4 => 16/5
3/5*x+4/5 where x=5 => 19/5


问:
Android Resource Linking Failed - Android Studio
I build my project and there is no error but when i try to run it on my device it throws this error.

```<code>C:\Users\FAISAL NAZIR\.gradle\caches\transforms-2\files-2.1\eaf17b24d60dc773c7680b20ac141638\material-1.1.0\res\layout\mtrl_calendar_month_navigation.xml:32: AAPT: error: 'textEnd' is incompatible with attribute iconGravity (attr) flags [start=1, textStart=2] [weak].
</code>```

This is the xml file in which it is showing error, the worst thing is, this file is auto-generated so i cannot edit or manipulate it.

```<code><?xml version="1.0" encoding="utf-8"?>
<!--
     Copyright (C) 2019 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  android:id="@+id/month_navigation_bar"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:paddingTop="@dimen/mtrl_calendar_navigation_top_padding"
  android:paddingBottom="@dimen/mtrl_calendar_navigation_bottom_padding"
  android:orientation="horizontal">

  <FrameLayout
    android:layout_width="0dp"
    android:layout_height="match_parent"
    android:layout_weight="1">

    <com.google.android.material.button.MaterialButton
      android:id="@+id/month_navigation_fragment_toggle"
      android:layout_width="wrap_content"
      android:layout_height="@dimen/mtrl_calendar_navigation_height"
      android:layout_gravity="start"
      android:gravity="center_vertical|start"
      android:insetBottom="0dp"
      android:insetTop="0dp"
      app:icon="@drawable/ic_menu_arrow_down_black_24dp"
      app:iconGravity="textEnd"
      app:iconPadding="4dp"/>

  </FrameLayout>

  <com.google.android.material.button.MaterialButton
    android:id="@+id/month_navigation_previous"
    android:layout_width="@dimen/mtrl_min_touch_target_size"
    android:layout_height="@dimen/mtrl_calendar_navigation_height"
    android:contentDescription="@string/mtrl_picker_a11y_prev_month"
    android:gravity="center"
    android:insetBottom="0dp"
    android:insetTop="0dp"
    app:icon="@drawable/ic_keyboard_arrow_left_black_24dp"/>

  <com.google.android.material.button.MaterialButton
    android:id="@+id/month_navigation_next"
    android:layout_width="@dimen/mtrl_min_touch_target_size"
    android:layout_height="@dimen/mtrl_calendar_navigation_height"
    android:contentDescription="@string/mtrl_picker_a11y_next_month"
    android:gravity="center"
    android:insetBottom="0dp"
    android:insetTop="0dp"
    app:icon="@drawable/ic_keyboard_arrow_right_black_24dp"/>

</LinearLayout>
</code>```

i have tried rebuilding project several times, i restarted android studio and i also invalidated caches and restarted, nothing has happened.

答:
It looks like it a confliction between packages. In my case, I had to downgrade the following packages to the following versions:

Xamarin.AndroidX.Core : 1.6.0.3 (currently latest is 1.6.0.4)

Xamarin.AndroidX.Activity : 1.3.1.2 (currently latest is 1.3.1.3)

Clean your project and remove bin/obj folders to get fresh build, and try to build. If it fails, just try building again (without cleaning).
The above is currently solution in my case after hours of headache. I wish it helps a lot of developer facing similar issue.

If you still have issues, do the following:
In case you have Xamarin.Android.Support.V4 installed, uninstall it and use the latest versions of following packages instead:

Xamarin.Android.Support.Compat

Xamarin.Android.Support.Core.UI

Xamarin.Android.Support.Core.Utils

Xamarin.Android.Support.CustomTabs

Xamarin.Android.Support.Design

Xamarin.Android.Support.Fragment

Xamarin.AndroidX.Legacy.Support.Core.UI

Use AndroidX instead of Support library in your code.

The above is what I use in my project which might help you solve confliction issues for many of us.

Body:
I build my project and there is no error but when i try to run it on my device it throws this error.

C:\Users\FAISAL NAZIR\.gradle\caches\transforms-2\files-2.1\eaf17b24d60dc773c7680b20ac141638\material-1.1.0\res\layout\mtrl_calendar_month_navigation.xml:32: AAPT: error: 'textEnd' is incompatible with attribute iconGravity (attr) flags [start=1, textStart=2] [weak].

This is the xml file in which it is showing error, the worst thing is, this file is auto-generated so i cannot edit or manipulate it.

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  android:id="@+id/month_navigation_bar"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:paddingTop="@dimen/mtrl_calendar_navigation_top_padding"
  android:paddingBottom="@dimen/mtrl_calendar_navigation_bottom_padding"
  android:orientation="horizontal">

  <FrameLayout
    android:layout_width="0dp"
    android:layout_height="match_parent"
    android:layout_weight="1">

    <com.google.android.material.button.MaterialButton
      android:id="@+id/month_navigation_fragment_toggle"
      android:layout_width="wrap_content"
      android:layout_height="@dimen/mtrl_calendar_navigation_height"
      android:layout_gravity="start"
      android:gravity="center_vertical|start"
      android:insetBottom="0dp"
      android:insetTop="0dp"
      app:icon="@drawable/ic_menu_arrow_down_black_24dp"
      app:iconGravity="textEnd"
      app:iconPadding="4dp"/>

  </FrameLayout>

  <com.google.android.material.button.MaterialButton
    android:id="@+id/month_navigation_previous"
    android:layout_width="@dimen/mtrl_min_touch_target_size"
    android:layout_height="@dimen/mtrl_calendar_navigation_height"
    android:contentDescription="@string/mtrl_picker_a11y_prev_month"
    android:gravity="center"
    android:insetBottom="0dp"
    android:insetTop="0dp"
    app:icon="@drawable/ic_keyboard_arrow_left_black_24dp"/>

  <com.google.android.material.button.MaterialButton
    android:id="@+id/month_navigation_next"
    android:layout_width="@dimen/mtrl_min_touch_target_size"
    android:layout_height="@dimen/mtrl_calendar_navigation_height"
    android:contentDescription="@string/mtrl_picker_a11y_next_month"
    android:gravity="center"
    android:insetBottom="0dp"
    android:insetTop="0dp"
    app:icon="@drawable/ic_keyboard_arrow_right_black_24dp"/>

</LinearLayout>

i have tried rebuilding project several times, i restarted android studio and i also invalidated caches and restarted, nothing has happened.


问:
MySQL Not unique table/alias
I looked at the answers of others having the same problem, but I can't figure out how to fix the "Not unique table/alias".

```<code>SELECT m.*, u.*
  FROM ".TABLE_PREFIX."users_medals u
  LEFT JOIN ".TABLE_PREFIX."medals m ON u.medal_id = m.medal_id
  WHERE u.user_id IN (".$post['uid'].")
  AND m.medal_level = (
    SELECT MAX(".TABLE_PREFIX."medals.medal_level) FROM ".TABLE_PREFIX."medals
    LEFT JOIN ".TABLE_PREFIX."medals ON ".TABLE_PREFIX."users_medals.medal_id = ".TABLE_PREFIX."medals.medal_id
    WHERE ".TABLE_PREFIX."users_medals.user_id = u.user_id
    AND ".TABLE_PREFIX."medals.medal_type = m.medal_type
  )
</code>```

TABLE_PREFIX is what my script uses to define the database table prefix.

答:
In your sub-query

LEFT JOIN ".TABLE_PREFIX."medals

I think that should be

```<code>LEFT JOIN ".TABLE_PREFIX."users_medals
</code>```

Title: MySQL Not unique table/alias

Body:
I looked at the answers of others having the same problem, but I can't figure out how to fix the "Not unique table/alias".

SELECT m.*, u.*
  FROM ".TABLE_PREFIX."users_medals u
  LEFT JOIN ".TABLE_PREFIX."medals m ON u.medal_id = m.medal_id
  WHERE u.user_id IN (".$post['uid'].")
  AND m.medal_level = (
    SELECT MAX(".TABLE_PREFIX."medals.medal_level) FROM ".TABLE_PREFIX."medals
    LEFT JOIN ".TABLE_PREFIX."medals ON ".TABLE_PREFIX."users_medals.medal_id = ".TABLE_PREFIX."medals.medal_id
    WHERE ".TABLE_PREFIX."users_medals.user_id = u.user_id
    AND ".TABLE_PREFIX."medals.medal_type = m.medal_type
  )

TABLE_PREFIX is what my script uses to define the database table prefix.

Body:
In your sub-query

LEFT JOIN ".TABLE_PREFIX."medals

I think that should be

LEFT JOIN ".TABLE_PREFIX."users_medals


问:
UnboundLocalError: local variable referenced before assignment #
Having issue with the code, I'm getting error with this code for using class and method. Please explain me the error I'm facing.</p>
```<code>class Solution():
    def __init__(self,list1,list2):
        self.list1=list1
        self.list2=list2
    def medianOfList(self):
        self.list1=list1
        self.list2=list2
        list1=list1+list2
        l=len(list1)
        sum=0
        for i in range(l):
            sum+=list1[i]
        return sum/l
list1=[1,2]
list2=[3,100]
m=Solution(list1,list2)
m.medianOfList()
</code>```
```<code>UnboundLocalError                         Traceback (most recent call last)
Input In [18], in <module>
     19 list2=[3,100]
     20 m=Solution(list1,list2)
---> 21 m.medianOfList()

Input In [18], in Solution.medianOfList(self)
      9 def medianOfList(self):
---> 10     self.list1=list1
     11     self.list2=list2
     12     list1=list1+list2

UnboundLocalError: local variable 'list1' referenced before assignment
</code>```

答:
The variable list1 is indeed not defined within the scope of the medianOfList method. It is only defined in the global scope and as a member of the Solution class as self.list1.

I think the accepted answer doesn't exactly follow your intent. I suppose you'd like to use the members of the object you just initialized as follows instead of adding arguments to the method. (You're by the way computing the mean, not the median, check the difference here for example). Note that the medianOfList() method should be called without any arguments as in your original code.

class Solution():
    def __init__(self, list1, list2):
        self.list1 = list1
        self.list2 = list2
    def medianOfList(self):
        listA = self.list1 + self.list2
        l = len(listA)
        sum = 0
        for i in range(l):
            sum += listA[i]
        return sum/l
```

Body:
Having issue with the code, I'm getting error with this code for using class and method. Please explain me the error I'm facing.

class Solution():
    def __init__(self,list1,list2):
        self.list1=list1
        self.list2=list2
    def medianOfList(self):
        self.list1=list1
        self.list2=list2
        list1=list1+list2
        l=len(list1)
        sum=0
        for i in range(l):
            sum+=list1[i]
        return sum/l
list1=[1,2]
list2=[3,100]
m=Solution(list1,list2)
m.medianOfList()

UnboundLocalError                         Traceback (most recent call last)
Input In [18], in <module>
     19 list2=[3,100]
     20 m=Solution(list1,list2)
---> 21 m.medianOfList()

Input In [18], in Solution.medianOfList(self)
      9 def medianOfList(self):
---> 10     self.list1=list1
     11     self.list2=list2
     12     list1=list1+list2

UnboundLocalError: local variable 'list1' referenced before assignment


问:
Flutter merge array if they are duplicated
I need to merge arrays that are duplicate

I have data like this

```<code>var filterData = [{'date': '25, feb', 'data': ['asd','dsa']}, {'date': '25, feb', 'data': ['asd','dsa']}, {'date': '26, feb', 'data': ['asd','dsa']}]
</code>```

I want to filter it like [{'date': '25, feb', 'data': ['asd','dsa','asd','dsa']}, {'date': '26, feb', 'data': ['asd','dsa']}]

答:
The filterData datatype is List<Map<String, dynamic>>, this dynamic satisfy String and List<String>.

filterData  and result data type => List<Map<String, dynamic>>

```<code>List<Map<String, String>> + List<Map<String, List<String>>>
</code>```

Let's take help from Map to have a unique date. Now we are going to create a map, then we will convert to list.

Run on dartPad.

Map<String, List<String>> result = {};

for (final data in filterData) {
  /// assume filterData will never cause null
  final String key = data['date'];
  final List<String> value = data['data'];
  // just append map value
  if (result.containsKey(key)) {
    result[key] = [...value, ...value];
    ;
  } else {
    //init key-value
    result.putIfAbsent(key, () => value);
  }
}

//* Current State of result: {25, feb: [asd, dsa, asd, dsa], 26, feb: [asd, dsa]}

//convert map to list
List<Map<String, dynamic>> formatedListResult = result.entries
    .map(
      (e) => {
        'date': e.key,
        'data': e.value,
      },
    )
    .toList();

print(formatedListResult);
```

Body:
I need to merge arrays that are duplicate

I have data like this

var filterData = [{'date': '25, feb', 'data': ['asd','dsa']}, {'date': '25, feb', 'data': ['asd','dsa']}, {'date': '26, feb', 'data': ['asd','dsa']}]

I want to filter it like [{'date': '25, feb', 'data': ['asd','dsa','asd','dsa']}, {'date': '26, feb', 'data': ['asd','dsa']}]

Body:
The filterData datatype is List<Map<String, dynamic>>, this dynamic satisfy String and List<String>.

filterData  and result data type => List<Map<String, dynamic>>

List<Map<String, String>> + List<Map<String, List<String>>>

Let's take help from Map to have a unique date. Now we are going to create a map, then we will convert to list.

Run on dartPad.

Map<String, List<String>> result = {};

for (final data in filterData) {
  /// assume filterData will never cause null
  final String key = data['date'];
  final List<String> value = data['data'];
  // just append map value
  if (result.containsKey(key)) {
    result[key] = [...value, ...value];
    ;
  } else {
    //init key-value
    result.putIfAbsent(key, () => value);
  }
}

//* Current State of result: {25, feb: [asd, dsa, asd, dsa], 26, feb: [asd, dsa]}

//convert map to list
List<Map<String, dynamic>> formatedListResult = result.entries
    .map(
      (e) => {
        'date': e.key,
        'data': e.value,
      },
    )
    .toList();

print(formatedListResult);


问:
chrome.runtime.onMessage response with async await
I want to use async await in an onMessage listener:

```<code>chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) =>{
    var key = await getKey();
    sendResponse(key);
});
</code>```

However I get undefined when I send a message.

From the documentation for chrome.runtime.onMessage.addListener:

If you want to asynchronously use sendResponse(), add return true; to the onMessage event handler.

This works when I use a callback.

```<code>chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) =>{
    getKey(key => {
        sendResponse(key);
    });
    return true;
});
</code>```

However I would like to leverage the await syntax. But it does not seem to work and still returns undefined:

```<code>chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) =>{
    var key = await getKey();
    sendResponse(key);
    return true;
});
</code>```

答:
I was unable to use async/await, however I did manage to make it work using then. You need to return true at the very end of your onMessage function.

Here is an example of how I'm asynchronously retrieving the current active tab to my content script.

background.js

```<code>chrome.runtime.onMessage.addListener(function (data, sender, sendResponse) {

  if (data.type === 'getTab') {
    const promise = new Promise(async (resolve) => {
      /* gets active tab info */
      let queryOptions = { active: true, currentWindow: true };
      let [tab] = await chrome.tabs.query(queryOptions);

      resolve(tab);
    });

    promise.then((tab) => {
      sendResponse(tab);
    });
  }

  return true;
});

</code>```

content.js

```<code>chrome.runtime.sendMessage(
  {
    type: 'getTab'
  },
  function (data) {

    if (data.type === 'getTab') {
      console.log('my tab', data);
    }
  }
);
</code>```

I hope this helps someone out there.
I've spent more time than I'd care to admit on this one.

Body:
I want to use async await in an onMessage listener:

chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) =>{
    var key = await getKey();
    sendResponse(key);
});

However I get undefined when I send a message.

From the documentation for chrome.runtime.onMessage.addListener:

If you want to asynchronously use sendResponse(), add return true; to the onMessage event handler.

This works when I use a callback.

chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) =>{
    getKey(key => {
        sendResponse(key);
    });
    return true;
});

However I would like to leverage the await syntax. But it does not seem to work and still returns undefined:

chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) =>{
    var key = await getKey();
    sendResponse(key);
    return true;
});

Body:
I was unable to use async/await, however I did manage to make it work using then. You need to return true at the very end of your onMessage function.

Here is an example of how I'm asynchronously retrieving the current active tab to my content script.

background.js

chrome.runtime.onMessage.addListener(function (data, sender, sendResponse) {

  if (data.type === 'getTab') {
    const promise = new Promise(async (resolve) => {
      /* gets active tab info */
      let queryOptions = { active: true, currentWindow: true };
      let [tab] = await chrome.tabs.query(queryOptions);

      resolve(tab);
    });

    promise.then((tab) => {
      sendResponse(tab);
    });
  }

  return true;
});

content.js

chrome.runtime.sendMessage(
  {
    type: 'getTab'
  },
  function (data) {

    if (data.type === 'getTab') {
      console.log('my tab', data);
    }
  }
);

I hope this helps someone out there.
I've spent more time than I'd care to admit on this one.