-
Notifications
You must be signed in to change notification settings - Fork 328
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
"Break out" of a frame from the server #367
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
module Turbo::Streams::Redirect | ||
extend ActiveSupport::Concern | ||
|
||
def redirect_to(options = {}, response_options = {}) | ||
turbo_frame = response_options.delete(:turbo_frame) | ||
turbo_action = response_options.delete(:turbo_action) | ||
location = url_for(options) | ||
|
||
if request.format.turbo_stream? && turbo_frame.present? | ||
alert, notice, flash_override = response_options.values_at(:alert, :notice, :flash) | ||
flash.merge!(flash_override || {alert: alert, notice: notice}) | ||
|
||
case Rack::Utils.status_code(response_options.fetch(:status, :created)) | ||
when 300..399 then response_options[:status] = :created | ||
end | ||
|
||
render "turbo/streams/redirect", **response_options.with_defaults( | ||
locals: {location: location, turbo_frame: turbo_frame, turbo_action: turbo_action}, | ||
location: location, | ||
) | ||
else | ||
super | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<%= turbo_stream.append_all "head" do %> | ||
<%= javascript_tag nonce: true, data: {turbo_cache: false} do %> | ||
window.Turbo.visit("<%= escape_javascript response.location %>", { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Having the flexibility to redirect the whole page from a request that came from a I gave this change a spin and hit a bit of an issue...
I removed the A similar issue happens if the page is cached with the incomplete (More widely, this affects any Turbo Stream response triggered from a link inside a I 'solved' the problem by forcing the
I'm guessing that workaround isn't the best approach - because Would really welcome your thoughts on the right approach to this. |
||
frame: "<%= escape_javascript turbo_frame %>", | ||
<% if turbo_action.present? %> | ||
action: "<%= escape_javascript turbo_action %>", | ||
<% end %> | ||
}) | ||
document.currentScript.remove() | ||
<% end %> | ||
<% end %> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<details> | ||
<summary>New Article</summary> | ||
|
||
<%= turbo_frame_tag @article do %> | ||
<%= form_with model: @article do |form| %> | ||
<%= form.label :body %> | ||
<%= form.text_area :body, aria: { describedby: (dom_id(@article, :errors) if @article.errors[:body].any?) } %> | ||
<% if @article.errors[:body].any? %> | ||
<p id="<%= dom_id(@article, :errors) %>"> | ||
<%= @article.errors[:body].to_sentence %> | ||
</p> | ||
<% end %> | ||
|
||
<%= form.button name: :turbo_frame, value: "_top"%> | ||
<% end %> | ||
<% end %> | ||
</details> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
require "test_helper" | ||
|
||
class Turbo::Streams::RedirectTest < ActionDispatch::IntegrationTest | ||
test "html requests respond with a redirect HTTP status" do | ||
post articles_path, params: { | ||
turbo_frame: "_top", status: 303, | ||
article: {body: "A valid value"} | ||
} | ||
|
||
assert_response :see_other | ||
assert_redirected_to articles_url | ||
assert_equal "Created!", flash[:notice] | ||
end | ||
|
||
test "html redirects write to the flash" do | ||
post articles_path, params: { | ||
turbo_frame: "_top", flash: {alert: "Wrote to alert:"}, | ||
article: {body: "A valid value"} | ||
} | ||
|
||
assert_equal "Wrote to alert:", flash[:alert] | ||
end | ||
|
||
test "html redirects write to alert" do | ||
post articles_path, params: { | ||
turbo_frame: "_top", alert: "Wrote to alert:", | ||
article: {body: "A valid value"} | ||
} | ||
|
||
assert_equal "Wrote to alert:", flash[:alert] | ||
end | ||
|
||
test "html redirects write to notice" do | ||
post articles_path, params: { | ||
turbo_frame: "_top", notice: "Wrote to notice:", | ||
article: {body: "A valid value"} | ||
} | ||
|
||
assert_equal "Wrote to notice:", flash[:notice] | ||
end | ||
|
||
test "turbo_stream requests with the turbo_frame: option responds with a redirect Turbo Stream" do | ||
post articles_path, as: :turbo_stream, params: { | ||
turbo_frame: "_top", | ||
article: {body: "A valid value"} | ||
} | ||
|
||
assert_turbo_stream action: :append, targets: "head", status: :created do | ||
assert_select "script[data-turbo-cache=false]", count: 1 do |script| | ||
assert_includes script.text, %(frame: "_top",) | ||
assert_not_includes script.text, %(action:) | ||
end | ||
end | ||
assert_equal articles_url, response.location | ||
end | ||
|
||
test "turbo_stream requests with the turbo_frame: and turbo_action: options responds with a redirect Turbo Stream" do | ||
post articles_path, as: :turbo_stream, params: { | ||
turbo_frame: "_top", | ||
turbo_action: "replace", | ||
article: {body: "A valid value"} | ||
} | ||
|
||
assert_turbo_stream action: :append, targets: "head", status: :created do | ||
assert_select "script[data-turbo-cache=false]", count: 1 do |script| | ||
assert_includes script.text, %(frame: "_top",) | ||
assert_includes script.text, %(action: "replace",) | ||
end | ||
end | ||
assert_equal articles_url, response.location | ||
end | ||
|
||
test "turbo_stream requests with the turbo_frame: option preserves status: values in the 2xx range" do | ||
post articles_path, as: :turbo_stream, params: { | ||
turbo_frame: "_top", status: 200, | ||
article: { body: "A valid value" } | ||
} | ||
|
||
assert_response 200 | ||
end | ||
|
||
test "turbo_stream requests with the turbo_frame: option replaces status: values in the 3xx range with 201 Created" do | ||
post articles_path, as: :turbo_stream, params: { | ||
turbo_frame: "_top", status: 303, | ||
article: { body: "A valid value" } | ||
} | ||
|
||
assert_response 201 | ||
end | ||
|
||
test "turbo_stream requests with the turbo_frame: option preserves status: values in the 4xx range" do | ||
post articles_path, as: :turbo_stream, params: { | ||
turbo_frame: "_top", status: 403, | ||
article: { body: "A valid value" } | ||
} | ||
|
||
assert_response 403 | ||
end | ||
|
||
test "turbo_stream requests with the turbo_frame: option preserves status: values in the 5xx range" do | ||
post articles_path, as: :turbo_stream, params: { | ||
turbo_frame: "_top", status: 500, | ||
article: { body: "A valid value" } | ||
} | ||
|
||
assert_response 500 | ||
end | ||
|
||
test "turbo_stream requests without the turbo_frame: option respond with a redirect HTTP status" do | ||
post articles_path, as: :turbo_stream, params: { | ||
article: { body: "A valid value" } | ||
} | ||
|
||
assert_redirected_to articles_url | ||
end | ||
|
||
test "turbo_stream redirects write to the flash" do | ||
post articles_path, as: :turbo_stream, params: { | ||
turbo_frame: "_top", flash: {alert: "Wrote to alert:"}, | ||
article: {body: "A valid value"} | ||
} | ||
|
||
assert_equal "Wrote to alert:", flash[:alert] | ||
end | ||
|
||
test "turbo_stream redirects write to alert" do | ||
post articles_path, as: :turbo_stream, params: { | ||
turbo_frame: "_top", alert: "Wrote to alert:", | ||
article: {body: "A valid value"} | ||
} | ||
|
||
assert_equal "Wrote to alert:", flash[:alert] | ||
end | ||
|
||
test "turbo_stream redirects write to notice" do | ||
post articles_path, as: :turbo_stream, params: { | ||
turbo_frame: "_top", notice: "Wrote to notice:", | ||
article: {body: "A valid value"} | ||
} | ||
|
||
assert_equal "Wrote to notice:", flash[:notice] | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
require "application_system_test_case" | ||
|
||
class FramesTest < ApplicationSystemTestCase | ||
test "can render an invalid submission within a frame" do | ||
visit new_article_path | ||
toggle_disclosure "New Article" do | ||
click_on "Create Article" | ||
end | ||
|
||
within_disclosure "New Article" do | ||
assert_field "Body", described_by: "can't be blank" | ||
end | ||
end | ||
|
||
test "can redirect the entire page after a valid submission within a frame" do | ||
visit new_article_path | ||
toggle_disclosure "New Article" do | ||
fill_in "Body", with: "An article's body" | ||
click_on "Create Article" | ||
end | ||
|
||
assert_no_selector :disclosure, "New Article" | ||
assert_no_field "Body" | ||
assert_text "An article's body" | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A possible alternative to handling the
flash
options here could be to callsuper
first, then set the response body with the Turbo Stream. This way, the existingredirect_to
still handles theflash
options, including any custom flash types added withadd_flash_types
.Similar to the
Turbo::Redirection
module here, we could have something like: