Hi, this blog is no longer maintained, my new blog is here

Ruby On Rails and a Conning Israeli entrepreneur

Rails Nested Resources Tutorial

Preface

The best way to get started with Rails 2.x nested routing and routing at all, is to read the official Rails Routing guide at the Rails Guides website.

Rails Nested Routes/Resources

The rails nested routes/resources were indroduced at Rails 1.2 as part of the RESTful approach that was adopted by the Rails core members.
Nested resources allowed urls like:
/tasks/?project_id=1
To have a bit more sexy/RESTful look:
/projects/1/tasks

Let’s use this example to make things a little more clear, we will use 2 models, Project and Task

# /app/models/project.rb
class Project < ActiveRecord::Base
has_many :tasks
end

# /app/models/task.rb
class Task < ActiveRecord::Base
belongs_to :project
end


Setting up routes.rb

Creating a Nested Resource

:has_many keyword

The easiest way to create a nested route, is to use the :has_many keyword like that:

# /config/routes.rb
map.resources :projects, :has_many => :tasks

# and the correspondent task resource
map.resources :tasks


Adding the second routes, that defines a RESTful route to :tasks, depends if you would like to allow an access to the Task resource, without the project context, this is not a must.

Block

You can also specify the sub-resources in a block
map.resources :projects do |project|
project.resources :tasks
end

Singular Resources

Just the same:
map.resources :projects do |project|
user.resource :design_document
end

Routes Helpers

Run:
$ rake routes
to see what kind of routes do you have in your application, you can pipe UNIX’s grep command (”| grep xxx”) to filter the results:
$ rake routes | grep project

A basic map.resources :projects will produce:
events GET /projects {:controller=>"projects", :action=>"index"}
formatted_projects GET /projects.:format {:controller=>"projects", :action=>"index"}
POST /projects {:controller=>"projects", :action=>"create"}
POST /projects.:format {:controller=>"projects", :action=>"create"}
new_project GET /projects/new {:controller=>"projects", :action=>"new"}
formatted_new_project GET /projects/new.:format {:controller=>"projects", :action=>"new"}



but a Nested route, like we defined before will produce:
project_tasks GET /projects/:project_id/tasks
new_project_task GET /projects/:project_id/tasks/new
edit_project_task GET /projects/:project_id/tasks/:id/edit
project_task GET /projects/:project_id/tasks/:id


very nice.

Singular Nested Route Helpers


(from the example above)
/projects - list all projects
/projects/1 - show a single project
/projects/1/design_document - a project’s design document


Using the routing helpers


Since we now have another resource in context when we want o use the new helpers, we need to include that resource instance as a paramter:
new_project_task(@project)
# or when both resources are required
edit_project_task(@project, @task)


Forms


I'll assume you use form_for in your forms, it will make the usage of nested resources a lot easier than to work with plain HTML or form_tag.
The regular form we know of form_for, receives one instance as the form object:
<% form_for(@project) do |f| %>
...
<% end %>

But with nested resources, we'll pimp it up a little bit:

<% form_for([ @project, @task ]) do |f| %>
...
<% end %>

Note the instances array, that specifies the objects we need in our form when we deal with nested resources

Conclusion and some Gotchas.


Using nested resources and routes is the right thing, URLs are clear, and code is readable. but:

# You should not implement nested resources of more than 2 levels.
# Setting up pagination support (?page=3) kind of breaks the RESTful approach.
# The railscast about Nested Resources.
# Using RESTful ajax calls, a great lib by dfr|work (#rubyonrails).


The Web Ask eizesus.com

Subscribe

    follow me on Twitter

    Twiters Around

    About Me

    My photo
    I am a web developer for more than 9 years, managed, cried, coded, designed and made money in this industry. now trying to do it again.

    Labels