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?


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


more information about restful routing: frozenplague.net

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