diff --git a/spec/lucky/action_redirect_spec.cr b/spec/lucky/action_redirect_spec.cr index 8e2330f4d..e2c5b31bc 100644 --- a/spec/lucky/action_redirect_spec.cr +++ b/spec/lucky/action_redirect_spec.cr @@ -37,6 +37,34 @@ 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: 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) + 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..997b62306 100644 --- a/src/lucky/redirectable.cr +++ b/src/lucky/redirectable.cr @@ -24,6 +24,55 @@ # 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: fallback.route, status: 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: fallback.path, status: 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: fallback, status: 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. + # + # 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 : Int32 = 302) + referer = request.headers["Referer"]? + redirect to: (referer || fallback), status: status + end + # Redirect using a `Lucky::RouteHelper` # # ```crystal