From 5ed6ea340687f32fb08ccabf471fd711fa0e5c81 Mon Sep 17 00:00:00 2001 From: Matthew McGarvey Date: Tue, 2 Jun 2020 23:15:50 -0500 Subject: [PATCH 1/3] Add redirect_back functionality --- spec/lucky/action_redirect_spec.cr | 24 ++++++++++++++++++ src/lucky/redirectable.cr | 40 ++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/spec/lucky/action_redirect_spec.cr b/spec/lucky/action_redirect_spec.cr index 8e2330f4d..9def43414 100644 --- a/spec/lucky/action_redirect_spec.cr +++ b/spec/lucky/action_redirect_spec.cr @@ -37,6 +37,30 @@ describe Lucky::Action do should_redirect(action, to: "/somewhere", status: 301) end + it "redirects back" do + request = build_request("POST") + request.headers["Referer"] = "https://www.example.com/coming/from" + action = RedirectAction.new(build_context(request), params) + action.redirect_back fallback: "/fallback" + should_redirect(action, to: "https://www.example.com/coming/from", status: 302) + + action = RedirectAction.new(build_context, params) + action.redirect_back fallback: "/fallback" + should_redirect(action, to: "/fallback", status: 302) + + action = RedirectAction.new(build_context, params) + action.redirect_back fallback: RedirectAction.route + should_redirect(action, to: RedirectAction.path, status: 302) + + action = RedirectAction.new(build_context, params) + action.redirect_back fallback: RedirectAction + should_redirect(action, to: RedirectAction.path, status: 302) + + action = RedirectAction.new(build_context, params) + action.redirect_back fallback: RedirectAction, status: 301 + should_redirect(action, to: RedirectAction.path, status: 301) + end + it "turbolinks redirects after a XHR POST form submission" do request = build_request("POST") request.headers["Accept"] = "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01" diff --git a/src/lucky/redirectable.cr b/src/lucky/redirectable.cr index eb46d1cf3..d6505ad2e 100644 --- a/src/lucky/redirectable.cr +++ b/src/lucky/redirectable.cr @@ -24,6 +24,46 @@ # method that takes a `String`. However, it's recommended you pass a # `Lucky::Action` class if possible because it guarantees runtime safety. module Lucky::Redirectable + # Redirect back with a `Lucky::Action` fallback + # + # ```crystal + # redirect_back fallback: Users::Index + # ``` + def redirect_back(fallback : Lucky::Action.class, status = 302) + redirect_back fallback.route, status + end + + # Redirect back with a `Lucky::RouteHelper` fallback + # + # ```crystal + # redirect_back fallback: Users::Show.with(user.id) + # ``` + def redirect_back(fallback : Lucky::RouteHelper, status = 302) + redirect_back fallback.path, status + end + + # Redirects the browser to the page that issued the request (the referrer) + # if possible, otherwise redirects to the provided default fallback + # location. + # + # The referrer information is pulled from the 'Referer' header on + # the request. This is an optional header, and if the request + # is missing this header the *fallback* will be used. + # + # ```crystal + # redirect_back fallback: "/users" + # ``` + # + # A redirect status can be specified + # + # ```crystal + # redirect_back fallback: "/home", status: 301 + # ``` + def redirect_back(fallback : String, status = 302) + referer = request.headers["Referer"]? + redirect to: (referer || fallback), status: status + end + # Redirect using a `Lucky::RouteHelper` # # ```crystal From 231d58d7e4f995171ffd97422a8b5c7e2ce2589d Mon Sep 17 00:00:00 2001 From: Matthew McGarvey Date: Wed, 3 Jun 2020 19:19:12 -0500 Subject: [PATCH 2/3] Add support for HTTP::Status in redirect_back --- spec/lucky/action_redirect_spec.cr | 4 ++++ src/lucky/redirectable.cr | 11 ++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/spec/lucky/action_redirect_spec.cr b/spec/lucky/action_redirect_spec.cr index 9def43414..e2c5b31bc 100644 --- a/spec/lucky/action_redirect_spec.cr +++ b/spec/lucky/action_redirect_spec.cr @@ -56,6 +56,10 @@ describe Lucky::Action do action.redirect_back fallback: RedirectAction should_redirect(action, to: RedirectAction.path, status: 302) + action = RedirectAction.new(build_context, params) + action.redirect_back fallback: RedirectAction, status: HTTP::Status::MOVED_PERMANENTLY + should_redirect(action, to: RedirectAction.path, status: 301) + action = RedirectAction.new(build_context, params) action.redirect_back fallback: RedirectAction, status: 301 should_redirect(action, to: RedirectAction.path, status: 301) diff --git a/src/lucky/redirectable.cr b/src/lucky/redirectable.cr index d6505ad2e..72de62608 100644 --- a/src/lucky/redirectable.cr +++ b/src/lucky/redirectable.cr @@ -42,6 +42,15 @@ module Lucky::Redirectable redirect_back fallback.path, status end + # Redirect back with a human friendly status + # + # ```crystal + # redirect_back fallback: "/users", status: HTTP::Status::MOVED_PERMANENTLY + # ``` + def redirect_back(fallback : String, status : HTTP::Status) + redirect_back fallback, status.value + end + # Redirects the browser to the page that issued the request (the referrer) # if possible, otherwise redirects to the provided default fallback # location. @@ -59,7 +68,7 @@ module Lucky::Redirectable # ```crystal # redirect_back fallback: "/home", status: 301 # ``` - def redirect_back(fallback : String, status = 302) + def redirect_back(fallback : String, status : Int32 = 302) referer = request.headers["Referer"]? redirect to: (referer || fallback), status: status end From b282afef06a0c50b1ba0fdc38646752a8fc7ab6f Mon Sep 17 00:00:00 2001 From: Matthew McGarvey Date: Fri, 5 Jun 2020 18:35:43 -0500 Subject: [PATCH 3/3] Require keyword arguments to be used for redirect_back --- src/lucky/redirectable.cr | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/lucky/redirectable.cr b/src/lucky/redirectable.cr index 72de62608..997b62306 100644 --- a/src/lucky/redirectable.cr +++ b/src/lucky/redirectable.cr @@ -29,8 +29,8 @@ module Lucky::Redirectable # ```crystal # redirect_back fallback: Users::Index # ``` - def redirect_back(fallback : Lucky::Action.class, status = 302) - redirect_back fallback.route, status + def redirect_back(*, fallback : Lucky::Action.class, status = 302) + redirect_back fallback: fallback.route, status: status end # Redirect back with a `Lucky::RouteHelper` fallback @@ -38,8 +38,8 @@ module Lucky::Redirectable # ```crystal # redirect_back fallback: Users::Show.with(user.id) # ``` - def redirect_back(fallback : Lucky::RouteHelper, status = 302) - redirect_back fallback.path, status + def redirect_back(*, fallback : Lucky::RouteHelper, status = 302) + redirect_back fallback: fallback.path, status: status end # Redirect back with a human friendly status @@ -47,8 +47,8 @@ module Lucky::Redirectable # ```crystal # redirect_back fallback: "/users", status: HTTP::Status::MOVED_PERMANENTLY # ``` - def redirect_back(fallback : String, status : HTTP::Status) - redirect_back fallback, status.value + def redirect_back(*, fallback : String, status : HTTP::Status) + redirect_back fallback: fallback, status: status.value end # Redirects the browser to the page that issued the request (the referrer) @@ -68,7 +68,7 @@ module Lucky::Redirectable # ```crystal # redirect_back fallback: "/home", status: 301 # ``` - def redirect_back(fallback : String, status : Int32 = 302) + def redirect_back(*, fallback : String, status : Int32 = 302) referer = request.headers["Referer"]? redirect to: (referer || fallback), status: status end