【问题标题】:Rails: ActiveRecord associations saving issueRails:ActiveRecord 关联保存问题
【发布时间】:2013-03-13 22:41:57
【问题描述】:

在保存 ActiveRecord 关联时遇到问题,需要您的帮助 :)

我需要将文章合并功能添加到遗留代码。

预计其工作方式如下:

  1. 将“源”文章的文本合并到“目标”文章。
  2. 检查“源”的 cmets,如果有,将它们重新关联到“目标”。
  3. 销毁“源”条目。注释应保留并与“目标”相关联。

这是我的文章模型代码(为便于阅读而减少)。

class Article < Content

  before_destroy :reload_associated_comments

  has_many :comments,   :dependent => :destroy, :order => "created_at ASC" do

  def reload_associated_comments
    unless self.comments.empty?
      article = Article.find(@merge_with)
      self.comments.each do |comment|
        comment.article = article
        article.save!
      end
    end
  end

  def merge_with(id)
    @merge_with = id
    article = Article.find(@merge_with)
    if !article.nil?
      text = article.body + body
      article.body = text
      article.save!
      self.destroy
      return article
    end
    nil
  end
end

这里是评论模型(也减少了):

class Comment < Feedback
  belongs_to :article
end

问题是当我从 before_destroy 钩子返回时,没有任何东西保存到数据库中。我通过以下方式检查:

eval Article.find(target_article_id).comments

保存不会引发异常。我在这里缺少什么?

提前致谢!

这对我有用

  def merge_with(id)
    @merge_with = id
    article = Article.find(@merge_with)
    unless article.nil?
      text = article.body + body
      article.body = text
      article.save!
      reload_associated_comments
      self.reload
      self.destroy
      return article
    end
    nil
  end

【问题讨论】:

  • 在reload_associated_cmets那个方法中,应该是comment.save!而不是article.save!我认为:)
  • 我也不确定,但我认为你不能在 self 调用的方法中调用 self.destroy。退回文章,然后从外部销毁(调用merge_with 方法)
  • reload_associated_comments 方法用作before_destroy 回调。如果我调用article.save!,是不是表示cmets会自动保存?如果没有,正确的保存顺序是什么。评论然后文章,反之亦然?
  • 1.对于第二条评论->我的错误,当您调用destroy时,它会从数据库中销毁它,并且不会销毁对象本身。 2.你可以只做comment.save,因为它将文章的ID保存在评论中。我认为用 article.save 来做是无效的,因为你没有修改文章。亲爱的天哪,我希望我告诉你正确的事情:)
  • 好点。我会尝试从外面拨打destroy。虽然不知道会打扰selfobject 本身。

标签: ruby-on-rails database associations rails-activerecord legacy-code


【解决方案1】:

实际上,Rails 在为文章调用 before_destroy 回调之前会销毁所有评论。可悲的是,rails 就是这样工作的。更改此行为将意味着破坏旧版应用程序。您可以在此处找到有关此问题的更多信息:https://github.com/rails/rails/issues/670

在我看来,最好的解决方案是重写 destroy 方法并去掉回调:

class Article < Content

  def destroy
    reload_associated_comments
    super
  end

  has_many :comments,   :dependent => :destroy, :order => "created_at ASC" do

  def reload_associated_comments
    unless self.comments.empty?
      article = Article.find(@merge_with)
      self.comments.each do |comment|
        comment.article = article
        comment.save!
      end
    end
  end

  def merge_with(id)
    @merge_with = id
    article = Article.find(@merge_with)
    if !article.nil?
      text = article.body + body
      article.body = text
      article.save!
      self.destroy
      return article
    end
    nil
  end
end

另外,正如@Zippie 提到的,您应该调用comment.save! 而不是article.save!

希望对你有帮助!

【讨论】:

  • 哇,好棒的答案! alfonso,你不会说reload_associated_comments 方法中的article.save! 不对吗?不应该是comment.save!如果它是正确的,它是如何正确的?当我们将.save! 放在一个对象上时,它会影响它的所有子对象吗?
  • 我真的很高兴,因为如果我不是,ActiveRecord 会吓坏我的! :)
  • 真的很酷!非常感谢你们两位,伙计们!坦率地说,回调在这里并不是最好的解决方案。只是用来玩回调))
  • 不幸的是,发现即使使用@alfonso 提供的解决方案也无法正常工作。但它与self.reload 一起工作得很好,最后我设法将关联的 cmets 保存到目标文章中。不过,再次感谢各位!你帮了我很多!
猜你喜欢
  • 2020-11-14
  • 2012-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多