为什么我的after_save回调会阻止我的ActiveRecord关联正确保存?

时间:2013-03-05 10:31:34

标签: ruby-on-rails activerecord associations

当我发表评论after_save时,我的ActiveRecord协会工作得很好。在Rails控制台中,您会看到:

> @report = Report.create :name => "foo"
=> #<Report id: 9, name: "foo", created_at: "2013-03-05 09:51:55", updated_at: "2013-03-05 09:51:55"> 
> @question = @report.questions.create :description => "bar"
=> #<Question id: 18, standard_id: nil, description: "bar", element_id: nil, condition_id: nil, blueprint_name: nil, blueprint_url: nil, created_at: "2013-03-05 09:52:32", updated_at: "2013-03-05 09:52:32", additive: false, instructions: nil> 
> @report.questions
=> [#<Question id: 18, standard_id: nil, description: "bar", element_id: nil, condition_id: nil, blueprint_name: nil, blueprint_url: nil, created_at: "2013-03-05 09:52:32", updated_at: "2013-03-05 09:52:32", additive: false, instructions: nil>] 
> @question.reports
=> [#<Report id: 9, name: "foo", created_at: "2013-03-05 09:51:55", updated_at: "2013-03-05 09:51:55">]

但是,当我将以下after_save回调添加到question.rb时,关联会停止工作:

  def create_matching_surveys
    self.reports.each do |report|
      report.reviews.each do |review|
        review.competitors.each do |competitor|
          competitor.surveys.find_or_create_by_question_id(self.id)
        end
      end
    end
  end

然后,在Rails控制台中,您将获得:

> @report = Report.create :name => "foo"
=> #<Report id: 13, name: "foo", created_at: "2013-03-05 10:20:51", updated_at: "2013-03-05 10:20:51">
> @question = @report.questions.create :description => "bar"
=> #<Question id: 24, standard_id: nil, description: "bar", element_id: nil, condition_id: nil, blueprint_name: nil, blueprint_url: nil, created_at: "2013-03-05 10:21:02", updated_at: "2013-03-05 10:21:02", additive: false, instructions: nil> 
> @report.questions
=> [#<Question id: 24, standard_id: nil, description: "bar", element_id: nil, condition_id: nil, blueprint_name: nil, blueprint_url: nil, created_at: "2013-03-05 10:21:02", updated_at: "2013-03-05 10:21:02", additive: false, instructions: nil>] 
> @question.reports
=> [] 

无论报告是否包含有竞争对手的评论,都会发生这种情况。

奇怪的是我认为回调是在问题被保存后发生的?因此,通过权利,协会应该在任何这种情况发生之前保存,对吗?

我该如何解决?

更新

我想我必须在对象的生命周期中的正确位置调用回调,但我找不到那个位置。这就是为什么我这么想:

> @report = Report.create :name => "foo"
=> #<Report id: 20, name: "foo", created_at: "2013-03-05 12:29:35", updated_at: "2013-03-05 12:29:35"> 
> @question = @report.questions.create :description => "bar"
=> #<Question id: 31, standard_id: nil, description: "bar", element_id: nil, condition_id: nil, blueprint_name: nil, blueprint_url: nil, created_at: "2013-03-05 12:30:14", updated_at: "2013-03-05 12:30:14", additive: false, instructions: nil> 
> @question.reports
 => [] 
> @question.update_attributes :description => "foo"
=> true 
> @question.reports
=> [#<Report id: 20, name: "foo", created_at: "2013-03-05 12:29:35", updated_at: "2013-03-05 12:29:35">] 

BTW,该方法现在位于question_observer.rb:

class QuestionObserver < ActiveRecord::Observer

  def after_save(model)
    model.reload
    model.reports.reload
    model.reports.each do |report|
      report.reviews.each do |review|
        review.competitors.each do |competitor|
          competitor.surveys.find_or_create_by_question_id(model.id)
        end
      end
    end
    return true
  end

end

1 个答案:

答案 0 :(得分:0)

答案是使用一个名为after_commit的简洁的新回调钩子,它是在Rails 3中引入的。

请参阅http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html#method-i-after_commit

唯一的问题是after_commit无法通过交易固定装置“开箱即用”,但有很多解决方案,我发现这个对我有用:https://supportbee.com/devblog/2012/01/14/testing-after_commitafter_transaction-with-rspec/