2.x and RESTful Controllers

Hello everybody. I'm in the process of developing a site on Rails
2.0.2, and having migrated from the early 1.x days, I'm still getting
my feet wet with the new REST-based controllers. For the most part,
the REST controllers generated by scaffold have been painless to use
so far. I ran into a problem last night when I tried to add a method
to a controller outside of the REST domain. A dumbed down example
would be:

class CoursesController < ApplicationController
  def hello
    render :text => "Hello"
  end
end

Trying to access http://mysite.com/courses/hello would yield.

Couldn't find Course with ID=hello

I understand why this is happening. The controller is trying to use
hello as a course ID because of the REST URI layout, but what do I do
if I want to define a custom method on my controller? My solution last
night was to modify routes.rb and add something like the following
above the map.resources :courses declaration:

map.connect 'courses/hello', :controller => 'courses', :action =>
'hello'

This seems to work, but I'm wondering if it's the right way to do it.
Maybe I'm never supposed to diverge from the REST domain, but there
are times when it's sort of a necessity. Can anybody tell me if I'm on
the right track, or is there a better way?

Hi,

there is a better way of defining routes to custom actions in a
RESTful controller.

I assume you have something like

map.resources :courses

in your routes.rb.

Methods can be of two types. The first is a method that is expected to
handle a collection of the resource (like index), the other is
expected to handle only one instance of the resource (like show and
edit).

For a collection method you write this instead of the plain entry
above:

map.resources :courses, :collection => {
    :channel_timeline => :get
}

This will create the correct route and also supply you with other
methods like hello_courses_path. Set the value to :get, :post, :put
or :delete as appropriate.

For the second type you write:

map.resources :courses, :member => {
  :hello => :get
}

Note that this will yield different routes and methods. Now it will
expect an id and the path method will be in singular,
hello_course_path.

Hope this helps. Kind regards

Erik Lindblad

Checkout members and/or collections

I'm pretty sure the code is wrong, but it's something like this:

map.resources :courses, :members => [:cancel => :post]
whicih allows for /courses/1/cancel

map.resources :courses, :collections => [:cancel_all]
which allows for /courses/cancel_all

And btw, you might as well run Rails 2.1 if you're starting from scratch :slight_smile:

Hi again

I think the syntaxes are equivalent. [:cancel => :post] is really
[{:cancel => :post}] which has the same effect as the code in my
answer above. The code is from an app that is in production so
definitively works. Chose the syntax that is most comfortable to you.

Kindest regards

Erik

more information about restful routing: http://frozenplague.net/2008/01/06/restful-routing-an-overview/

Hello everybody. I just wanted to say thanks for the help and for all
the good solutions. I'm loving working with Rails so far. My only
complaint is that it's moderately difficult to figure out how to do
certain things. but the community is here to help, so that's really
awesome.

Thanks,
Travis