Pattern for creating child objects

Hi, complete newbie question but I'd like to understand the recommended controller pattern for creating child objects of a parent.

The starting point is a display action for the parent: def show I have a button on the page which calls an action on the parent controller: def new_child I have an action on the child controller for creating a new child with the parent passed in as an argument: def new (parent)

I'm struggling with how to pass the parent object through to the new_child action from the parent controller. This makes me think that perhaps the pattern is wrong.

I would really welcome any thoughts, guidelines, etc.

Thanks,

Adam

I don’t know enough about your data to know if this is a tree structure (self-referential join) or a parent-child in terms of 'a project has a task associated"

Either way the concept is the same. It’s trivial if you use RESTful routing.

config/routes.rb

map.resources :projects do |p| p.resources :tasks end

app/models/project.rb

has_many :tasks

app/views/projects/index.html.erb

<%=link_to “Create new project”, new_project_task_url(@project) %>

/app/controllers/task_controller.rb

before_filter :find_project

def index @tasks = @project.tasks.find :all end

def new @task = @project.tasks.build end

def create @task = @project.tasks.build(params[:task]) if @task.save flash[:notice] = “Task added successfully!” redirect_to project_tasks_url(@project) else render :action=>“new” end end

private

  def find_project
    begin   
       @project = Project.find(params[:project_id])  # the url sends the project in as params[:project_id]
    rescue
        flash[:notice] = "Project not found"
        redirect_to root_url
    end
  end

The key is to make sure to pass the id of the project around in every URL you use and scope everything using the associations. Notice when I find tasks I do @project.tasks.find(:all) instead of Task.find(:all). This is a great way to ensure that I only get the things I need.

@task = @project.tasks.build is the same as @task = Task.new(:project_id => some_id).

If this is not clear enough, let me know how I can help.