maček maček - 1 month ago 4
reST (reStructuredText) Question

How to add a custom RESTful route to a Rails app?

I'm reading these two pages


  1. resources

  2. Adding more RESTful actions



The Rails Guides page shows

map.resources :photos, :new => { :upload => :post }


And its corresponding URL

/photos/upload


This looks wonderful.




My
routes.rb
shows this

map.resources :users, :new => { :signup => :get, :register => :post }


When I do:
[~/my_app]$ rake routes


I see the two new routes added

signup_new_user GET /users/new/signup(.:format)
register_new_user POST /users/new/register(.:format)


Note the inclusion of
/new
! I don't want that. I just want
/users/signup
and
/users/register
(as described in the Rails Routing Guide).

Any help?

Answer

When you expose a controller as a resource, following actions are automatically added:

show
index
new
create
edit
update
destroy

These actions can be categorized in to two groups:

  • :member actions

The URL for the member action has the id of the target resource. E.g:

users/1/edit 
users/1

You can think of :member action as an instance method on a class. It always applies on an existing resource.

Default member actions: show, edit, update, destroy

  • :collection actions

The URL for the :collection action does not contain the id of the target resource. E.g:

users/login
users/register

You can think of :collection action as a static method on a class.

Default collection actions: index, new, create

In your case you need two new actions for registration. These actions belong to :collection type( as you do not have the id of the user while submitting these actions). Your route can be as follows:

map.resources :users, :collection => { :signup => :get, :register => :post }

The URL for the actions are as follows:

users/signup
users/register

If you want to remove a standard action generated by Rails use :except/:only options:

map.resources :foo, :only => :show

map.resources :foo, :except => [:destroy, :show]

Edit 1

I usually treat the confirmation action as a :member action. In this case params[id] will contain the confirmation code.

Route configuration:

map.resources :users, :member => { :confirm => :get}

URL

/users/xab3454a/confirm

confirm_user_path(:id => @user.confirmation_code) # returns the URL above

Controller

class UsersController < ApplicationController
  def confirm
    # assuming you have an attribute called `confirmation_code` in `users` table 
    # and you have added a uniq index on the column!!
    if User.find_by_confirmation_code(params[id])
      # success
    else
      # error
    end
  end
end