23

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?

maček
  • 76,434
  • 37
  • 167
  • 198

4 Answers4

62

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
Harish Shetty
  • 64,083
  • 21
  • 152
  • 198
  • @KandadaBoggu, this explanation look great. As a follow-up to check for my understanding, say I wanted to send an "account confirmation" link in the user's welcome email. That link would contain an 8-character validation hash. Would I add `map.resources :users, :member => {:validate => :get}`? How does the `hash` param get plugged in? – maček Apr 20 '10 at 17:25
  • Updated my answer, take a look. – Harish Shetty Apr 20 '10 at 19:18
  • What's telling `confirm_user_path` to use `@user.confirmation_code` in place of the `:id` wildcard instead of `@user.foo` or `@user.bar`? Should this be `confirm_user_path(:id => @user.confirmation_code)`? – maček Apr 20 '10 at 20:50
  • @KandadaBoggu, just a note: StackOverflow says I can issue the bounty in 4 hours :) – maček Apr 20 '10 at 21:21
  • Yes you have to use `confirm_user_path(:id => @user.confirmation_code)`, I will update the answer. – Harish Shetty Apr 20 '10 at 23:30
  • @KandadaBoggu, elegance as always. I will issue the bounty as soon as SO lets me :) – maček Apr 21 '10 at 01:09
12

This can be taken as just another syntax -- something good to know may be.

Syntax 1:

resources :users do
  member do
    get 'signup'
    post 'register'
  end
end

Rake Route Output will include

signup_users GET    /users/signup(.:format)    {:action=>"signup", :controller=>"users"}
register_users POST   /users/register(.:format)  {:action=>"register", :controller=>"use

rs"}

Syntax 2: If you have only one collection route

resources :users do
    get 'signup', :on => :collection
end
prashantsunkari
  • 959
  • 7
  • 21
3

If i'm understanding your question right, you just want to rename the urls of the new and create actions.

This would be done like so:

map.resources :users, :path_names => {:new => 'signup', :create => 'register'}

If you really would like to add new routes with corresponding controller actions, then Damiens answer is the way to go.

mikezter
  • 2,393
  • 1
  • 17
  • 24
  • @mikezter, I definitely still need the `new` and `create` routes. However, this answers I question about *renaming* routes I've had in the past. Thanks :) – maček Apr 14 '10 at 14:19
1

The new option allows you to create new routes for creating new objects. That's why they're prefixed with that term.

What you're looking for is the :collection option.

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

Which will create the /users/signup and /users/register urls.

John Topley
  • 113,588
  • 46
  • 195
  • 237
Damien MATHIEU
  • 31,924
  • 13
  • 86
  • 94
  • I had trouble understand what `collection` was intended for. The route **is** for creating new objects; visitors that sign-up create a new `User` object. So, why wouldn't I want to use `new`? Is this a typo in the Rails Guide? – maček Apr 14 '10 at 14:17