Nested Routing in Rails
map.resources :programs do |program| # /programs/:id programs_url program_url(@program)
program.resources :deadlines # /programs/:program_id/deadlines/:id program_deadlines(@program) program_deadline(@program, @deadline)
program.resources :pages do |page| # /programs/:program_id/pages/:id program_pages_url(@program)
page.resource :images # /programs/:program_id/pages/:page_id/images/:id
# program_page_image(@program, @page.slug, @image)
end
end
class ApplicationController < ActionController::Base
private
def find_program
@program = params[:controller] == "projects" ? Program.find(params[:id]) || Program.find(params[:program_id])
end
def find_page
# we want page names to show up as a slug, rather than a numerical id
# so we assume people will send in link_to @page.name, program_page_url(@program, @page.slug)
# and then we find_by_slug instead of find or find_by_id
@page = params[:controller] == "pages" ? Page.find_by_slug(params[:id]) || Page.find_by_slug(params[:page_id])
end
end
class ProgramsController < ApplicationController
before_filter :find_program, :except=> [:index, :create, :new]
def index
@programs = Program.all
end
def new
@program = Program.new
end
def edit
# you can skip this action since the filter does its job and it's not needed
# as the view will still render. This action will get skipped from now on.
end
def create
@progra = Program.new(params[:page])
if @page.save
redirect_to program_url(@program)
else
render :action => "new"
end
end
def update
if @program.update_attributes(params[:page])
redirect_to programs_url
else
render :action => "new"
end
end
def destroy
@program.destroy
redirect_to programs_url
end
end
class PagesController < ApplicationController
before_filter :find_program
before_filter :find_page, :except => [:index, :create, :new]
def index
@program.pages.find :all
end
def new
@page = @program.pages.build
end
def edit
@page = @program.pages.find(params[:id]
end
def create
@page = @program.pages.build(params[:page])
if @page.save
redirect_to program_pages_url(@program)
else
render :action => "new"
end
end
def update
if @page.update_attributes(params[:page])
redirect_to program_pages_url(@program)
else
render :action => "new"
end
end
def destroy
@page.destroy
redirect_to program_pages_url(@program)
end
end
# A singleton controller has no index action... it still has a pluralized controller name
# by default though!!!
class ImagesController < ApplicationController
before_filter :find_program
before_filter :find_page
before_filter :find_image, :except => [:create, :new]
def new
@image = @page.images.build
end
def create
@image = @page.images.build(params[:image]
if @image.save
redirect_to program_page_image(@program, @page, @image
else
render :action => "new"
end
end
def edit
end
def update
if @image.update_attributes(params[:image])
redirect_to program_page_image(@program, @page, @image
else
render :action => "new"
end
end
def destroy
@image.destroy
end
end
Original snippet written by Brian Hogan
Last updated at 08:42 AM on Oct 10, 2008
by Brian Hogan