ruby-on-railsnamed-routing

How do I create a resource that is the sub-set of an existing resource


In my "routes.rb" file I have the following line:

resource :users

which gives me a bunch of named routes for accessing my User model in a RESTful manner.

Now, I've made some additions to the User model including creating a special class of user. These are still stored in the User model but there is a "special" flag in the database that identifies them as special.

So, is it possible to create special_users resource? For example, I'd like to have a "special_users_path" as a named route to "/special_users" which will return an index of only the special users when you perform a GET on the URL.

Is there a way to do this?


Solution

  • In Rails routing, a 'resource' refers to the standard 7 routes that are created for RESTful resources: index, show, new, create, edit, update and destroy. Normally that is enough, but sometimes you might want to create another action.

    In the model, you want to create a scope that only returns special users:

    class User < ActiveRecord::Base
      scope :special, where(:special => true)
    end
    

    On the controller side, there are two ways to go about this. What you are suggesting is the creation of an additional action:

    match "/users/special" => "users#special"  
    resource :users
    

    In the controller, your special action would return the scope you just created:

    class UsersController < ApplicationController
      def special
        @users = User.special
      end
    end
    

    That will do what you ask, but I would suggest NOT doing it this way. What if you add other flags later that you want to search by? What if you want to search by multiple flags? This solution isn't flexible enough for that. Instead, keep the routes the way they are:

    resource :users
    

    and just add an additional line to your controller:

    class UsersController < ApplicationController
      def index
        @users = User.all
        @users = @users.special if params[:special]
      end
    end
    

    and now, when you want to display special users, simply direct the user to /users?special=true

    This approach is much more future-proof, IMO.

    (This answer is assuming Rails-3. If you're still using 2.3 let me know)