Topic: Creating Two Models in One Form
Q: How do I make a form that handles multiple models?
This question is asked quite frequently. Scaffolding and simple Rails tutorials show you how to create one model per form. Unfortunately, sometimes this is not sufficient.
In this article we will make one form that creates two models: Project and Task (where a project has many tasks). What I would like to do is have the first task be created the same time the project is created (in the same form). Here's the new action in the controller:
# in the projects_controller.rb
@project = Project.new
@task = Task.new
Here we are creating the models which will contain the default values - we can set any default values in this action and they will be reflected in the form.
Next we make the form containing fields for these two models. Of course you could add as many fields as you need to for each model:
# in the projects/new.rhtml
<%= error_messages_for :project %>
<%= error_messages_for :task %>
<%= start_form_tag :action => 'create' %>
<%= text_field :project, :name %>
<%= text_field :task, :name %>
<%= submit_tag 'Create' %>
<%= end_form_tag %>
Pretty simple. Now comes the tricky part, the create action. First the code, then I'll explain it.
@project = Project.new(params[:project])
@task = @project.tasks.build(params[:task])
redirect_to :action => 'index'
render :action => 'new'
The @project instance variable is set normally, but what's up with how the task is created? We use a fancy method to help us out here. The @project.tasks.build method creates a task (just like Task.new) and adds it to the @project at the same time. Pretty cool huh?
Next we call @project.save. This method is actually doing a lot. First it checks if the project and all of its tasks are valid. If something is invalid it returns false, otherwise it saves both project and task and returns true. This save method is very convenient and handles everything for us automagically.
Why do we bother setting the @task instance variable you may wonder? We need it in case the validation fails and we render the 'new' form again.
The creation of the project along with the task is finished, but how about editing? Normally, with this kind of set up, I use separate forms for editing. In this case I would list the tasks on the project 'show' page with an edit link next to each one.
If you want to edit all of the tasks on one big form, check out the next article in this series.
Last edited by ryanb (2006-09-26 19:48:21)