KrNel
KrNel

Reputation: 434

Rails routes, problem with custom :action not being recognized, always 'show'

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) 

Upvotes: 0

Views: 7808

Answers (4)

Abraham
Abraham

Reputation: 331

I know it is super late and 2020 but if you by accident duplicate the routes in routes.rb it will give you this weird situation. For example: #routes.rb

resources :users
...(bunch of other routes declaration later)
resources users do
 collection do
   get :manage
end

This will cause that when you try to access GET /users/manage it will go to the :show action. I saw in the screenshot you posted that you have the /users routes listed twice. That's an indicator. Find the simple resources :users and delete it and leave the one that has more stuff in it since it's the version you need.

Upvotes: 0

Sartaj Singh Sisodiya
Sartaj Singh Sisodiya

Reputation: 1143

You can add routes like below for other GET type actions of a controller -

resources :users do
    collection do
      get 'manage'
    end
end

Upvotes: 3

dombesz
dombesz

Reputation: 7909

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

Upvotes: 0

Max Chernyak
Max Chernyak

Reputation: 37375

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.

Upvotes: 6

Related Questions