Skip to content

Commit 42573e8

Browse files
authored
Remove support for using request.referer as redirect URL. (#5)
* Remove support for using `request.referer` as URL. Redirects preserve the original `HTTP_REFERER` which isn't what we want. You must either use `params[:redirect_url]` or pass an explicit URL with something like this: ```ruby stash_redirect_for :sign_in, on: :new, url: :root_url stash_redirect_for :sign_in, on: :new, url: -> { request.url } ``` * Remove use of referer and cut down some glue code * People will be passing a block to this most likely
1 parent 4b6e60c commit 42573e8

File tree

4 files changed

+25
-56
lines changed

4 files changed

+25
-56
lines changed

README.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@ class ApplicationController < ActionController::Base
1212

1313
private
1414
def authenticate
15-
redirect_to new_session_url unless Current.user
15+
# Pass `redirect_url:` to pass the URL we're currently on.
16+
redirect_to new_session_url(redirect_url: request.url) unless Current.user
1617
end
1718
end
1819

1920
class SessionsController < ApplicationController
2021
# Stash a redirect at the start of the session authentication flow,
21-
# from either params[:redirect_url] or request.referer in that order.
22+
# from `params[:redirect_url]` automatically.
2223
stash_redirect_for :sign_in, on: :new
2324

2425
def new

lib/action_controller/stashed_redirects.rb

+12-12
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,9 @@ def initialize(purpose)
2929
#
3030
# stash_redirect_for :sign_in, on: :new
3131
# stash_redirect_for :sign_in, on: %i[ new edit ]
32-
# stash_redirect_for :sign_in, on: :new, from: :referer
33-
# stash_redirect_for :sign_in, on: :new, from: -> { update_post_path(@post) }
34-
def stash_redirect_for(purpose, on:, from: DEFAULT_FROM)
35-
before_action(-> { stash_redirect_for(purpose, from: from.respond_to?(:call) ? instance_exec(&from) : from) }, only: on)
32+
# stash_redirect_for :sign_in, on: :new, url: -> { update_post_path(@post) }
33+
def stash_redirect_for(purpose, on:, url: DEFAULT_URL)
34+
before_action(-> { stash_redirect_for(purpose, url: url) }, only: on)
3635
end
3736
end
3837

@@ -46,8 +45,8 @@ def stash_redirect_for(purpose, on:, from: DEFAULT_FROM)
4645
# stash_redirect_for :sign_in, from: url_from(params[:redirect_url]) || root_url
4746
# stash_redirect_for :sign_in, from: :param # Only derive the redirect URL from `params[:redirect_url]`.
4847
# stash_redirect_for :sign_in, from: :referer # Only derive the redirect URL from `request.referer`.
49-
def stash_redirect_for(purpose, from: DEFAULT_FROM)
50-
if url = derive_stash_redirect_url_from(from)
48+
def stash_redirect_for(purpose, url: DEFAULT_URL)
49+
if url = derive_stash_redirect_url_from(url)
5150
session[KEY_GENERATOR.(purpose)] = url
5251
else
5352
raise ArgumentError, "missing a redirect_url to stash, pass one via from: or via a redirect_url URL param"
@@ -76,11 +75,12 @@ def stashed_redirect_url_for(purpose)
7675
url_from(discard_stashed_redirect_for(purpose)) or raise MissingRedirectError, purpose
7776
end
7877

79-
def derive_stash_redirect_url_from(from)
80-
from = %i[ param referer ] if from == DEFAULT_FROM
81-
possible_urls = { param: params[:redirect_url], referer: request.get? && request.referer }
82-
83-
url_from(possible_urls.values_at(*from).find(&:present?) || from)
78+
def derive_stash_redirect_url_from(url)
79+
case url
80+
when DEFAULT_URL then redirect_url
81+
when String then url_from url
82+
when Symbol, Proc then url_from instance_exec(self, &url)
83+
end
8484
end
8585

8686
# Looks up a redirect URL from `params[:redirect_url]` using
@@ -91,7 +91,7 @@ def derive_stash_redirect_url_from(from)
9191
# redirect_to redirect_url || users_url
9292
def redirect_url = url_from(params[:redirect_url])
9393

94-
DEFAULT_FROM = Object.new
94+
DEFAULT_URL = Object.new
9595

9696
KEY_GENERATOR = ->(purpose) { "__url_stash_#{purpose}" }
9797
private_constant :KEY_GENERATOR

test/action_controller/stashed_redirects_test.rb

+9-41
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,7 @@ class ActionController::StashedRedirectsTest < ActionDispatch::IntegrationTest
1515
assert_redirected_to users_url
1616
end
1717

18-
test "stash and recall redirect from the referer" do
19-
get new_session_url, headers: { HTTP_REFERER: users_url }
20-
assert_response :no_content
21-
22-
post sessions_url
23-
assert_redirected_to users_url
24-
end
25-
26-
test "passing from: block accesses instance context" do
18+
test "passing url: block accesses instance context" do
2719
delete session_url(id: 1)
2820
assert_redirected_to users_url
2921
end
@@ -44,52 +36,28 @@ class ActionController::StashedRedirectsTest < ActionDispatch::IntegrationTest
4436

4537
class ActionController::StashedRedirects::HooksTest < ActiveSupport::TestCase
4638
module Context
47-
def session
48-
@session ||= {}
49-
end
50-
51-
def params
52-
@params ||= { redirect_url: "/users/param" }
53-
end
54-
55-
def request
56-
@request ||= Struct.new(:host, :referer) { def get? = true }.new "http://example.com", "/users/referer"
57-
end
39+
def request = @request ||= Struct.new(:host).new("http://example.com")
40+
def session = @session ||= {}
41+
def params = { redirect_url: "/users/param" }
5842

5943
def redirect_to(url, *) = url
60-
61-
def url_from(url)
62-
if url.present?
63-
url if URI(url.to_s).host.then { _1.nil? || _1 == request.host }
64-
end
65-
end
44+
def url_from(url) = URI(url.to_s).host.then { _1.nil? || _1 == request.host } && url
6645
end
67-
6846
include Context, ActionController::StashedRedirects
6947

70-
test "param takes precedence over referer" do
48+
test "from redirect_url" do
7149
stash_redirect_for :sign_in
7250
assert_equal "/users/param", redirect_from_stashed(:sign_in)
7351
end
7452

75-
test "from param" do
76-
stash_redirect_for :sign_in, from: :param
77-
assert_equal "/users/param", redirect_from_stashed(:sign_in)
78-
end
79-
80-
test "from referer" do
81-
stash_redirect_for :sign_in, from: :referer
82-
assert_equal "/users/referer", redirect_from_stashed(:sign_in)
83-
end
84-
8553
test "explicit url override" do
86-
stash_redirect_for :sign_in, from: "/users/explicit"
54+
stash_redirect_for :sign_in, url: "/users/explicit"
8755
assert_equal "/users/explicit", redirect_from_stashed(:sign_in)
8856
end
8957

9058
test "passing the wrong URL raises" do
91-
assert_raises(ArgumentError) { stash_redirect_for :sign_in, from: nil }
92-
assert_raises(ArgumentError) { stash_redirect_for :sign_in, from: "http://google.com" }
59+
assert_raises(ArgumentError) { stash_redirect_for :sign_in, url: -> { nil } }
60+
assert_raises(ArgumentError) { stash_redirect_for :sign_in, url: "http://google.com" }
9361
end
9462

9563
test "no stashed redirect raises" do

test/boot/action_controller.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ class ApplicationController < ActionController::Base
44

55
class SessionsController < ApplicationController
66
stash_redirect_for :sign_in, on: :new
7-
stash_redirect_for :sign_out, on: :destroy, from: -> { users_url }
7+
stash_redirect_for :sign_out, on: :destroy, url: :users_url
88

99
def new
1010
head :no_content

0 commit comments

Comments
 (0)