I'm having trouble routing a form to a custom action in Rails 3. Here are my routes:
resources :photos do
resources :comments
collection do
get 'update_states'
end
member do
put 'upload'
end
end
Here's the form_for:
form_for @photo, :remote => true, :url => { :action => upload_photo_path(@photo) }, :html => { :multipart => :true, :method => 'put' } do |f|
And here's the error message:
No route matches {:action=>"/photos/42/upload", :controller=>"photos"}
... this is especially frustrating because "photos/:id/upload" is exactly the correct action for this form.
What am I missing?
EDITS - Here are the original Photo-related routes:
photo_comments GET /photos/:photo_id/comments(.:format) {:action=>"index", :controller=>"comments"}
POST /photos/:photo_id/comments(.:format) {:action=>"create", :controller=>"comments"}
new_photo_comment GET /photos/:photo_id/comments/new(.:format) {:action=>"new", :controller=>"comments"}
edit_photo_comment GET /photos/:photo_id/comments/:id/edit(.:format) {:action=>"edit", :controller=>"comments"}
photo_comment GET /photos/:photo_id/comments/:id(.:format) {:action=>"show", :controller=>"comments"}
PUT /photos/:photo_id/comments/:id(.:format) {:action=>"update", :controller=>"comments"}
DELETE /photos/:photo_id/comments/:id(.:format) {:action=>"destroy", :controller=>"comments"}
update_states_photos GET /photos/update_states(.:format) {:action=>"update_states", :controller=>"photos"}
upload_photo PUT /photos/:id/upload(.:format) {:action=>"upload", :controller=>"photos"}
photos GET /photos(.:format) {:action=>"index", :controller=>"photos"}
POST /photos(.:format) {:action=>"create", :controller=>"photos"}
new_photo GET /photos/new(.:format) {:action=>"new", :controller=>"photos"}
edit_photo GET /photos/:id/edit(.:format) {:action=>"edit", :controller=>"photos"}
photo GET /photos/:id(.:format) {:action=>"show", :controller=>"photos"}
PUT /photos/:id(.:format) {:action=>"update", :controller=>"photos"}
DELETE /photos/:id(.:format) {:action=>"destroy", :controller=>"photos"}
Here are the relevant routes when I changed the route to match 'upload'
:
photo_comments GET /photos/:photo_id/comments(.:format) {:action=>"index", :controller=>"comments"}
POST /photos/:photo_id/comments(.:format) {:action=>"create", :controller=>"comments"}
}
new_photo_comment GET /photos/:photo_id/comments/new(.:format) {:action=>"new", :controller=>"comments"}
edit_photo_comment GET /photos/:photo_id/comments/:id/edit(.:format) {:action=>"edit", :controller=>"comments"}
photo_comment GET /photos/:photo_id/comments/:id(.:format) {:action=>"show", :controller=>"comments"}
PUT /photos/:photo_id/comments/:id(.:format) {:action=>"update", :controller=>"comments"}
DELETE /photos/:photo_id/comments/:id(.:format) {:action=>"destroy", :controller=>"comments"}
update_states_photos GET /photos/update_states(.:format) {:action=>"update_states", :controller=>"photos"}
upload_photo /photos/:id/upload(.:format) {:action=>"upload", :controller=>"photos"}
photos GET /photos(.:format) {:action=>"index", :controller=>"photos"}
POST /photos(.:format) {:action=>"create", :controller=>"photos"}
new_photo GET /photos/new(.:format) {:action=>"new", :controller=>"photos"}
edit_photo GET /photos/:id/edit(.:format) {:action=>"edit", :controller=>"photos"}
photo GET /photos/:id(.:format) {:action=>"show", :controller=>"photos"}
PUT /photos/:id(.:format) {:action=>"update", :controller=>"photos"}
DELETE /photos/:id(.:format) {:action=>"destroy", :controller=>"photos"}
Unfortunately 'match' didn't work any better...
-- EDIT --
Just to confirm another scenario here... with this in the routes:
resources :photos do
resources :comments
collection do
get 'update_states'
end
member do
match 'upload'
end
end
and this in the view:
form_for @photo, :remote => true, :url => { :action => 'upload' }, :html => { :multipart => :true, :id => 'photo_upload' } do |f|
I still get:
No route matches {:action=>"upload", :controller=>"photos"}
What if you did just :url => upload_photo_path(@photo)
?
It seems a little strange that you'd be uploading to a member though. Is this just a creation method (in which case you should just POST to the collection path)?
I had the same problem and finally worked through to a solution which I'm not sure was reached in the above case, since the original poster moved on to another approach.
My routes had
resources :members do
member do
get "invite"
post 'register'
end
end
And "rake routes" included
register_member POST /members/:id/register(.:format) {:protocol=>"http", :action=>"register", :controller=>"members"}
Yet I kept getting the error
Started POST "/members/149/register" for 127.0.0.1 at 2012-04-13 13:18:35 -0700
ActionController::RoutingError (No route matches "/members/149/register"):
Rendered /Users/lisa/.rvm/gems/ruby-1.9.2-p180@stv/gems/actionpack-3.0.9/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (1.1ms)
and the problem was limited only to the form generated by Rails according to the below form_for (note I confirmed this using HTTP client to manually POST to the URL and saw it was finding the route)
<%= form_for @account, :url => register_member_path(@account.id) do |account_form| %>
...
I checked the method, I checked the path, everything looked good. What I finally noticed, scouring the generated form line by line:
<form accept-charset="UTF-8" action="/members/149/register" class="edit_member" id="edit_member_149" method="post">
<div style="margin:0;padding:0;display:inline">
<input name="utf8" type="hidden" value="✓" />
<input name="_method" type="hidden" value="put" />
<input name="authenticity_token" type="hidden" value="74pkMgRHfdowSfzjJGMILkAsivVNrJZ0iWYXRUgxyF0=" />
</div>
...
Notice the hidden input name="_method". I wish the fact that Rails was interpreting this as a PUT had shown up in the logs, that would have made my debugging a lot faster. I fixed it by telling the form explicitly to use the POST method, which of course it was already, but telling it that removed the hidden _method override. I assume there's some facet about @account which triggered Rails to use the _method parameter, but @account should be an existing record.
Your url
parameter should be
:url => { :action => "upload" }
(Original reply)
I would bet it's because your route expects a PUT
and your form is sending a POST
(probably because @photo = Photo.new
). You have several options:
post 'upload'
form_for @photo, :as => :post
with the rest of your arguments@photo
is an existing record (e.g. by calling create
instead of new
)The most appropriate choice is probably one of the first 2.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With