Skip to content

Commit a321f52

Browse files
committed
Mount /admin/logout with the methods AA + Devise configured
Read whatever methods Devise.sign_out_via and ActiveAdmin.application.logout_link_method combine to (same set AA's own Devise integration uses in lib/active_admin/devise.rb) and mount the destroy route with `via:` that list. Host stays in control — keep AA defaults and the gem mounts a :get logout; set `config.logout_link_method = :delete` and the gem mounts :delete. This block runs in after_initialize, after the host's config/initializers/active_admin.rb has set its value. Turns the failing spec from the previous commit green.
1 parent 3ab4c9b commit a321f52

2 files changed

Lines changed: 81 additions & 3 deletions

File tree

lib/activeadmin/oidc/engine.rb

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,24 @@ def controllers
156156
# isolated engines don't try to resolve the controller as
157157
# `<Engine>::ActiveAdmin::Devise::SessionsController` from
158158
# the relative string form.
159-
get login_path, to: ::ActiveAdmin::Devise::SessionsController.action(:new), as: :"new_#{scope_name}_session"
160-
delete logout_path, to: ::ActiveAdmin::Devise::SessionsController.action(:destroy), as: :"destroy_#{scope_name}_session"
159+
get login_path, to: ::ActiveAdmin::Devise::SessionsController.action(:new), as: :"new_#{scope_name}_session"
160+
161+
# Mirror what AA's own Devise integration does in
162+
# lib/active_admin/devise.rb: accept whichever HTTP
163+
# methods Devise.sign_out_via and
164+
# ActiveAdmin.application.logout_link_method combine to.
165+
# Read at route-draw time (not in the enclosing
166+
# after_initialize) so `Rails.application.reload_routes!`
167+
# picks up host changes to either value — useful for
168+
# specs that stub the setting and re-evaluate routes.
169+
# AA 4 dropped `logout_link_method` (its layout uses
170+
# `button_to` + Turbo), so only consult the setting when
171+
# the version still exposes it.
172+
aa_app = ::ActiveAdmin.application
173+
aa_method = aa_app.logout_link_method if aa_app.respond_to?(:logout_link_method)
174+
logout_via = [*::Devise.sign_out_via, aa_method].compact.uniq
175+
176+
match logout_path, to: ::ActiveAdmin::Devise::SessionsController.action(:destroy), as: :"destroy_#{scope_name}_session", via: logout_via
161177
end
162178
end
163179
end

spec/requests/logout_spec.rb

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@
7878
context "with AA's default logout_link_method (:get)" do
7979
before { sign_in admin_user }
8080

81-
it "accepts GET /admin/logout" do
81+
it "accepts GET /admin/logout", skip: (ActiveAdmin::Oidc.aa_v4? && "AA 4 dropped logout_link_method; layout uses button_to + Turbo") do
8282
get "/admin/logout"
8383

8484
expect(response).to be_redirect
@@ -87,4 +87,66 @@
8787
expect(response).to redirect_to("/admin/login")
8888
end
8989
end
90+
91+
# Route-table introspection so a future regression in the mount-time
92+
# method-resolution logic is caught even if no request spec happens
93+
# to exercise the affected verb. Reads the verbs actually advertised
94+
# by the destroy route and compares them against what AA and Devise
95+
# configured.
96+
describe "destroy_admin_user_session route verbs" do
97+
subject(:route) do
98+
Rails.application.routes.routes.find { |r| r.name == "destroy_admin_user_session" }
99+
end
100+
101+
it "exists" do
102+
expect(route).not_to be_nil
103+
end
104+
105+
it "includes Devise.sign_out_via" do
106+
Array(::Devise.sign_out_via).each do |method|
107+
expect(route.verb).to match(/#{method.to_s.upcase}/),
108+
"destroy_admin_user_session does not accept #{method.to_s.upcase} (verb: #{route.verb.inspect})"
109+
end
110+
end
111+
112+
it "includes ActiveAdmin.application.logout_link_method when AA exposes it" do
113+
aa_app = ::ActiveAdmin.application
114+
skip "AA 4 dropped logout_link_method" unless aa_app.respond_to?(:logout_link_method)
115+
116+
expected = aa_app.logout_link_method&.to_s&.upcase
117+
skip "logout_link_method not set" if expected.nil?
118+
119+
expect(route.verb).to match(/#{expected}/),
120+
"destroy_admin_user_session does not accept #{expected} (verb: #{route.verb.inspect})"
121+
end
122+
123+
# End-to-end proof that the gem follows host overrides: change
124+
# AA's setting, reload routes, then drive an actual request
125+
# through the freshly-drawn route. Catches regressions where
126+
# logout_link_method gets read once at boot and frozen into the
127+
# closure (route introspection alone wouldn't catch a frozen
128+
# `via:` array if Rails resolved it before the stub took effect).
129+
it "logs the user out via the method host configured on logout_link_method" do
130+
aa_app = ::ActiveAdmin.application
131+
skip "AA 4 dropped logout_link_method" unless aa_app.respond_to?(:logout_link_method)
132+
133+
original = aa_app.logout_link_method
134+
begin
135+
allow(aa_app).to receive(:logout_link_method).and_return(:put)
136+
Rails.application.reload_routes!
137+
138+
sign_in admin_user
139+
put "/admin/logout"
140+
expect(response).to be_redirect
141+
142+
# Session is really cleared — subsequent admin request is
143+
# bounced back to the login page.
144+
get "/admin"
145+
expect(response).to redirect_to("/admin/login")
146+
ensure
147+
allow(aa_app).to receive(:logout_link_method).and_return(original)
148+
Rails.application.reload_routes!
149+
end
150+
end
151+
end
90152
end

0 commit comments

Comments
 (0)