views:

42

answers:

2

Hello,

I'm trying to 'manage' users, instead of 'new' and 'show' users via actions. The problem is somewhere in routes I suspect, as my link '/users/manage' is being received as an id parameter to 'show' action:

Terminal log of process:

Processing UsersController#show (for 127.0.0.1 at 2010-06-28 00:31:45) [GET]
  Parameters: {"id"=>"manage"}

ActionController::UnknownAction (No action responded to show. Actions: create, destroy, index, manage, and update):

Here are some code snippets of relevant parts:

users/index.html.erb (the link created to go to the manage section, i.e. '/users/manage'):

<%= link_to('New User', :action => 'manage') %>

users_controller.rb (supposed to be receiving 'manage' action, but gets 'show' fr om above call:

def index
    @users = User.all

    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @users }
    end
  end

  def manage
      @users = User.all
      @user = User.find(params[:id]) if params[:id]
    @user = User.new if @user.nil?

    respond_to do |format|
      format.html # new.html.erb
      format.xml  { render :xml => @user }
    end
  end

Ruby/rails sees '/users/manage' as a ':controller/:action/:id' i.e. 'users/show/1'.

When using '/users/manage/1' to edit a single user, the proper :action (as 'manage') is loaded via the UsersController 'manage' function, and everything is displayed to edit from the manage.html.erb file. UsersController sees 'manage' and not 'show', correctly, int his case, but only because of the :id being passed making the ':controller/:action/:id' route kick in and work.

'users/manage', :controller/:action seems to be the problem, not recognizing 'manage' as a valid :action alone, instead sending is as an :id in 'show'...

routes.rb:

ActionController::Routing::Routes.draw do |map|
  map.resources :users
  map.resources :categories
  map.resources :posts
  map.connect ':controller/:action'
  map.connect ':controller/:action/:id'
  map.connect ':controller/:action/:id.:format'
end

Can someone please help me resolve this?

Why is the 'show' action being automatically undertaken? Can I force 'users' and 'manage' in routes to be recognized in the controller as 'manage' and not as 'show'?

Thanks for the help people :)

Peace.

EDIT rake routes

$ rake routes
(in /home/krnel/sites/rails_projects/simple_blog)
        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"}
   categories GET    /categories(.:format)              {:action=>"index", :controller=>"categories"}
              POST   /categories(.:format)              {:action=>"create", :controller=>"categories"}
 new_category GET    /categories/new(.:format)          {:action=>"new", :controller=>"categories"}
edit_category GET    /categories/:id/edit(.:format)     {:action=>"edit", :controller=>"categories"}
     category GET    /categories/:id(.:format)          {:action=>"show", :controller=>"categories"}
              PUT    /categories/:id(.:format)          {:action=>"update", :controller=>"categories"}
              DELETE /categories/:id(.:format)          {:action=>"destroy", :controller=>"categories"}
        posts GET    /posts(.:format)                   {:action=>"index", :controller=>"posts"}
              POST   /posts(.:format)                   {:action=>"create", :controller=>"posts"}
     new_post GET    /posts/new(.:format)               {:action=>"new", :controller=>"posts"}
    edit_post GET    /posts/:id/edit(.:format)          {:action=>"edit", :controller=>"posts"}
         post GET    /posts/:id(.:format)               {:action=>"show", :controller=>"posts"}
              PUT    /posts/:id(.:format)               {:action=>"update", :controller=>"posts"}
              DELETE /posts/:id(.:format)               {:action=>"destroy", :controller=>"posts"}
 manage_users GET    /users/manage(.:format)            {:action=>"manage", :controller=>"users"}
              GET    /users(.:format)                   {:action=>"index", :controller=>"users"}
              POST   /users(.:format)                   {:action=>"create", :controller=>"users"}
              GET    /users/new(.:format)               {:action=>"new", :controller=>"users"}
              GET    /users/:id/edit(.:format)          {:action=>"edit", :controller=>"users"}
              GET    /users/:id(.:format)               {:action=>"show", :controller=>"users"}
              PUT    /users/:id(.:format)               {:action=>"update", :controller=>"users"}
              DELETE /users/:id(.:format)               {:action=>"destroy", :controller=>"users"}
                     /:controller/:action/:id           
                     /:controller/:action/:id(.:format) 
+1  A: 

You're never actually mapping a 'manage' action specifically. You are however mapping /users, /users/:id, /users/:id/edit and some more (post, put, delete) routes by doing map.resources :users. Check your rake routes to find out what exactly you've mapped.

As per your question, in your case you can add a route to user resources as follows:

map.resources :users, :collection => {:manage => :get}

This will add /users/manage GET route for your action. You can add :member(s) or :collection(s) this way. The difference is that member will be expecting an :id to be provided, while collection won't.

Read more in the rails routing guide: http://guides.rubyonrails.org/routing.html

The right way

What you probably want to do is create an Admin namespace for managing users. Then your users will be accessible through /admin/users, /admin/users/:id, /admin/users/:id/edit, etc. This way you can separate the interface in which you're managing the users from the one where users are editing their own profiles. This is a better practice, because this way you don't need to come up with custom routes like /users/manage. It will provide a CRUD area for administration, unrelated to CRUD area for users themselves.

hakunin
Thanks for quick replay :)Added **map.resources :users, :collection => {:manage => :get}** to routes.rb, I still get same problem as above.
KrNel
Edited post, added rake routes if that helps pinpoint the problem. Thx.
KrNel
make sure your `map.resources :users, :collection => {:manage => :get}` comes before any other users route declaration.
BaroqueBobcat
In your code it looks like you're trying to find user by `params[:id]` inside your `manage` action. This means, you're expecting a route like /users/:id/manage, and for that you need to use `:member => {:manage => :get}` instead of `:collection =>`.
hakunin
Appreciate the namespace solution, definetly, better. But, how can I get this to work this way? **Do these three routes conflict?**/users/:id(.:format) {:action=>"show"/users/manage(.:format) {:action=>"manage"/users/:id(.:format) {:action=>"show"
KrNel
You probably have duplicate routes because you placed both `map.resources :users` and `map.resources :users, :member => {:manage => :get}` in there. Remove the former. Speaking of namespace, I suggest reading the guide I mentioned. It's very clear and to the point. Basically, it involves using `Admin::UsersController` as your controller class, and adding `namespace :admin` block to your routes. Read up. :)
hakunin
Solution: as hakunin suggested, place the new map.resources for the collection of manage as a GET before the other resources.
KrNel
Another thing: **link_to('Destroy User', {:action => 'manage', :id => @user}** is being made as **'/users/manage?id=1'**. I have to fix routes again right? This time to show **:controller/:action/:id -> /users/manage/1** correct?
KrNel
Can I add **GET /users/manage/:id {:action=>"manage", :controller=>"users"}** ? I added it, but I cant add the HTTP var GET in there, so now it doesnt respond to anything...
KrNel
Looks like you're definitely looking for complete CRUD functionality under 'manage' namespace. You should use namespaces for this.
hakunin
Yes I know, thanks again. I'm learning, so I want to know how to fix things even if its the wrong way ;). Not for real project. Thanks ;)Solution is to add the 'member' like you said earlier for :id, and in the link_to add the new path manage_user_path(:id => user), instead of the :action and :id. Definitely go for the name-space, but I want to know how to do it this way to learn. Thanks hakunin.
KrNel
A: 

If you want to rename your routes, use :path_names hash in your routes like this.

map.resources :photos, :path_names => { :new  => 'make', :edit  => 'change' } 

This would cause the routing to recognize URLs such as

/photos/make
/photos/1/change 

The actual action names aren’t changed by this option; the two URLs shown would still route to the new and edit actions.

See this guide for more info: http://guides.rubyonrails.org/routing.html

dombesz