diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 1ec8da0a3..c768005ea 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,4 +1,5 @@ require "devise/hooks/two_step_verification" +require "devise/hooks/set_current_user" class ApplicationController < ActionController::Base include Pundit::Authorization diff --git a/lib/devise/hooks/set_current_user.rb b/lib/devise/hooks/set_current_user.rb new file mode 100644 index 000000000..a2e0fd5b1 --- /dev/null +++ b/lib/devise/hooks/set_current_user.rb @@ -0,0 +1,8 @@ +module Devise::Hooks::SetCurrentUser + Warden::Manager.after_set_user(only: :set_user) do |user, _auth, _options| + Current.user = user + end + Warden::Manager.before_logout do |_user, _auth, _options| + Current.user = nil + end +end diff --git a/test/integration/set_current_attributes_test.rb b/test/integration/set_current_attributes_test.rb index 1f7fa45f0..19650625f 100644 --- a/test/integration/set_current_attributes_test.rb +++ b/test/integration/set_current_attributes_test.rb @@ -2,65 +2,116 @@ class SetCurrentAttributesTest < ActionDispatch::IntegrationTest class TestsController < ApplicationController - cattr_accessor :current_user + cattr_accessor :user, :signed_in_outside_action, :users, :user_ip skip_after_action :verify_authorized def show - render json: { user_id: Current.user&.id, user_ip: Current.user_ip } + self.class.users[:within_action] = Current.user + self.user_ip = Current.user_ip + + head :ok + end + + def signing_in_within_action + self.class.users[:before_signing_in] = Current.user + sign_in(self.class.user) + self.class.users[:after_signing_in] = Current.user + + head :ok + end + + def signing_out_within_action + self.class.users[:before_signing_out] = Current.user + sign_out + self.class.users[:after_signing_out] = Current.user + + head :ok end private def current_user - self.class.current_user + self.class.signed_in_outside_action ? self.class.user : super end end - should "set Current.user if user is signed in" do - with_test_route do + setup do + TestsController.user = nil + TestsController.signed_in_outside_action = false + TestsController.users = {} + TestsController.user_ip = nil + end + + should "set Current.user if user is signed in outside action" do + with_test_routes do user = create(:user) - with_current_user(user) do - visit "/test" + TestsController.signed_in_outside_action = true + TestsController.user = user + visit "/show" - assert_equal user.id, JSON.parse(page.body)["user_id"] - end + assert_equal user, TestsController.users[:within_action] end end - should "not set Current.user if user is not signed in" do - with_test_route do - with_current_user(nil) do - visit "/test" + should "not set Current.user if user is not signed in outside action" do + with_test_routes do + TestsController.signed_in_outside_action = true + TestsController.user = nil + visit "/show" - assert_nil JSON.parse(page.body)["user_id"] - end + assert_nil TestsController.users[:within_action] end end should "set Current.user_ip" do - with_test_route do + with_test_routes do page.driver.options[:headers] = { "REMOTE_ADDR" => "4.5.6.7" } - visit "/test" + visit "/show" + + assert_equal "4.5.6.7", TestsController.user_ip + end + end + + should "set Current.user if user signs in within action" do + with_test_routes do + user = create(:user) + TestsController.user = user + visit "/signing_in_within_action" + + assert_nil TestsController.users[:before_signing_in] + assert_equal user, TestsController.users[:after_signing_in] + end + end + + should "unset Current.user if user signs out within action" do + with_test_routes do + user = create(:user) + TestsController.signed_in_outside_action = true + TestsController.user = user + visit "/signing_out_within_action" - assert_equal "4.5.6.7", JSON.parse(page.body)["user_ip"] + assert_equal user, TestsController.users[:before_signing_out] + assert_nil TestsController.users[:after_signing_out] end end private - def with_test_route + def with_test_routes Rails.application.routes.draw do - get "/test" => "set_current_attributes_test/tests#show" + get "/show" => "set_current_attributes_test/tests#show" + get "/signing_in_within_action" => "set_current_attributes_test/tests#signing_in_within_action" + get "/signing_out_within_action" => "set_current_attributes_test/tests#signing_out_within_action" end yield ensure Rails.application.reload_routes! end - def with_current_user(user) - TestsController.current_user = user + def with_user(user) + TestsController.user = user yield ensure - TestsController.current_user = nil + TestsController.user = nil end end