11.25.07
A rails form that creates multiple models at once
I want to create a simple site that allows users to add event, restaurant and location details through an ajax-ish interface. Ultimately I have a design in mind but to get there I need to be able to submit details of multiple models through a single form (there are about 10 fields over 4 models that will need to be defined).
I wanted to use the action view “form_for”, a single submit and have the submission automatically map the fields to their proper object so that my controller method could look like this (sans error handling):
def create
if request.post?
@deal = Deal.new(params[:deal])
@deal.Restaurant = Restaurant.new(params[:restaurant])
@deal.Location = Location.new(params[:location])
@deal.save
end
end
Long story short - what you need to do is use the “fields_for” call within the form to get the model information. The form in the view looks like:
<% form_for :deal, :url => { :action => :create } do |form| %>
<% fields_for :restaurant do |r| %>
Restaurant: <%= r.text_field :name %><br/>
<% end %>
<% fields_for :location do |l| %>
Address 1: <%= l.text_field :address1 %><br/>
Address 2: <%= l.text_field :address2 %><br/>
City: <%= l.text_field :city %><br/>
State: <%= l.text_field :state %><br/>
Zip: <%= l.text_field :zip %><br/>
<% end %>
Details: <%= form.text_area :description, :rows => 3 %>
<%= submit_tag %>
<% end %>
In this example three models are used - Deal, Restaurant and Location.
The form is based on Deal (since I want the submit to go to Deal::create and I defined two fields_for blocks - one for Restaurant and Location.
The params.inspect output of the form data is:
Parameters: {”restaurant”=>{”name”=>”rest name”}, “deal”=>{”description”=>”Kids can eat whatever they want in under 3 minutes.”}, “commit”=>”Save changes”, “location”=>{”city”=>”some place”, “address1″=>”address one”, “zip”=>”12345″, “address2″=>”", “state”=>”NC”}}
Notice that restaurant, deal and location are all their own hash which can be passed to the new method on the respective models.
Worked like a champ.
Details on the schema is:
create_table :locations do |t|
t.column :address1, :string, :limit => 60
t.column :address2, :string, :limit => 60
t.column :city, :string, :limit => 40
t.column :state, :string, :limit => 2
t.column :zip, :string, :limit => 10
t.column :phone, :string, :limit => 16
t.column :lng, :string, :limit => 30
t.column :lat, :string, :limit => 30
t.column :restaurant_id, :int
end
create_table :restaurants do |t|
t.column :name, :string, :limit => 60
end
create_table :deals do |t|
t.column :restaurant_id, :int
t.column :location_id, :int
t.column :description, :text
end
And the models relationships:
class Deal < ActiveRecord::Base belongs_to :Restaurant belongs_to :Location ... end class Location < ActiveRecord::Base belongs_to :Restaurant end class Restaurant < ActiveRecord::Base has_many :Location has_many :Deal ... end