Has_many autosave_associated_records_for_ *

I'm trying to link existing records while still being able to add new ones. The following does not work, but pretty close to what I need. How can I link existing records and create new ones?

has_many :comments, :through => :commentings, :source => :commentable, :source_type => "Comment" accepts_nested_attributes_for :comments, :allow_destroy => true def autosave_associated_records_for_comments comments.each do |comment| if existing_comment = Comment.find_by_fax_and_name(comment.fax, comment.name) self.comments.reject! { |hl| hl.fax == existing_comment.fax && hl.name == existing_comment.name } self.comments << existing_comment else self.comments << comment end end end 

Here is the corresponding source line: https://github.com/rails/rails/blob/v3.0.11/activerecord/lib/active_record/autosave_association.rb#L155

+4
source share
2 answers

I made a decision, but if you know the best way to do this, please let me know!

 def autosave_associated_records_for_comments existing_comments = [] new_comments = [] comments.each do |comment| if existing_comment = Comment.find_by_fax_and_name(comment.fax, comment.name) existing_comments << existing_comment else new_comments << comment end end self.comments << new_comments + existing_comments end 
+6
source

I have a tag system that uses has_many: through relationships. None of the solutions here led me to where I needed to go, so I came up with a solution that could help others. This has been tested on Rails 3.2.

Customization

Here is the basic version of my models:

Location Object:

 class Location < ActiveRecord::Base has_many :city_taggables, :as => :city_taggable, :dependent => :destroy has_many :city_tags, :through => :city_taggables accepts_nested_attributes_for :city_tags, :reject_if => :all_blank, allow_destroy: true end 

Tag objects

 class CityTaggable < ActiveRecord::Base belongs_to :city_tag belongs_to :city_taggable, :polymorphic => true end class CityTag < ActiveRecord::Base has_many :city_taggables, :dependent => :destroy has_many :ads, :through => :city_taggables end 

Decision

I really redefined the autosave_associated_record_for method as follows:

 class Location < ActiveRecord::Base private def autosave_associated_records_for_city_tags tags =[] #For Each Tag city_tags.each do |tag| #Destroy Tag if set to _destroy if tag._destroy #remove tag from object don't destroy the tag self.city_tags.delete(tag) next end #Check if the tag we are saving is new (no ID passed) if tag.new_record? #Find existing tag or use new tag if not found tag = CityTag.find_by_label(tag.label) || StateTag.create(label: tag.label) else #If tag being saved has an ID then it exists we want to see if the label has changed #We find the record and compare explicitly, this saves us when we are removing tags. existing = CityTag.find_by_id(tag.id) if existing #Tag labels are different so we want to find or create a new tag (rather than updating the exiting tag label) if tag.label != existing.label self.city_tags.delete(tag) tag = CityTag.find_by_label(tag.label) || CityTag.create(label: tag.label) end else #Looks like we are removing the tag and need to delete it from this object self.city_tags.delete(tag) next end end tags << tag end #Iterate through tags and add to my Location unless they are already associated. tags.each do |tag| unless tag.in? self.city_tags self.city_tags << tag end end end 

The above implementation saves, deletes and modifies tags as I needed, using the fields for the nested form. I am open to feedback if there are ways to simplify. It is important to note that I explicitly change tags when the label changes, rather than updating the tag label.

+1
source

Source: https://habr.com/ru/post/1393252/


All Articles