Weird routing error in Rails 3.0 - ruby-on-rails

I've been converting my Rails 2.3.9 application to Rails 3.0 and everything has been going well. I've created a lot of routes with the new system so I feel like I know how to do this. However, I recently got a routing error I can't solve.
I have a users resource defined like this:
resources :users do
member do
get 'activate'
get 'edit_password'
post 'update_password'
end
collection do
get 'forgot_password'
post 'send_reset_instructions'
end
end
The failing route is update_password. If I change it to a get method it works. But not when used as a post, with data coming from a form in "edit_password".
This is the error message:
Routing Error
No route matches "/users/31/update_password"
This is the (relevant) output of rake routes:
activate_user GET /users/:id/activate(.:format) {:action=>"activate", :controller=>"users"}
edit_password_user GET /users/:id/edit_password(.:format) {:action=>"edit_password", :controller=>"users"}
update_password_user POST /users/:id/update_password(.:format) {:action=>"update_password", :controller=>"users"}
forgot_password_users GET /users/forgot_password(.:format) {:action=>"forgot_password", :controller=>"users"}
send_reset_instructions_users POST /users/send_reset_instructions(.:format) {:action=>"send_reset_instructions", :controller=>"users"}
users GET /users(.:format) {:action=>"index", :controller=>"users"}
users POST /users(.:format) {:action=>"create", :controller=>"users"}
new_user GET /users/new(.:format) {:action=>"new", :controller=>"users"}
edit_user GET /users/:id/edit(.:format) {:action=>"edit", :controller=>"users"}
user GET /users/:id(.:format) {:action=>"show", :controller=>"users"}
user PUT /users/:id(.:format) {:action=>"update", :controller=>"users"}
user DELETE /users/:id(.:format) {:action=>"destroy", :controller=>"users"}
Finally, this is the output of the web server for that request (webrick):
Started POST "/users/31/update_password" for 127.0.0.1 at 2010-10-14 23:30:59 +0200
SQL (1.5ms) SELECT name
FROM sqlite_master
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
SQL (0.7ms) SELECT name
FROM sqlite_master
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
ActionController::RoutingError (No route matches "/users/31/update_password"):
Rendered /home/jonatan/.rvm/gems/ruby-1.9.2-p0/gems/actionpack-3.0.0/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (1.0ms)
Can you find any logic in this?
I'm using the latest Rails available through gem (3.0.1). At first I did override *to_param* in the User-model to use the username, but the problem is the same no matter what.
I've checked for misspellings in the update_password method of the model, and also made sure it is not private.

I have noticed this as well, only with the POST method and only when using "member", so same as your example, ie:
resources :forum_posts do
member do
post :preview
end
end
will trigger this, but changing it to GET or using collection both work fine, so seems to be a bug with rails routes; I get around this for now by adding the following just above my resources :forum_posts do line:
match '/forum_posts/:id/preview(.:format)', :to => "forum_posts#preview", :as => :preview_forum_post
then everything continues working; easy temporary fix.

Related

Scoped routes creating a routing issue

Im trying to learn to dry up my code a bit but have come across a issue,
Im scoping my routes with controller and path options
scope path: '/administrators', controller: :administrators do
get 'unverified' => :unverified
patch 'verify/:id' => :verify
get 'reported' => :reported
get 'ban_user' => :ban_user
patch 'execute_ban/:id' => :execute_ban
end
So this is what ive done so far, all the get links are working correctly...
but this is making the patch 'execute_ban/:id' => :execute_ban become a extension of ban user like this: (also the same with verify)
verified GET /administrators/unverified(.:format) administrators#unverifie
PATCH /administrators/verify/:id(.:format) administrators#verify
reported GET /administrators/reported(.:format) administrators#reported
ban_user GET /administrators/ban_user(.:format) administrators#ban_user
PATCH /administrators/execute_ban/:id(.:format) administrators#execute_ban
now ive changed my link_to route = link_to 'ban', ban_user_path(x.id), method: :patch
but its throwing an routing error saying no path matches.
Is there something im missing, any insight would aooreciated as always.
Thanks
Why not go for a more restful design that centers around the resource being modified?
Rails.application.routes.draw do
resources :users do
get :unverified, on: :collection
get :reported, on: :collection
get :ban
patch :ban, action: 'execute_ban'
end
end
You don't need different paths for the form and acting on a resource - use the HTTP verb instead.
Prefix Verb URI Pattern Controller#Action
unverified_users GET /users/unverified(.:format) users#unverified
reported_users GET /users/reported(.:format) users#reported
user_ban GET /users/:user_id/ban(.:format) users#ban
PATCH /users/:user_id/ban(.:format) users#execute_ban
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
If you are adding a separate controller just for authorization purposes it's an anti-pattern of sorts since you are just adding more complexity for something that should be handled by Pundit/CanCanCan.

pass no id, but only parameters with Rails path

With my settings, I have the following routes
users GET /users(.:format) {:action=>"index", :controller=>"users"}
POST /users(.:format) {:action=>"create", :controller=>"users"}
new_user GET /users/new(.:format) {:action=>"new", :controller=>"users"}
edit_user GET /users/:id/edit(.:format) {:action=>"edit", :controller=>"users"}
user GET /users/:id(.:format) {:action=>"show", :controller=>"users"}
PUT /users/:id(.:format) {:action=>"update", :controller=>"users"}
DELETE /users/:id(.:format) {:action=>"destroy", :controller=>"users"}
Now, in my corresponding index.html.haml view under app/views... etc, I have a link looking like this,
%th#name_header= link_to "List Names", user_path( ...
Now, I'd like to define that link, so that I can call the index action, that is, I come back to the same page, with different settings
The index action is mapped to users_path, not user_path - that's the show action and requires an :id parameter with this setup. To link to the index action with a format (e.g. javascript), use
users_path(:format => "js")
It seems you want to link to the users index page, so you have to use users_path (note plural):
= link_to "List Names", users_path
You can then of course pass users_path any of the parameters you'd like.

Rails - From RESTFul resource to customized routes

This is a design problem that I am trying to figure out. I will explain what I have right now, and what I would like to have:
1. Actual design
I have a defined a resources :users and by doing so I have defined different actions such as new, create and update in the Users controller. This is working as expected by following urls like users/new , users/:id, etc...
Now I want to go one step forward, and I want to be able to do the following...
2. What am I looking for
I want to be able to have a route like this:
users/overview/profile - This should be equivalent to `users/:id` (show action)
users/overview/network - This should be equivalent to users/:id/network (list of networks for that user)
3. My idea
My first idea was to define something like this:
resource :users do
namespace :overview do
resource :networks
end
end
But this would work for urls like: users/:id/overview/networks and I don't want the user id to be shown in the URL. So my questions are:
1 - How can I deal with users/overview/networks instead of users/:id/overview/networks , assuming that I can get the user id from session.
2 - How can I be able to manage URLs like this: users/overview/profile where actually a profile is just the show method of users/:id Right now I have defined all the actions in the users controller and everything is working fine (new,delete,create,update...) I just don't know how to move into that "namespace" overview/profile
I have tried same thing you tried, and it is returning your desired results only, not sure what is your problem. Posting rake routes result here.
users_overview_networks POST /users/overview/networks(.:format) {:action=>"create", :controller=>"overview/networks"}
new_users_overview_networks GET /users/overview/networks/new(.:format) {:action=>"new", :controller=>"overview/networks"}
edit_users_overview_networks GET /users/overview/networks/edit(.:format) {:action=>"edit", :controller=>"overview/networks"}
GET /users/overview/networks(.:format) {:action=>"show", :controller=>"overview/networks"}
PUT /users/overview/networks(.:format) {:action=>"update", :controller=>"overview/networks"}
DELETE /users/overview/networks(.:format) {:action=>"destroy", :controller=>"overview/networks"}
users POST /users(.:format) {:action=>"create", :controller=>"users"}
new_users GET /users/new(.:format) {:action=>"new", :controller=>"users"}
edit_users GET /users/edit(.:format) {:action=>"edit", :controller=>"users"}
GET /users(.:format) {:action=>"show", :controller=>"users"}
PUT /users(.:format) {:action=>"update", :controller=>"users"}
DELETE /users(.:format) {:action=>"destroy", :controller=>"users"}
scope :path => 'users/overview' do
match ':id/profile', :to => 'users#show'
match ':id/network', :to => 'users#network'
end

difference between resource and controller generators

when I do
rails g model user name:string
rails g controller users index create new destroy show
and edit config/routes.rb to add:
resource :users
bundle exec rake routes gives:
users POST /users(.:format) {:action=>"create", :controller=>"users"}
new_users GET /users/new(.:format) {:action=>"new", :controller=>"users"}
edit_users GET /users/edit(.:format) {:action=>"edit", :controller=>"users"}
GET /users(.:format) {:action=>"show", :controller=>"users"}
PUT /users(.:format) {:action=>"update", :controller=>"users"}
DELETE /users(.:format) {:action=>"destroy", :controller=>"users"}
however, when I do
rails g resource users name:string
(which automatically adds resources :users to config/routes.rb)
bundle exec rake routes
I get
users GET /users(.:format) {:action=>"index", :controller=>"users"}
POST /users(.:format) {:action=>"create", :controller=>"users"}
new_user GET /users/new(.:format) {:action=>"new", :controller=>"users"}
edit_user GET /users/:id/edit(.:format) {:action=>"edit", :controller=>"users"}
user GET /users/:id(.:format) {:action=>"show", :controller=>"users"}
PUT /users/:id(.:format) {:action=>"update", :controller=>"users"}
DELETE /users/:id(.:format) {:action=>"destroy", :controller=>"users"}
So my question is,
when I generate a controller how can I get the correct helper methods to make
link_to 'Destroy', instance, :method=> :delete
work?
Because currently it gives an error user_path is not defined.
You should call
rails g controller user index create new destroy show
instead of
rails g controller users index create new destroy show
in order to get resources :users to give you the helpers you want.
The latter causes Rails to assume that users is a singular object, and that resources :users should create what is called a singular resource:
http://guides.rubyonrails.org/routing.html#singular-resources
as a result, user_path is undefined, whereas users_path is defined.
When you use rails g controller and specify the method names, the generator only maps specific routes to the routes file. rails g resource assumes that you want the whole resource functionality and will map resources.
In order to fix this, just go into your routes file and replace the specific mappings with a resources call.
resources :users
What I really wanted was a way of creating a working (with correct delete/show paths) controller for an existing model (as described in the question) but just adding "resource :x" and generating the controller wasn't enough.
I ended up using the scaffold_controller generator. It doesn't create any migrations or models, but it does generate a resource with views and rake paths command shows the correct paths for delete and show to work.
You can run following commands in the console:
$rails g model user name:string
$rails g scaffold_controller User
And add this code line to the file routes.rb:
resources :users

Routing redirection

I am using Ruby on Rails 3 and I would like to redirect all requests made to a resource (URL) to another resource.
I have the following resources:
<My_app_name>::Application.routes.draw do
resources :users
namespace :users do
resources :user_admins
end
end
What I would like to do is to redirect all requests made to <my_app_name>/users/user_admins/<id> to <my_web_site_name>/users/<id>. How can I do that?
Note: I am using a Single Table Inheritance approach, so that the <id> value will don't change behaviours. That is, the <id> value will be automatically handled from the RoR framework and it will refer to the same resource for both when the URL is <my_app_name>/users/user_admins/<id> or <my_web_site_name>/users/<id>.
You may want to avoid the use of a namespace, and play it like that :
scope "users" do
resources "user_admins", :controller => "users"
end
You'll get those routes :
user_admins GET /users/user_admins(.:format) {:action=>"index", :controller=>"users"}
POST /users/user_admins(.:format) {:action=>"create", :controller=>"users"}
new_user_admin GET /users/user_admins/new(.:format) {:action=>"new", :controller=>"users"}
edit_user_admin GET /users/user_admins/:id/edit(.:format) {:action=>"edit", :controller=>"users"}
user_admin GET /users/user_admins/:id(.:format) {:action=>"show", :controller=>"users"}
PUT /users/user_admins/:id(.:format) {:action=>"update", :controller=>"users"}
DELETE /users/user_admins/:id(.:format) {:action=>"destroy", :controller=>"users"}
Try this in your routes.rb:
match 'users/user_admins/:id' => 'users#show'

Resources