I have the same exact schema as described here with a polymorphic join table: http://aaronvb.com/articles/a-polymorphic-join-table.html
class Location < ActiveRecord::Base
has_many :note_joins, as: :notable
has_many :notes, through: :note_joins
end
class Checkpoint < ActiveRecord::Base
has_many :note_joins, as: :notable
has_many :notes, through: :note_joins
end
class NoteJoin < ActiveRecord::Base
belongs_to :notable, polymorphic: true
belongs_to :note
end
class Note < ActiveRecord::Base
attr_accessible :content, :user_id
belongs_to :notable, polymorphic: true
belongs_to :user
has_many :note_joins
end
I want to be able to create and update multiple types of polymorphic associations at once, instead of having to do @note.locations << Location.first
or @note.checkpoints << Checkpoint.first
.
Something like @note.create note_joins_params
and @note.update note_joins_params
would be awesome.
The way I've been able to achieve the creation part so far is by passing an array of attributes to @note.note_joins.create
, e.g. :
note_joins_params = [{"notable_id"=>"9225", "notable_type"=>"Location"}, {"notable_id"=>"9220", "notable_type"=>"Checkpoint"}]
@note.note_joins.create note_joins_params
Is there a more Rails-esque way to accomplish this, or proper attributes hash syntax similar to accepts_nested_attributes or something similar?
Also the only way I know of how to do an update
is to first delete all the existing records in the join table and then re-create them, i.e.
@note.note_joins.destroy_all
new_note_joins_params = [{"notable_id"=>"9225", "notable_type"=>"Location"}, {"notable_id"=>"9220", "notable_type"=>"Checkpoint"}]
@note.note_joins.create new_note_joins_params
For what you want to accomplish, Rails doesn't really have this 'smart_way' of accepting nested attributes if you don't specify the source_type
. Refer to this The other side of polymorphic :through associations
But you can try this:
class Location < ActiveRecord::Base
has_many :note_joins, as: :notable
has_many :notes, through: :note_joins
accepts_nested_attributes_for :notes
end
class Checkpoint < ActiveRecord::Base
has_many :note_joins, as: :notable
has_many :notes, through: :note_joins
accepts_nested_attributes_for :notes
end
class NoteJoin < ActiveRecord::Base
belongs_to :notable, polymorphic: true
belongs_to :note
accepts_nested_attribute_for :note
end
class Note < ActiveRecord::Base
attr_accessible :content, :user_id
belongs_to :user
has_many :note_joins
# add these, otherwise you won't be able to do nested attributes
# refer to the blog post I link above.
has_many :locations, through: :note_joins, source: :notable, source_type: 'Location'
has_many :checkpoints, through: :note_joins, source: :notable, source_type: 'Checkpoint'
end
Then in your form, build something like this:
# In your form
# if you want to create from the note, do this
<%= form_for @note do |f| %>
<%= f.text_field :some_note_field %>
<%= text_field_tag 'note[locations_attributes][][some_location_field]' %>
<%= text_field_tag 'note[checkpoints_attributes][]some_checkpoint_field]' %>
<% end %>
# if you want to create from the location/checkpoint, do this.
<%= form_for @location do |f| %>
<%= f.text_field :name %>
<%= text_field_tag 'location[notes_attributes][][body]' %>
<% end %>
# In your Location/Checkpoint controllers
def create
@location = Location.create(location_params)
redirect_to @location
end
def location_params
params.required(:location).permit(:name, notes_attributes: [:body])
end
# In your Note controller
def create
@note = Note.create(note_params)
redirect_to @note
end
def note_params
# the goal here is to create a set of params like this
# { note_field: 'foobar',
# locations_attributes: [{name: 'somewhere'}],
# checkpoints_attributes: [{description: 'lol'}] }
params.required(:note).permit(:note_field, locations_attributes: [:location_field], checkpoints_attributes: [:checkpoint_field])
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With