custom route no routes match - ruby-on-rails

During cucumber tests, I get the following error:
No route matches "/companies/29/update_owner"
I am not sure what I am doing wrong, but im sure its something stupid.
I have the following routes:
company_update_owner POST /companies/:company_id/update_owner(.:format) {:controller=>"companies", :action=>"update_owner"}
company_set_owner /companies/:company_id/set_owner(.:format) {:controller=>"companies", :action=>"set_owner"}
companies GET /companies(.:format) {:action=>"index", :controller=>"companies"}
POST /companies(.:format) {:action=>"create", :controller=>"companies"}
new_company GET /companies/new(.:format) {:action=>"new", :controller=>"companies"}
edit_company GET /companies/:id/edit(.:format) {:action=>"edit", :controller=>"companies"}
company GET /companies/:id(.:format) {:action=>"show", :controller=>"companies"}
PUT /companies/:id(.:format) {:action=>"update", :controller=>"companies"}
DELETE /companies/:id(.:format) {:action=>"destroy", :controller=>"companies"}
I have tried:
company_update_owner_path(:company_id => #company.id)
and
company_update_owner_path(#company)
update:
= form_for #company, :url => company_update_owner_path(:company_id => #company.id), :method => :put do |f|
Any help would be greatly appreciated.
Here is the code in routes.rb:
resources :companies do
match '/update_owner' => 'companies#update_owner', :as => :update_owner, :via => :post
match '/set_owner' => 'companies#set_owner', :as => :set_owner
end

you need to remove the ":method=>:put"

Your route is declared as a POST but you're doing a PUT in the form. Fix either the route or the form and you'll nail it.

Would leave this as a comment, but the fromatting gets jacked.
If you're not aware, you can also define those routes slightly differently, too:
resources :companies do
member do
post "update_owner"
get "set_owner"
end
end

Related

Sophisticated route and url generation in Rails

I have a group model which has_many article model. And I want to use the following url pattern "{group_id}/{article_id}".
so I wrote these route codes:
resource :groups do
resource :articles
end
match ':group_id/:id(.:format)', :to => 'articles#show', :as => :article
match ':id', :to => 'groups#show', :as => :group
But rails fail to generate correct url for group records and article records. How can I replace the automatic generated article_path and group_path to match my routes?
You're running into problems because you aren't watching out for pluralization. When you define a singular resource route, Rails doesn't treat it as a collection where you would refer to each member with an id. You instead want a plural resources for both groups and articles:
resources :groups do
resources :articles
end
Generates the following routes:
group_articles GET /groups/:group_id/articles(.:format) {:action=>"index", :controller=>"articles"}
POST /groups/:group_id/articles(.:format) {:action=>"create", :controller=>"articles"}
new_group_article GET /groups/:group_id/articles/new(.:format) {:action=>"new", :controller=>"articles"}
edit_group_article GET /groups/:group_id/articles/:id/edit(.:format) {:action=>"edit", :controller=>"articles"}
group_article GET /groups/:group_id/articles/:id(.:format) {:action=>"show", :controller=>"articles"}
PUT /groups/:group_id/articles/:id(.:format) {:action=>"update", :controller=>"articles"}
DELETE /groups/:group_id/articles/:id(.:format) {:action=>"destroy", :controller=>"articles"}
groups GET /groups(.:format) {:action=>"index", :controller=>"groups"}
POST /groups(.:format) {:action=>"create", :controller=>"groups"}
new_group GET /groups/new(.:format) {:action=>"new", :controller=>"groups"}
edit_group GET /groups/:id/edit(.:format) {:action=>"edit", :controller=>"groups"}
group GET /groups/:id(.:format) {:action=>"show", :controller=>"groups"}
PUT /groups/:id(.:format) {:action=>"update", :controller=>"groups"}
DELETE /groups/:id(.:format) {:action=>"destroy", :controller=>"groups"}
If you want to leave off the groups and articles segments you can pass :path => '' to each of the resources definitions, but you are going to have to tread carefully because any request to http://example.com/1/2 will map to an article under groups and be uninformative to end users and bots alike.

Rails 3 Form For Custom Action

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:
Change your route to post 'upload'
Create your form with form_for #photo, :as => :post with the rest of your arguments
Make sure #photo is an existing record (e.g. by calling create instead of new)
The most appropriate choice is probably one of the first 2.

Rails Functional test on a custom route

I have the following routes in my app:
GET /admin/comments(.:format) {:controller=>"admin/comments", :action=>"index"}
admin_comments POST /admin/comments(.:format) {:controller=>"admin/comments", :action=>"create"}
new_admin_comment GET /admin/comments/new(.:format) {:controller=>"admin/comments", :action=>"new"}
GET /admin/comments/:id(.:format) {:controller=>"admin/comments", :action=>"show"}
PUT /admin/comments/:id(.:format) {:controller=>"admin/comments", :action=>"update"}
admin_comment DELETE /admin/comments/:id(.:format) {:controller=>"admin/comments", :action=>"destroy"}
edit_admin_comment GET /admin/comments/:id/edit(.:format) {:controller=>"admin/comments", :action=>"edit"}
admin_approve_comment /admin/comments/approve/:id {:module=>"admin", :controller=>"admin/comments", :action=>"approve"}
admin_reject_comment /admin/comments/reject/:id {:module=>"admin", :controller=>"admin/comments", :action=>"reject"}
which is declared as:
namespace "admin" do
resources :comments
match '/comments/approve/:id' => 'comments#approve', :as => "approve_comment", :module => "admin"
match '/comments/reject/:id' => 'comments#reject', :as => "reject_comment", :module => "admin"
end
and a functional test like this:
context "a POST to :approve" do
setup do
comment = Factory(:comment)
sign_in Factory(:admin)
post :approve, :id => comment.id
end
should respond_with :success
end
However, when I run this I get:
test: a POST to :approve should respond with 200. (Admin::CommentsControllerTest):
ActionController::RoutingError: No route matches {:action=>"approve", :id=>339, :controller=>"admin/comments"}
What's wrong here? What stupid mistake am I making?
These routes look like member routes to me. So routing this way
namespace "admin" do
resources :comments do
member do
get :approve
get :reject
end
end
end
This will generate routes like /admin/comments/:id/approve . This is the rails way as far i know.
I think it's better to put match before resources. Because it's not check if it's good or not.

Nested routes in Rails with an alias

I have a primary model for my project, Place.rb with a places_controller, and I've currently got it exactly the way I want for the users end of my project. With a nested photos controller, review, etc.
I want now to create a management resource which is mostly just an alias for Places, with its own nested resources, some of them overlapping, some of them new.
I tried creating a new controller for it called Manage, but I'm having a hard time with routes. I'm not quite sure the hangup is, but I figure I'm doing something very wrong. I had little difficulty when I was using Places as controller to a real model and nesting other resources below it.
But for example trying to create a new record for a nested resource doesn't route correctly.
I can get a route path like new_manage_room_path(#place) for a link_to to work fine. But
for creating a New announcement in a form:
form_for manage_room_path(#place) doesn't work correctly given a valid id. I've tried many other combinations supplying the object and :url.
Should I avoid using a separate controller and just create an alias or what is the special routing for this purpose?
map.resources :manage, :collection => { :upcoming => [ :post, :get ], :pending => [ :post, :get ] } do |manage|
manage.resources :rooms
manage.resources :room_rates, :as => :rates
manage.resources :availables
manage.resources :manage_bookings, :as => :bookings
end
map.resources :places do |place|
place.resources :bookings
place.resources :photos, :collection => { :sort => :post }
place.resources :reviews, :only => [ :index, :show ]
end
manage_rooms GET /manage/:manage_id/rooms(.:format) {:controller=>"rooms", :action=>"index"}
POST /manage/:manage_id/rooms(.:format) {:controller=>"rooms", :action=>"create"}
new_manage_room GET /manage/:manage_id/rooms/new(.:format) {:controller=>"rooms", :action=>"new"}
edit_manage_room GET /manage/:manage_id/rooms/:id/edit(.:format) {:controller=>"rooms", :action=>"edit"}
manage_room GET /manage/:manage_id/rooms/:id(.:format) {:controller=>"rooms", :action=>"show"}
PUT /manage/:manage_id/rooms/:id(.:format) {:controller=>"rooms", :action=>"update"}
DELETE /manage/:manage_id/rooms/:id(.:format) {:controller=>"rooms", :action=>"destroy"}
manage_room_rates GET /manage/:manage_id/rates(.:format) {:controller=>"room_rates", :action=>"index"}
POST /manage/:manage_id/rates(.:format) {:controller=>"room_rates", :action=>"create"}
new_manage_room_rate GET /manage/:manage_id/rates/new(.:format) {:controller=>"room_rates", :action=>"new"}
edit_manage_room_rate GET /manage/:manage_id/rates/:id/edit(.:format) {:controller=>"room_rates", :action=>"edit"}
manage_room_rate GET /manage/:manage_id/rates/:id(.:format) {:controller=>"room_rates", :action=>"show"}
PUT /manage/:manage_id/rates/:id(.:format) {:controller=>"room_rates", :action=>"update"}
DELETE /manage/:manage_id/rates/:id(.:format) {:controller=>"room_rates", :action=>"destroy"}
manage_availables GET /manage/:manage_id/availables(.:format) {:controller=>"availables", :action=>"index"}
POST /manage/:manage_id/availables(.:format) {:controller=>"availables", :action=>"create"}
new_manage_available GET /manage/:manage_id/availables/new(.:format) {:controller=>"availables", :action=>"new"}
edit_manage_available GET /manage/:manage_id/availables/:id/edit(.:format) {:controller=>"availables", :action=>"edit"}
manage_available GET /manage/:manage_id/availables/:id(.:format) {:controller=>"availables", :action=>"show"}
PUT /manage/:manage_id/availables/:id(.:format) {:controller=>"availables", :action=>"update"}
DELETE /manage/:manage_id/availables/:id(.:format) {:controller=>"availables", :action=>"destroy"}
manage_manage_bookings GET /manage/:manage_id/bookings(.:format) {:controller=>"manage_bookings", :action=>"index"}
POST /manage/:manage_id/bookings(.:format) {:controller=>"manage_bookings", :action=>"create"}
new_manage_manage_booking GET /manage/:manage_id/bookings/new(.:format) {:controller=>"manage_bookings", :action=>"new"}
edit_manage_manage_booking GET /manage/:manage_id/bookings/:id/edit(.:format) {:controller=>"manage_bookings", :action=>"edit"}
manage_manage_booking GET /manage/:manage_id/bookings/:id(.:format) {:controller=>"manage_bookings", :action=>"show"}
PUT /manage/:manage_id/bookings/:id(.:format) {:controller=>"manage_bookings", :action=>"update"}
DELETE /manage/:manage_id/bookings/:id(.:format) {:controller=>"manage_bookings", :action=>"destroy"}
pending_manage POST /manage/pending(.:format) {:controller=>"manage", :action=>"pending"}
GET /manage/pending(.:format) {:controller=>"manage", :action=>"pending"}
upcoming_manage POST /manage/upcoming(.:format) {:controller=>"manage", :action=>"upcoming"}
GET /manage/upcoming(.:format) {:controller=>"manage", :action=>"upcoming"}
manage_index GET /manage(.:format) {:controller=>"manage", :action=>"index"}
POST /manage(.:format) {:controller=>"manage", :action=>"create"}
new_manage GET /manage/new(.:format) {:controller=>"manage", :action=>"new"}
edit_manage GET /manage/:id/edit(.:format) {:controller=>"manage", :action=>"edit"}
manage GET /manage/:id(.:format) {:controller=>"manage", :action=>"show"}
PUT /manage/:id(.:format) {:controller=>"manage", :action=>"update"}
DELETE /manage/:id(.:format) {:controller=>"manage", :action=>"destroy"}
Try:
<% form_for #new_room, :url => manage_rooms_path(#place) do |f| %>
or maybe it will work this way:
<% form_for manage_rooms_path(#place, #new_room) do |f| %>
#new_room is new instance of Room model, so in controller add:
#new_room = Room.new

Nested routing

How do I write a route that maps a path like this?
/powerusers/bob/article-title
This is what I got so far:
map.resources :users, :as => "powerusers" do |users|
users.resources :articles, :as => ''
end
This gives me the following route:
/powerusers/:user_id//:id
How do I get rid of the double backslah? /powerusers/admin//first-article?
Best regards.
Asbjørn Morell
Ok, if you don't want the intermediate nested resource (/articles) I wouldn't use the map.resources at all.
Try:
map.connect '/powerusers/:user_id/:article_title', :controller => 'articles', :action => 'view_by_title'
If I add...
map.resources :users, :as => "powerusers" do |users|
users.resources :entries, :as => 'article-title'
end
I get the routes below, which include the one you want...
(Substitute "articles" for "entries" for your situation.)
GET /powerusers(.:format) {:controller=>"users", :action=>"index"}
POST /powerusers(.:format) {:controller=>"users", :action=>"create"}
GET /powerusers/new(.:format) {:controller=>"users", :action=>"new"}
GET /powerusers/:id/edit(.:format) {:controller=>"users", :action=>"edit"}
GET /powerusers/:id(.:format) {:controller=>"users", :action=>"show"}
PUT /powerusers/:id(.:format) {:controller=>"users", :action=>"update"}
DELETE /powerusers/:id(.:format) {:controller=>"users", :action=>"destroy"}
user_entries GET /powerusers/:user_id/article-title(.:format) {:controller=>"entries", :action=>"index"}
POST /powerusers/:user_id/article-title(.:format) {:controller=>"entries", :action=>"create"}
new_user_entry GET /powerusers/:user_id/article-title/new(.:format) {:controller=>"entries", :action=>"new"}
edit_user_entry GET /powerusers/:user_id/article-title/:id/edit(.:format) {:controller=>"entries", :action=>"edit"}
user_entry GET /powerusers/:user_id/article-title/:id(.:format) {:controller=>"entries", :action=>"show"}
PUT /powerusers/:user_id/article-title/:id(.:format) {:controller=>"entries", :action=>"update"}
DELETE /powerusers/:user_id/article-title/:id(.:format) {:controller=>"entries", :action=>"destroy"}
Instead of nesting, would this work?
map.resources :users, :as => "powerusers"
map.resources :articles, :path_prefix => '/powerusers/:user_id'
I think it won't but a quick test would tell better :)

Resources