-
Notifications
You must be signed in to change notification settings - Fork 21.4k
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
Restore to:
option in routes with an implicit controller
#51523
Conversation
4a3e034
to
1530f70
Compare
ex = assert_raises(ArgumentError) { | ||
draw do | ||
get "/foo/bar", to: "foo#" | ||
end | ||
} | ||
assert_match(/Missing :action/, ex.message) | ||
assert_match(/:to must respond to/, ex.message) |
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.
This used to fail in check_controller_and_action
, whereas now it fails in the checks for the to:
option, which seems correct to me.
@@ -4037,6 +4037,7 @@ def draw(&block) | |||
routes = ActionDispatch::Routing::RouteSet.new | |||
routes.draw(&block) | |||
@app = self.class.build_app routes | |||
@routes = routes |
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.
This lets us use routing assertions directly without having to use with_routing
.
raise ArgumentError, ":to must respond to `action` or `call`, or it must be a String that includes '#'" | ||
if to.is_a?(String) | ||
controller_or_action, action = to.split("#", 2).map!(&:-@) | ||
if !action || action.empty? |
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.
I avoided using action.present?
here, but maybe I could just require the core ext.
else | ||
raise ArgumentError, ":to must respond to `action` or `call`, or it must be a String that includes '#'" | ||
if to.is_a?(String) | ||
controller_or_action, action = to.split("#", 2).map!(&:-@) |
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.
Specifying the numbers of splits here makes sure we handle the "controller#"
case correctly (and that we don't assume controller
is the action).
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.
Can you also add a CHANGELOG entry since this fixes a regression in 7.1.3?
elsif to.is_a?(Symbol) | ||
action = to | ||
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.
If the goal is to backport this to 7-1-stable
I'm not sure we should be adding support for Symbol since that didn't work even before #50466
else | ||
raise ArgumentError, ":to must respond to `action` or `call`, or it must be a String that includes '#'" | ||
if to.is_a?(String) |
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.
I feel like this new code is much harder to follow than before #50466.
What do you think of this diff? It also passes the reproduction script and I think is a bit simpler:
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 724bf72e5c..b152de0ea7 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -231,10 +231,15 @@ def normalize_options!(options, path_params, modyoule)
if to.nil?
controller = default_controller
action = default_action
- elsif to.is_a?(String) && to.include?("#")
- to_endpoint = to.split("#").map!(&:-@)
- controller = to_endpoint[0]
- action = to_endpoint[1]
+ elsif to.is_a?(String)
+ if to.include?("#")
+ to_endpoint = to.split("#").map!(&:-@)
+ controller = to_endpoint[0]
+ action = to_endpoint[1]
+ else
+ controller = default_controller
+ action = default_action
+ end
else
raise ArgumentError, ":to must respond to `action` or `call`, or it must be a String that includes '#'"
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.
Yeah it's nicer. I had to use to
instead of default_action
in the new branch handling the string when it's missing the #
, otherwise the repro script wasn't passing.
1530f70
to
1c9f928
Compare
Added a changelog entry but it's a bit weird since the previous change in 7.1.3 hadn't been mentioned in the first place. |
The `:to` option for routes can once again be a String without a controller if the controller is implicitly provided by a nesting `controller` or `resources` call.
1c9f928
to
36ff424
Compare
…ller Restore `to:` option in routes with an implicit controller
Ref #50465
In #50466, routes that use the
to:
option without providing a controller (e.g.to: "action"
) started to raise an ArgumentError. Before that it was possible to use theto:
option without a controller as long as it was nested within acontroller
,resource
orresources
scope.This broke one of our apps between 7.1.2 and 7.1.3, here's a repro script:
This fails using 7.1.3 and passes using 7.1.2:
This PR fixes this and also allows passing a Symbol in those cases (e.g.
to: :action
).The
:to
option for routes can once again be a Symbol or a String without a controller if the controller is implicitly provided by a nestingcontroller
orresources
call.With these changes, the documentation changes from #50523 would not have been necessary, though it's fine to keep the documentation as it is now.
cc @skipkayhil @p8