SanjiBukai SanjiBukai - 16 days ago 8
Ruby Question

Why redirecting to #show action without passing the :id param work (in rails)?

I have a simple question about rails.

I followed a tutorial (from CrashLearner).
In that tutorial we have a simple resource

message
that generates the regular following routes (excerpt from
rake routes
)

Prefix Verb URI Pattern Controller#Action
messages GET /messages(.:format) messages#index
POST /messages(.:format) messages#create
new_message GET /messages/new(.:format) messages#new
edit_message GET /messages/:id/edit(.:format) messages#edit
message GET /messages/:id(.:format) messages#show
PATCH /messages/:id(.:format) messages#update
PUT /messages/:id(.:format) messages#update
DELETE /messages/:id(.:format) messages#destroy


As I understand the route to get to the
show
action of this controller is like something
/messages/17
, I mean we have to put the
:id
of that particular message we want to view.

So, if I needed to redirect the user to this message view after he modified it (in the
#update
action) I should use:

redirect_to message_path(17)


But it turns out that omitting this
:id
actually works great:

redirect_to message_path


Why and how this last one work ?

Since this works from an action that actually received the
:id
param I suppose that the controller keep it in memory and pass it through by default under the hood when it is missing but I would like to understand where this behavior come from ?

I found nothing in the rails documentation.

Here is the github repository of the tutorial, so the exact specific place of the above line is here in this controller.

And I confirm that this works.

There is also a
Comment
resource that is nested from the previous
Message
resource.
As you can see in that controller on the
update
action
, after updating a comment (which is nested within a message) the controller redirects to the
message_path
but in that case the
:id
parameter is present through the instance variable
@message
(and I learned that this works because the object
Message
respond to an
.id
method otherwise it should be
@message.id
)


I supposed that the reason that why here the
:id
is still passed is because we are in the
Comments
controller and the
:id
of another resource could not be passed under the hood, thus why it is explicitely written.

I don't have another explication..

Can anyone explain me why this works ?

Answer

I found this in rails source:

Missing routes keys may be filled in from the current request's parameters (e.g. +:controller+, +:action+, +:id+ and any other parameters that are placed in the path).

https://github.com/rails/rails/blob/92703a9ea5d8b96f30e0b706b801c9185ef14f0e/actionpack/lib/action_dispatch/routing/url_for.rb#L153

So here :id exists in current request params and it's used for this route.