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.
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.