views:

788

answers:

3

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?

+1  A: 

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.

Damien MATHIEU
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?
macek
A: 

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
@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 :)
macek
+8  A: 

Syntax you are using is for adding prefix to the default URL generated by Rails. It looks like that is not what you want.

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 in `users` table called `confirmation_code`
    if User.find_by_confirmation_code(params[id])
      # success
    else
      # error
    end
  end
end
KandadaBoggu
@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?
macek
Updated my answer, take a look.
KandadaBoggu
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)`?
macek
@KandadaBoggu, just a note: StackOverflow says I can issue the bounty in 4 hours :)
macek
Yes you have to use `confirm_user_path(:id => @user.confirmation_code)`, I will update the answer.
KandadaBoggu
@KandadaBoggu, elegance as always. I will issue the bounty as soon as SO lets me :)
macek