Routing Problem????

I started out with a normal scaffold for the USERS table. I changed
the index view to be list.html.erb but the url: '/users/list' returns
an 'unknown action' error. '/users/list/:id' also returns an 'unknown
action' error. I've also merged both the edit and new views into the
manage.html.erb which duplicates the list view except with a form on
the right side. the url '/users/manage' returns an 'unknown action'
error but '/users/manage/:id' brings me to the manage page with the
edit form.

in my routes.rb, it reads:
map.resources :users

The update an delete actions work but they don't route me to the right
url. the new action does not work. can anyone help? I've pasted my
controller and views below.

USERS CONTOLLER
class UsersController < ApplicationController

  layout 'staff'

  def index
    list
    render :action => 'list'
  end

  # GET /users
  # GET /users.xml
  def list
    @users = User.find(:all)

# respond_to do |format|
# format.html # index.html.erb
# format.xml { render :xml => @users }
# end
  end

  # GET /users/new
  # GET /users/new.xml
  def manage
    list
    @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

  # POST /users
  # POST /users.xml
  def create
    @user = User.new(params[:user])

    respond_to do |format|
      if @user.save
        flash[:notice] = 'User was successfully created.'
        format.html { redirect_to(users_url) }
        format.xml { render :xml => @user, :status
=> :created, :location => @user }
      else
        format.html { render(:action => "manage") }
        format.xml { render :xml => @user.errors, :status
=> :unprocessable_entity }
      end
    end
  end

  # PUT /users/1
  # PUT /users/1.xml
  def update
    @user = User.find(params[:id])

    respond_to do |format|
      if @user.update_attributes(params[:user])
        flash[:notice] = 'User was successfully updated.'
        format.html { redirect_to(users_url) }
        format.xml { head :ok }
      else
        format.html { render(:action => 'manage') }
        format.xml { render :xml => @user.errors, :status
=> :unprocessable_entity }
      end
    end
  end

  # DELETE /users/1
  # DELETE /users/1.xml
  def destroy
    @user = User.find(params[:id])
    @user.destroy

    respond_to do |format|
      flash[:notice] = 'User was successfully deleted.'
      format.html { redirect_to(:action => 'list') }
      format.xml { head :ok }
    end
  end

end

LIST VIEW
<% @page_title = 'Current Users' -%>

<%= content_tag('p', link_to('&laquo; Back to Menu', :controller =>
'staff', :action => 'menu')) %>

<div class='userlist_left'>
  <%= render(:partial => 'listing') -%>
</div>
<div class= 'userlist_right'>
  Please select a user on the left or create a new user.
  <%= link_to('New user', :action => 'manage') -%>
</div>

MANAGE VIEW
<% @page_title = 'Current Users' -%>

<%= content_tag('p', link_to('&laquo; Back to Menu', :controller =>
'staff', :action => 'menu')) %>

<div class='userlist_left'>
  <%= render(:partial => 'listing') -%>
</div>
<div class= 'userlist_right'>
  <% if params[:id].blank? %>
    <h2>New user</h2>

    <% form_for(@user) do |f| -%>
      <%= render(:partial => 'form') -%>
      <p class= 'user_submit'><%= submit_tag "Create" -%></p>
    <% end -%>
  <% else -%>
    <h2>Editing user</h2>

    <% form_for(@user) do |f| -%>
      <%= render(:partial => 'form')%>
      <p class= 'user_submit'><%= submit_tag "Update" -%></p>
    <% end -%>

    <p class= 'user_submit'><%= link_to('Delete User', { :action =>
'destroy',
    :id => @user }, :confirm => 'Are you sure you want to permanently
delete this user?',
    :method => :delete) -%>

  <% end -%>

  <%= link_to('Cancel', :action => 'list') %></p>

</div>

_LISTING PARTIAL
<div class='userlist_listing'>
  <table>
    <tr>
      <th>First Name</th>
      <th>Last Name</th>
      <th>Username</th>
      <th>User Level</th>
    </tr>
  <% for user in @users -%>
    <tr class='<%= cycle('row1', 'row2')%>'>
      <td><%= h(user.first_name) -%></td>
      <td><%= h(user.last_name) -%></td>
      <td><%= h(user.username) -%></td>
      <td><%= h(user.user_level) -%></td>
        <td><%= link_to('Edit', :action => 'manage', :id => user) -%></

    </tr>
  <% end %>
  </table>
</div><br/>

_FORM PARTIAL
<%= error_messages_for(:user) -%>

<table>
  <tr>
    <th>Username</td>
    <td><%= text_field(:user, :username) -%></td>
  </tr>
  <tr>
    <th>Hashed Password</th>
    <td><%= text_field(:user, :hashed_password) -%></td>
  </tr>
  <tr>
    <th>First Name</th>
    <td><%= text_field(:user, :first_name) -%></td>
  </tr>
  <tr>
    <th>Last Name</th>
    <td><%= text_field(:user, :last_name) -%></td>
  </tr>
  <tr>
    <th>Email</th>
    <td><%= text_field(:user, :email) -%></td>
  </tr>

  <tr>
    <th>Display Name</th>
    <td><%= text_field(:user, :display_name) -%></td>
  </tr>

  <tr>
    <th>User Level</th>
    <td><%= select(:user, :user_level, [0,1,2,3,4,9]) -%></td>
  </tr>
</table>

Check the output of "rake routes" to see which routes are recognized.
When you are sure your URLs follow the expected URLs, check that your
actions correspond. Keep an eye on the log file to see what's going
on.

Christian

Please read http://frozenplague.net/2008/01/06/restful-routing-an-overview/
  to gain a better understanding of restful routing.

I also don't recommend merging the new action with the edit action
because you may run into problems later on

rename the action in your controller

chris wrote:

I started out with a normal scaffold for the USERS table. I changed
the index view to be list.html.erb but the url: '/users/list' returns
an 'unknown action' error. '/users/list/:id' also returns an 'unknown
action' error. I've also merged both the edit and new views into the
manage.html.erb which duplicates the list view except with a form on
the right side. the url '/users/manage' returns an 'unknown action'
error but '/users/manage/:id' brings me to the manage page with the
edit form.

Simply adding the method in the controller doesn't give you the route, nor does changing the name of the method in the controller. The reason '/users/manage/:id' works is because it gets scooped up by your default route '/:controller/:action/:id'.

Take a look at the :member and :collection options to map.resources. Then can be used as such:

# to add a method to an object of class User
# this will give you /users/:id/change_name
map.resources :users, :member => {:change_name => [:get, :post]}

# to add a method to the class itself
# this will give you /users/active
map.resources :users, :collection => {:active => :get}

You may also be interested in the :path_names option, to change the names of the typical routes.

# to change "edit" to "manage"
map.resources :users, :path_names => { :new => 'manage' }

I'm not sure what would happen if you mapped two methods to the same name:

# may or may not work as you'd expect
map.resources :users, :path_names => { :new => 'manage', :edit => 'manage' }

Reference:
http://api.rubyonrails.org/classes/ActionController/Resources.html

Hope that helps.

Cheers,
Darrik

Thanks for the replies guys, especially you Darrik. I actually did
have a look at the options to map.resources but was a little
overwhelmed. The tutorial I've been trying to complete merges the NEW
and EDIT actions to show how its possible to put all those actions
into a single method but in doing so, it just royally screws with the
default routes. I'm going to play around with the options as you
suggest and I'll let you know how I do in the next few days. thanks.

We'll i've read into RESTful routes and your other suggestions yet
still can't seem to fix the problem. here's the output from RAKE
ROUTES:

users GET /users {:controller=>"users", :action=>"index"}
formatted_users GET /users.:format
{:controller=>"users", :action=>"index"}
  POST /users {:controller=>"users", :action=>"create"}
  POST /users.:format {:controller=>"users", :action=>"create"}
new_user GET /users/manage {:controller=>"users", :action=>"new"}
formatted_new_user GET /users/manage.:format
{:controller=>"users", :action=>"new"}
edit_user GET /users/:id/manage
{:controller=>"users", :action=>"edit"}
formatted_edit_user GET /users/:id/manage.:format
{:controller=>"users", :action=>"edit"}
user GET /users/:id {:controller=>"users", :action=>"show"}
formatted_user GET /users/:id.:format
{:controller=>"users", :action=>"show"}
  PUT /users/:id {:controller=>"users", :action=>"update"}
  PUT /users/:id.:format {:controller=>"users", :action=>"update"}
  DELETE /users/:id {:controller=>"users", :action=>"destroy"}
  DELETE /users/:id.:format {:controller=>"users", :action=>"destroy"}
categories GET /categories
{:controller=>"categories", :action=>"index"}
formatted_categories GET /categories.:format
{:controller=>"categories", :action=>"index"}
  POST /categories {:controller=>"categories", :action=>"create"}
  POST /categories.:format
{:controller=>"categories", :action=>"create"}
new_category GET /categories/new
{:controller=>"categories", :action=>"new"}
formatted_new_category GET /categories/new.:format
{:controller=>"categories", :action=>"new"}
edit_category GET /categories/:id/edit
{:controller=>"categories", :action=>"edit"}
formatted_edit_category GET /categories/:id/edit.:format
{:controller=>"categories", :action=>"edit"}
category GET /categories/:id
{:controller=>"categories", :action=>"show"}
formatted_category GET /categories/:id.:format
{:controller=>"categories", :action=>"show"}
  PUT /categories/:id {:controller=>"categories", :action=>"update"}
  PUT /categories/:id.:format
{:controller=>"categories", :action=>"update"}
  DELETE /categories/:id
{:controller=>"categories", :action=>"destroy"}
  DELETE /categories/:id.:format
{:controller=>"categories", :action=>"destroy"}
posts GET /posts {:controller=>"posts", :action=>"index"}
formatted_posts GET /posts.:format
{:controller=>"posts", :action=>"index"}
  POST /posts {:controller=>"posts", :action=>"create"}
  POST /posts.:format {:controller=>"posts", :action=>"create"}
new_post GET /posts/new {:controller=>"posts", :action=>"new"}
formatted_new_post GET /posts/new.:format
{:controller=>"posts", :action=>"new"}
edit_post GET /posts/:id/edit {:controller=>"posts", :action=>"edit"}
formatted_edit_post GET /posts/:id/edit.:format
{:controller=>"posts", :action=>"edit"}
post GET /posts/:id {:controller=>"posts", :action=>"show"}
formatted_post GET /posts/:id.:format
{:controller=>"posts", :action=>"show"}
  PUT /posts/:id {:controller=>"posts", :action=>"update"}
  PUT /posts/:id.:format {:controller=>"posts", :action=>"update"}
  DELETE /posts/:id {:controller=>"posts", :action=>"destroy"}
  DELETE /posts/:id.:format {:controller=>"posts", :action=>"destroy"}
    /:controller/:action/:id.:format
    /:controller/:action/:id

Sorry that its difficult to read, google's text editor doesn't really
offer much. I also tried adding the following into my ROUTES.RB after

map.resources :users| which was already in there:

:path_names => { :new => 'manage', :edit => 'manage' }, :collection
=> {:list => :get, :manage => [:post, :put, :delete]}

This adding the following 4 lines to my RAKE ROUTES:

manage_users POSTPUTDELETE /users/manage
{:controller=>"users", :action=>"manage"}
formatted_manage_users POSTPUTDELETE /users/manage.:format
{:controller=>"users", :action=>"manage"}
list_users GET /users/list
{:controller=>"users", :action=>"list"}
formatted_list_users GET /users/list.:format
{:controller=>"users", :action=>"list"}

It looks right to me but when i redirect to the url => 'users/list' or
'users/manage', it sends 'list' or 'manage' as the :id and it gives me
an unknown action error. This means my new, create, update, destroy
methods all don't work.

please look at the first post for my CONTROLLER and VIEW code.

chris wrote:

We'll i've read into RESTful routes and your other suggestions yet
still can't seem to fix the problem. here's the output from RAKE
ROUTES:

users GET /users {:controller=>"users", :action=>"index"}
formatted_users GET /users.:format
{:controller=>"users", :action=>"index"}
  POST /users {:controller=>"users", :action=>"create"}
  POST /users.:format {:controller=>"users", :action=>"create"}
new_user GET /users/manage {:controller=>"users", :action=>"new"}
formatted_new_user GET /users/manage.:format
{:controller=>"users", :action=>"new"}
edit_user GET /users/:id/manage
{:controller=>"users", :action=>"edit"}
formatted_edit_user GET /users/:id/manage.:format
{:controller=>"users", :action=>"edit"}
user GET /users/:id {:controller=>"users", :action=>"show"}
formatted_user GET /users/:id.:format
{:controller=>"users", :action=>"show"}
  PUT /users/:id {:controller=>"users", :action=>"update"}
  PUT /users/:id.:format {:controller=>"users", :action=>"update"}
  DELETE /users/:id {:controller=>"users", :action=>"destroy"}
  DELETE /users/:id.:format {:controller=>"users", :action=>"destroy"}
categories GET /categories
{:controller=>"categories", :action=>"index"}
formatted_categories GET /categories.:format
{:controller=>"categories", :action=>"index"}
  POST /categories {:controller=>"categories", :action=>"create"}
  POST /categories.:format
{:controller=>"categories", :action=>"create"}
new_category GET /categories/new
{:controller=>"categories", :action=>"new"}
formatted_new_category GET /categories/new.:format
{:controller=>"categories", :action=>"new"}
edit_category GET /categories/:id/edit
{:controller=>"categories", :action=>"edit"}
formatted_edit_category GET /categories/:id/edit.:format
{:controller=>"categories", :action=>"edit"}
category GET /categories/:id
{:controller=>"categories", :action=>"show"}
formatted_category GET /categories/:id.:format
{:controller=>"categories", :action=>"show"}
  PUT /categories/:id {:controller=>"categories", :action=>"update"}
  PUT /categories/:id.:format
{:controller=>"categories", :action=>"update"}
  DELETE /categories/:id
{:controller=>"categories", :action=>"destroy"}
  DELETE /categories/:id.:format
{:controller=>"categories", :action=>"destroy"}
posts GET /posts {:controller=>"posts", :action=>"index"}
formatted_posts GET /posts.:format
{:controller=>"posts", :action=>"index"}
  POST /posts {:controller=>"posts", :action=>"create"}
  POST /posts.:format {:controller=>"posts", :action=>"create"}
new_post GET /posts/new {:controller=>"posts", :action=>"new"}
formatted_new_post GET /posts/new.:format
{:controller=>"posts", :action=>"new"}
edit_post GET /posts/:id/edit {:controller=>"posts", :action=>"edit"}
formatted_edit_post GET /posts/:id/edit.:format
{:controller=>"posts", :action=>"edit"}
post GET /posts/:id {:controller=>"posts", :action=>"show"}
formatted_post GET /posts/:id.:format
{:controller=>"posts", :action=>"show"}
  PUT /posts/:id {:controller=>"posts", :action=>"update"}
  PUT /posts/:id.:format {:controller=>"posts", :action=>"update"}
  DELETE /posts/:id {:controller=>"posts", :action=>"destroy"}
  DELETE /posts/:id.:format {:controller=>"posts", :action=>"destroy"}
    /:controller/:action/:id.:format
    /:controller/:action/:id

Sorry that its difficult to read, google's text editor doesn't really
offer much. I also tried adding the following into my ROUTES.RB after
>map.resources :users| which was already in there:

:path_names => { :new => 'manage', :edit => 'manage' }, :collection
=> {:list => :get, :manage => [:post, :put, :delete]}

This adding the following 4 lines to my RAKE ROUTES:

manage_users POSTPUTDELETE /users/manage
{:controller=>"users", :action=>"manage"}
formatted_manage_users POSTPUTDELETE /users/manage.:format
{:controller=>"users", :action=>"manage"}
list_users GET /users/list
{:controller=>"users", :action=>"list"}
formatted_list_users GET /users/list.:format
{:controller=>"users", :action=>"list"}

It looks right to me but when i redirect to the url => 'users/list' or
'users/manage', it sends 'list' or 'manage' as the :id and it gives me
an unknown action error. This means my new, create, update, destroy
methods all don't work.

please look at the first post for my CONTROLLER and VIEW code.

Thanks for the replies guys, especially you Darrik. I actually did
have a look at the options to map.resources but was a little
overwhelmed. The tutorial I've been trying to complete merges the NEW
and EDIT actions to show how its possible to put all those actions
into a single method but in doing so, it just royally screws with the
default routes. I'm going to play around with the options as you
suggest and I'll let you know how I do in the next few days. thanks.

chriswrote:

I started out with a normal scaffold for the USERS table. I changed
the index view to be list.html.erb but the url: '/users/list' returns
an 'unknown action' error. '/users/list/:id' also returns an 'unknown
action' error. I've also merged both the edit and new views into the
manage.html.erb which duplicates the list view except with a form on
the right side. the url '/users/manage' returns an 'unknown action'
error but '/users/manage/:id' brings me to the manage page with the
edit form.

Simply adding the method in the controller doesn't give you the route,
nor does changing the name of the method in the controller. The reason
'/users/manage/:id' works is because it gets scooped up by your default
route '/:controller/:action/:id'.
Take a look at the :member and :collection options to map.resources.
Then can be used as such:
# to add a method to an object of class User
# this will give you /users/:id/change_name
map.resources :users, :member => {:change_name => [:get, :post]}
# to add a method to the class itself
# this will give you /users/active
map.resources :users, :collection => {:active => :get}
You may also be interested in the :path_names option, to change the
names of the typical routes.
# to change "edit" to "manage"
map.resources :users, :path_names => { :new => 'manage' }
I'm not sure what would happen if you mapped two methods to the same name:
# may or may not work as you'd expect
map.resources :users, :path_names => { :new => 'manage', :edit =>
'manage' }
Reference:http://api.rubyonrails.org/classes/ActionController/Resources.html
Hope that helps.
Cheers,
Darrik

>

Your controller doesn't have a method called 'list' or 'manage'.

Also of note, if you expect the manage method to manipulate an
individual object of the User class, you should add it as :member, not
:collection. Collection (as the name implies) defines actions that
operate on the entire collection (list, index, etc), whereas member
defines actions that operate on a single member (also as the name
implies). The key distinction is that the :collection option to mapping
a User resource will give you a route like /users/:action, whereas the
:member option will give you a route like /users/:id/:action, in both
cases where :action is whatever you specify.

Hope that helps.
Darrik

I actually do have a method called 'list' and 'manage' in my
controller so i'm not sure why you say I don't.

I've actually updated my Users Controller since the first post. it now
looks like this (I've CAPITALIZED the LIST and MANAGE methods:

class UsersController < ApplicationController

  layout 'staff'

  def index
    list
    render :action => 'list'
  end

  # GET /users
  # GET /users.xml
def LIST
    @users = User.find(:all)

# respond_to do |format|
# format.html # index.html.erb
# format.xml { render :xml => @users }
# end
  end

  # GET /users/new
  # GET /users/new.xml
  def MANAGE
    list
    if request.get? && params[:id].blank? #new
      @user = User.new
    elsif request.post? && params[:id].blank? #create
      @user = User.new(params[:user])
      respond_to do |format|
        if @user.save
          flash[:notice] = 'The user was successfully created.'
          format.html { redirect_to(:action => 'list') }
          format.xml { render :xml => @user, :status
=> :created, :location => @user }
        else
          format.html { render(:action => "manage") }
          format.xml { render :xml => @user.errors, :status
=> :unprocessable_entity }
        end
      end

    elsif request.get? && !params[:id].blank? #edit
      @user = User.find(params[:id])
    else request.post? && !params[:id].blank? #update or delete
      @user = User.find(params[:id])
      if params[:commit] == 'Update'
        respond_to do |format|
          if @user.update_attributes(params[:user])
            flash[:notice] = 'The user was successfully updated.'
            format.html { redirect_to(:action => 'list') }
            format.xml { head :ok }
          else
            format.html { render(:action => 'manage') }
            format.xml { render :xml => @user.errors, :status
=> :unprocessable_entity }
          end
        end
      else #action should delete
        @user = User.find(params[:id])
        @user.destroy
        respond_to do |format|
          flash[:notice] = 'The user was successfully deleted.'
          format.html { redirect_to(:action => 'list') }
          format.xml { head :ok }
        end
      end
    end
  end

end

I've made some very slight changes to my view to deal with the fact
that I no longer have a 'create' 'update' or 'destroy' method
anymore. As you can see, I've rolled all those methods into a single
method, 'manage'.

LIST VIEW
<% @page_title = 'Current Users' -%>

<%= content_tag('p', link_to('&laquo; Back to Menu', :controller =>
'staff', :action => 'menu')) %>

<div class='userlist_left'>
  <%= render(:partial => 'listing') -%>
</div>
<div class= 'userlist_right'>
  Please select a user on the left or create a new user.
  <%= link_to('New user', :action => 'manage') -%>
</div>

MANAGE VIEW
<% @page_title = 'Current Users' -%>

<%= content_tag('p', link_to('&laquo; Back to Menu', :controller =>
'staff', :action => 'menu')) %>

<div class='userlist_left'>
  <%= render(:partial => 'listing') -%>
</div>
<div class= 'userlist_right'>
  <% if params[:id].blank? %>
    <h2>New user</h2>

    <%# form_tag(:action => 'manage') do -%>
    <% form_for(@user) do -%>
      <%= render(:partial => 'form') -%>
      <p class= 'user_submit'><%= submit_tag "Create" -%></p>
    <% end -%>
  <% else -%>
    <h2>Editing user</h2>

    <%# form_tag(:action => 'manage', :id => @user) do -%>
    <% form_for(@user) do -%>
      <%= render(:partial => 'form')%>
      <p class= 'user_submit'><%= submit_tag "Update" -%></p>
    <% end -%>

    <p class= 'user_submit'><%= link_to('Delete User', { :action =>
'destroy',
    :id => @user }, :confirm => 'Are you sure you want to permanently
delete this user?',
    :method => :delete) -%>

  <% end -%>

  <%= link_to('Cancel', :action => 'list') %></p>

</div>

_LISTING PARTIAL
<div class='userlist_listing'>
  <table>
    <tr>
      <th>First Name</th>
      <th>Last Name</th>
      <th>Username</th>
      <th>User Level</th>
    </tr>
  <% for user in @users -%>
    <tr class='<%= cycle('row1', 'row2')%>'>
      <td><%= h(user.first_name) -%></td>
      <td><%= h(user.last_name) -%></td>
      <td><%= h(user.username) -%></td>
      <td><%= h(user.user_level) -%></td>
        <td><%= link_to('Edit', :action => 'manage', :id => user) -%></

    </tr>
  <% end %>
  </table>
</div><br/>

_FORM PARTIAL

<%= error_messages_for(:user) -%>

<table>
  <tr>
    <th>Username</td>
    <td><%= text_field(:user, :username) -%></td>
  </tr>
  <tr>
    <th>Hashed Password</th>
    <td><%= text_field(:user, :hashed_password) -%></td>
  </tr>
  <tr>
    <th>First Name</th>
    <td><%= text_field(:user, :first_name) -%></td>
  </tr>
  <tr>
    <th>Last Name</th>
    <td><%= text_field(:user, :last_name) -%></td>
  </tr>
  <tr>
    <th>Email</th>
    <td><%= text_field(:user, :email) -%></td>
  </tr>

  <tr>
    <th>Display Name</th>
    <td><%= text_field(:user, :display_name) -%></td>
  </tr>

  <tr>
    <th>User Level</th>
    <td><%= select(:user, :user_level, (0..9).to_a.reverse) -%></td>
  </tr>
</table>

I also tried to configure my ROUTES.RB as you've suggested, using
the :member option instead of the :collection for the 'manage' action
as such:

ActionController::Routing::Routes.draw do |map|
  map.resources :users, :path_names => { :new => 'manage', :edit =>
'manage' },
  :collection => {:list => :get}, :member => {:manage =>
[:post, :put, :delete]}

  map.resources :categories

  map.resources :posts

  map.connect ':controller/:action/:id.:format'
  map.connect ':controller/:action/:id'
end

Now, when I goto the url: '/users/manage' (the url for creating a new
user object) and '/users/:id/manage' (the url for editing an existing
user object) it still gives me the unknown action error. Instead of
sending 'manage' as the :id (which is what it did before I added
the :path_names, :collection, :member options in my routes.rb code),
it sends 'new' and 'edit' as the :action where instead it should be
sending 'manage' as the action or so I think.

Thanks again.