首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >has_many autosave_associated_records_for_*

has_many autosave_associated_records_for_*
EN

Stack Overflow用户
提问于 2012-01-27 04:20:30
回答 3查看 2.2K关注 0票数 4

我正在尝试关联现有记录,同时仍然可以添加新记录。以下代码不起作用,但非常接近我需要的内容。如何完成关联已有记录和创建新记录?

代码语言:javascript
复制
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

这里有一行相关的源代码:https://github.com/rails/rails/blob/v3.0.11/activerecord/lib/active_record/autosave_association.rb#L155

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-01-27 05:09:26

我已经做了一个解决方案,但是如果你知道更好的方法,请让我知道!

代码语言:javascript
复制
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
EN

Stack Overflow用户

发布于 2014-09-25 01:55:29

我有一个标签系统,它利用了has_many :through关系。这里的两个解决方案都没有让我达到我需要的程度,所以我想出了一个可能对其他人有帮助的解决方案。这已经在Rails 3.2上进行了测试。

设置

以下是我的模型的基本版本:

Location对象:

代码语言:javascript
复制
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

标记对象

代码语言:javascript
复制
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

解决方案

我确实覆盖了autosave_associated_record_for方法,如下所示:

代码语言:javascript
复制
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

上面的实现按照我在嵌套表单中使用fields_for时所需的方式保存、删除和更改标签。如果有简化的方法,我愿意接受反馈。需要指出的是,我是在标签更改时显式地更改标签,而不是更新标签。

票数 1
EN

Stack Overflow用户

发布于 2021-02-02 01:14:20

在Rails6(可能还有更早的版本)中,很容易覆盖由accepts_nested_attributes_for生成的属性编写器并使用find_or_initialize_by

在这种情况下,您可以简单地编写:

代码语言:javascript
复制
has_many :comments, :through => :commentings, :source => :commentable, :source_type => "Comment"
accepts_nested_attributes_for :comments, :allow_destroy => true

def comments_attributes=(hashes)
  hashes.each { |attributes| comments << Comment.find_or_initialize_by(attributes)
end

我还没有在传递:id:_destroy密钥时测试过这一点,因为它不适用于我的情况,但是如果你这样做了,请随时分享你的想法或代码。

我希望看到Rails原生地实现这一点,也许是通过向accepts_nested_attributes_for传递一个upsert: true选项。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9024745

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档