简体   繁体   中英

Is there a specific place in Rails where Devise deletes a user's session? Can't delete session due to read-only database

I've switched over to multi-databases where I have a reader and writer instance. As Rails 6+ auto switches database instances based on the HTTP verb, this has introduced several issues as it relates to Devise. While I was able to resolve most of them, one that seems to still be lingering is when a user submits an HTTP GET request and Devise tries to initiate a DELETE statement into the database.

Since Rails is connected to the read-only database during the GET request from the user, the user experiences a 404 error because of Devise trying to delete the session record.

Here's an example of the error:

ActiveRecord::ReadOnlyError: Write query attempted while in readonly mode: DELETE FROM "sessions" WHERE "sessions"."id" = $1
  from activerecord (7.0.2.4) lib/active_record/connection_adapters/abstract_adapter.rb:120:in `check_if_write_query'
  from activerecord (7.0.2.4) lib/active_record/connection_adapters/postgresql_adapter.rb:742:in `execute_and_clear'
  from activerecord (7.0.2.4) lib/active_record/connection_adapters/postgresql/database_statements.rb:71:in `exec_delete'
  from activerecord (7.0.2.4) lib/active_record/connection_adapters/abstract/database_statements.rb:181:in `delete'
  from activerecord (7.0.2.4) lib/active_record/connection_adapters/abstract/query_cache.rb:22:in `delete'
  from activerecord (7.0.2.4) lib/active_record/persistence.rb:530:in `_delete_record'
  from activerecord (7.0.2.4) lib/active_record/persistence.rb:1043:in `_delete_row'
  from activerecord (7.0.2.4) lib/active_record/persistence.rb:1039:in `destroy_row'
  from activerecord (7.0.2.4) lib/active_record/counter_cache.rb:176:in `destroy_row'
  from activerecord (7.0.2.4) lib/active_record/locking/optimistic.rb:121:in `destroy_row'
  from activerecord (7.0.2.4) lib/active_record/persistence.rb:681:in `destroy'
  from activerecord (7.0.2.4) lib/active_record/callbacks.rb:439:in `block in destroy'
  from activesupport (7.0.2.4) lib/active_support/callbacks.rb:99:in `run_callbacks'
  from activesupport (7.0.2.4) lib/active_support/callbacks.rb:929:in `_run_destroy_callbacks'
  from activerecord (7.0.2.4) lib/active_record/callbacks.rb:439:in `destroy'
  from activerecord (7.0.2.4) lib/active_record/transactions.rb:294:in `block in destroy'
  from activerecord (7.0.2.4) lib/active_record/transactions.rb:354:in `block in with_transaction_returning_status'
  from activerecord (7.0.2.4) lib/active_record/connection_adapters/abstract/transaction.rb:319:in `block in within_new_transaction'
  from activesupport (7.0.2.4) lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `handle_interrupt'
  from activesupport (7.0.2.4) lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `block in synchronize'
  from activesupport (7.0.2.4) lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `handle_interrupt'
  from activesupport (7.0.2.4) lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `synchronize'
...

I just simply need to wrap wherever this is being initiated around this block:

      ActiveRecord::Base.connected_to(role: :writing) do
        # Devise method that calls DELETE on session needs to be here.
      end

Is there a way to "intercept" or "wrap" this session delete call around the above method?

When the Rails app calls current_user it tries to detect the data from sessions table. Now, if the session is expired it will try to delete the record and since the call to the URL will be GET call, the app will use read only db. Now to make this work you will need to put the code of that uses the current_user session variable inside the code you mentioned above.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM