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?
CodePudding user response:
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.