Reputation: 2520
I wanted to add another action to a controller. So I defined the action in my controller, added a button to activate it and added it to routes.rb.
orders_controller.rb
...
def shipped
...
end
...
routes.rb
resources :orders do
put :shipped, on: :member
end
...
view/orders/edit.html.rb
...
<%= button_to 'Ship', order_shipped_path, method: :put %>
...
However when I tried to view /orders/1/edit I got this error:
No route matches {:action=>"shipped", :controller=>"orders"}
rake routes gave me the following output:
shipped_order PUT /orders/:id/shipped(.:format) orders#shipped
orders GET /orders(.:format) orders#index
POST /orders(.:format) orders#create
new_order GET /orders/new(.:format) orders#new
edit_order GET /orders/:id/edit(.:format) orders#edit
order GET /orders/:id(.:format) orders#show
PUT /orders/:id(.:format) orders#update
DELETE /orders/:id(.:format) orders#destroy
...
After searching and trying to find info about path helpers and routes I found the following alternate syntax, which worked:
<%= button_to 'Ship', [:shipped, @order], method: :put %>
So the question is, why did the alternate syntax work? What's going on behind the scenes? As an aside, is this the correct way of adding actions to routes?
If it is relevant, I'm using Ruby on Rails 3.2
Thanks
Upvotes: 1
Views: 985
Reputation: 26193
By nesting the PUT
shipped
route within your resource route, you are effectively declaring that there is a shipped
action on the Order
controller. Actions are performed on models, and to that extent, the Rails naming convention for link_to
helpers is action_controller
(e.g., new_post_path
).
Running rake routes
yields the following:
# rake routes
shipped_order PUT /orders/:id/shipped(.:format) orders#shipped
To invoke the route, you can utilize the syntax that you're using:
<%= button_to 'Ship', [:shipped, @order], method: :put %>
This bracketed syntax understands the :shipped
symbol to be the action, and orders_controller
to be the controller. It therefore composes the same route that would be created using the path helper:
<%= button_to 'Ship', order_shipped_path(@order), method: :put %>
Upvotes: 2
Reputation: 3935
In the first one you're giving the button_to the route_path but not the resource specific path. The correct way would be to do
order_shipped_path(@order)
The route needs to resolve the :id portion and the helper can only do that when the specific object is passed to it.
shipped_order PUT /orders/:id/shipped(.:format) orders#shipped
In your second case you're telling it both the route, :shipped, and the resource, @order.
Upvotes: 2