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