Rails:如果has_many关系发生了变化

oka*_*56k 15 ruby-on-rails ruby-on-rails-3

我有这两个班.

class Article < ActiveRecord::Base
  attr_accessible :body, :issue, :name, :page, :image, :video, :brand_ids
  has_many :publications
  has_many :docs, :through => :publications
end

class Doc < ActiveRecord::Base
  attr_accessible :issue_id, :cover_id, :message, :article_ids, :user_id, :created_at, :updated_at, :issue_code, :title, :template_id
  has_many :publications, dependent: :destroy
  has_many :articles, :through => :publications, :order => 'publications.position'
  has_many :edits, dependent: :destroy
  accepts_nested_attributes_for :articles, allow_destroy: false
end
Run Code Online (Sandbox Code Playgroud)

如何编写条件语句以查看@doc.articles更新后是否已更改@doc

if @doc.articles.changed?
  ...
end
Run Code Online (Sandbox Code Playgroud)

上面给了我一个错误.我找不到正确的语法.

lur*_*ker 20

你必须检查每一个..changed?仅适用于单个记录.如果您需要检查至少一个更改的整个关联,您可以执行以下操作:

if @doc.articles.find_index {|a| a.changed?} then...
Run Code Online (Sandbox Code Playgroud)

或者您可以使用Enumerable#any?:

if @doc.articles.any? {|a| a.changed?} then...
Run Code Online (Sandbox Code Playgroud)

  • 这似乎不适用于添加或删除关联对象的情况. (6认同)
  • 如果您还想考虑添加或删除关联对象的时间,您可以执行`@ doc.articles.any?(&:更改?)|| @ doc.articles.collect(&:id).sort!= @ doc.articles.pluck(&:id).sort`.这是有效的,因为`collect`将从内存中的关联中拉出id(包括数组中的`nil`项,用于尚未保存的关联,并从数组中排除ID以获取待删除的关联),同时`pluck `从数据库中提取ID(相反,排除尚未保存的关联ID,包括待删除的关联ID). (4认同)
  • 有没有办法检测@ person.task_ids_changed?我想检测_ids数组是否发生变化. (3认同)
  • 将 has_many 添加到列表中的情况如何?这是一个变化,但会以这种方式检测到吗? (2认同)
  • 你也可以把它写成`@ doc.articles.any?(&:changed?)` (2认同)

aka*_*ick 10

使用after_addafter_remove关联回调检查添加/删除以及使用saved_changes?检查现有文章的任何更改。

class Doc < ActiveRecord::Base
  has_many :articles, after_add: :set_article_flag, after_remove: :set_article_flag

  after_save :do_something_with_changed_articles

  private

  def set_article_flag
    @articles_changed = true
  end

  def do_something_with_changed_articles
    if @articles_changed || articles.any?(&:saved_changes?)
      # do something
    end
  end
end
Run Code Online (Sandbox Code Playgroud)


Seb*_*gge 7

有点晚了,但对于正在寻找类似解决方案的其他人,您可以通过以下方式检测关系中的更改(也包括has_and_belongs_to_many):

class Article < ActiveRecord::Base
  attr_accessible :body, :issue, :name, :page, :image, :video, :brand_ids
  has_many :publications
  has_many :docs, :through => :publications
end

class Doc < ActiveRecord::Base
  attr_accessible :issue_id, :cover_id, :message, :article_ids, :user_id, :created_at, :updated_at, :issue_code, :title, :template_id
  has_many :publications, dependent: :destroy
  has_many :articles, :through => :publications, :order => 'publications.position'
  has_many :edits, dependent: :destroy
  accepts_nested_attributes_for :articles, allow_destroy: false

  after_initialize :initialize_article_changes_safe

  after_save :change_articles
  after_save :initialize_article_changes

  before_add_for_articles << ->(method,owner,change) { owner.send(:on_add_article, change) }
  before_remove_for_articles << ->(method,owner,change) { owner.send(:on_remove_article, change) }

  def articles_changed?
    @article_changes[:removed].present? or @article_changes[:added].present?
  end

  private

  def on_add_article(article)
    initialize_article_changes_safe
    @article_changes[:added] << article.id
  end

  def on_remove_article(article)
    initialize_article_changes_safe
    @article_changes[:removed] << article.id
  end

  def initialize_article_changes
    @article_changes = {added: [], removed: []}
  end

  def initialize_article_changes_safe
    @article_changes = {added: [], removed: []} if @article_changes.nil?
  end

  def unchanged_article_ids
    self.article_ids - @article_changes[:added] - @article_changes[:removed]
  end

  def change_articles
    do_stuff if self.articles_changed?
    do_stuff_for_added_articles unless @article_changes[:added].nil?
    do_stuff_for_removed_articles unless @article_changes[:removed].nil?
  end
end
Run Code Online (Sandbox Code Playgroud)

这两个钩子before_add_for_NAME-OF-RELATIONbefore_remove_for_NAME-OF-RELATION添加或删除的关系时被触发.触发的函数(您不能通过名称链接函数,您必须通过lambda执行)将添加/删除的关系项的ID添加到@articel_changes哈希.保存模型后,您可以通过change_articles函数中的ID来处理对象.在它之后,@articel_changes哈希将被清除.