Switching to another user causes a duplicate request
shadydealer opened this issue · 1 comments
Switching to another account causes duplicate requests
I want to allow a caregiver to be able to switch to a child's account and then switch back. The problem is that two requests are sent before the second request gets sent the user has already been changed and so the original_user is now the user we've switched to, so there's no switching back to the caregiver's user.
Log
Started GET "/switch_user?scope_identifier=user_2" for 127.0.0.1 at 2021-08-11 12:48:58 +0300
....
Completed 302 Found in 9ms (ActiveRecord: 0.8ms | Allocations: 3011)
Started GET "/" for 127.0.0.1 at 2021-08-11 12:48:58 +0300
...
Completed 200 OK in 18ms (Views: 13.2ms | ActiveRecord: 1.0ms | Allocations: 9008)
Started GET "/switch_user?scope_identifier=user_2" for 127.0.0.1 at 2021-08-11 12:48:58 +0300
...
Redirected to http://localhost:3000/
Completed 302 Found in 9ms (ActiveRecord: 0.6ms | Allocations: 3453)
Started GET "/" for 127.0.0.1 at 2021-08-11 12:48:58 +0300
....
Completed 200 OK in 20ms (Views: 15.7ms | ActiveRecord: 0.9ms | Allocations: 8962)
What I've got is the following:
- My erb view file:
<% current_user_children = current_user.children %>
<% unless current_user_children.empty? %>
<% current_user_children.each do |child| %>
<%= link_to "Switch to #{child.email}", "/switch_user?scope_identifier=user_#{child.id}" %>
<% end %>
<% end %>
- My config/initializers/switch_user.rb
# frozen_string_literal: true
SwitchUser.setup do |config|
# provider may be :devise, :authlogic, :clearance, :restful_authentication, :sorcery, or :session
config.provider = :devise
# available_users is a hash,
# key is the model name of user (:user, :admin, or any name you use),
# value is a block that return the users that can be switched.
config.available_users = { user: -> { User.all } }
# available_users_identifiers is a hash,
# keys in this hash should match a key in the available_users hash
# value is the name of the identifying column to find by,
# defaults to id
# this hash is to allow you to specify a different column to
# expose for instance a username on a User model instead of id
config.available_users_identifiers = { user: :id }
# available_users_names is a hash,
# keys in this hash should match a key in the available_users hash
# value is the column name which will be displayed in select box
config.available_users_names = { user: :email }
# controller_guard is a block,
# if it returns true, the request will continue,
# else the request will be refused and returns "Permission Denied"
# if you switch from "admin" to user, the current_user param is "admin"
config.controller_guard = ->(current_user, request, original_user) { current_user.caregivers.where(caregiver: original_user) }
# view_guard is a block,
# if it returns true, the switch user select box will be shown,
# else the select box will not be shown
# if you switch from admin to "user", the current_user param is "user"
config.view_guard = ->(current_user, request, original_user) { Rails.env.development? }
# redirect_path is a block, it returns which page will be redirected
# after switching a user.
config.redirect_path = ->(_request, _params) { '/' }
# helper_with_guest is a boolean value, if it set to false
# the guest item in the helper won't be shown
config.helper_with_guest = false
# false = login from one scope to another and you are logged in only in both scopes
# true = you are logged only into one scope at a time
config.login_exclusive = true
# switch_back allows you to switch back to a previously selected user. See
# README for more details.
config.switch_back = true
end
Rails version 6.1.4
Ruby version 2.7.4
We managed to find out what the problem was. We're using turbolinks in our application and so wrapping the link in a data-turbolinks="false"
div fixed the problem for us. Like so:
<% current_user_children = current_user.children %>
<% unless current_user_children.empty? %>
<% current_user_children.each do |child| %>
<div data-turbolinks="false">
<%= link_to "Switch to #{child.email}'s Tracker", "/switch_user?scope_identifier=user_#{child.id}", class: "btn btn-primary" %>
</div>
<% end %>
<% end %>
So the return link should be:
<% if provider.original_user %>
<div data-turbolinks="false">
<%= link_to "Swtich back to #{provider.original_user.email}", "/switch_user?scope_identifier=user_#{provider.original_user.id}&remember=false", class: "btn btn-primary" %>
</div>
<% end %>
EDIT:
The issue WAS NOT turbolinks in our case. The issue was that in one of our stimulus controllers we were calling:
s1.setAttribute('data-turbolinks-track', 'reload');
which causes a full page reload and all of the requests got processed twice.