Nested Model Forms -- How do you create an object through an association if it doesn't already exist?
From Ryan Bates's episode about nested model forms, I was able to create a project with concerts
, bands
and performances
that they play. I can add performances to a new concert or when I edit a concert. That's fairly simple and straightforward when I follow his tutorial.
performances
belongs to bands
and performances
belongs to concerts
. A performance will list the band playing and the time starting/ending. Bands only have a string column for its name.
When I create a new concert and add a whole slew of performances, I'd like to, at the same time, be able to create the band
objects if they don't already exist. Otherwise, the user has the added step(s) of creating those objects, which would be tedious.
How, through accepts_nested_attributes_for
or some other useful Rails feature, can I do this? I am using Rails 2.3.8
Here are my associations:
class Band < ActiveRecord::Base
has_many :performances
has_many :concerts, :through => :performances
end
class Concert < ActiveRecord::Base
has_many :performances
has_many :bands, :through => :performances
accepts_nested_attributes_for :performances, :reject_if => lambda { |a| a[:content].blank? }, :allow_dest开发者_如何学JAVAroy => true
end
class Performance < ActiveRecord::Base
belongs_to :band
belongs_to :concert
end
Rails can handle this for you, you just need to make sure you pass in the params the right way (which multiple nested forms should do for you)
class Concert < ActiveRecord::Base
has_many :performances
has_many :bands, :through => :performances
accepts_nested_attributes_for :performances
end
class Performance < ActiveRecord::Base
belongs_to :concert
has_many :bands
accepts_nested_attributes_for :bands
end
class Band < ActiveRecord::Base
belongs_to :performance
end
Your params
hash should look like this:
{
:concert => {
:performances_attributes => [
{
:bands_attributes => [
{
:name => "test u"
}],
:name=>"test p"
}],
:name=>"test"
}
}
You build
new blank instances of the association that you want to create. In the case of a belongs_to
, the method to build the association instance is "build_#{association_name}"
so if you wanted to create a new band via a performance that accepts_nested_attributes_for :band
you would initialize a blank band in your controller method:
class PerformancesController < ApplicationController
def new
@performance = Performance.new # You're building
# the performance to create
@performance.build_band # You're building
# the band to create
end
end
The build method for has_many associations is "#{association_name}.build
, so for a band that accepts_nested_attributes_for :performances
:
class BandsController < ApplicationController
def new
@band = Band.new
3.times { @band.performances.build }
end
end
You have to use the build method noted above for the fields to show up in your form. Following is how you'd set up your form.
<%= form_for @concert do |cf| %>
<%= cf.label :name %>
<%= cf.text_field :name %>
<%= cf.fields_for :performances do |pf| do %>
<%= pf.label :some_attr %>
...
<%= pf.fields_for :bands do |bf| %>
<%= bf.label ... %>
<%end>
<% end %>
<% end %>
精彩评论