11

このような ActiveRecord クラスがあります。

class Foo
  belongs_to :bar, autosave: true
  before_save :modify_bar
  ...
end

ログを記録すると、 が変更されていることがわかりますbarが、その変更は保存されません。どうしたの?

4

2 に答える 2

24

ここでの問題は、通常のコールバックをautosave: true設定するだけで、コールバックが作成された順序で実行されることです。**before_savebefore_save

barしたがって、変更のないを保存しようとしてから、呼び出しますmodify_bar

解決策はmodify_bar、自動保存の前にコールバックが実行されるようにすることです。

これを行う 1 つの方法は、prependオプションを使用することです。

class Foo
  belongs_to :bar, autosave: true
  before_save :modify_bar, prepend: true
  ...
end

別の方法は、before_saveステートメントを の前に置くことbelongs_toです。

barもう 1 つの方法は、メソッドの最後で明示的に保存し、オプションをまったくmodify_bar使用しないことです。autosave

役立つブログ記事を提供してくれた Danny Burkes に感謝します。

** また、すべてのafter_validationコールバックの後、コールバックの前に実行されbefore_createます - docs を参照してください


アップデート

このようなコールバックの順序を確認する 1 つの方法を次に示します。

  describe "sequence of callbacks" do

    let(:sequence_checker) { SequenceChecker.new }

    before :each do
      foo.stub(:bar).and_return(sequence_checker)
    end

    it "modifies bar before saving it" do
      # Run the before_save callbacks and halt before actually saving
      foo.run_callbacks(:save) { false }
      # Test one of the following
      #
      # If only these methods should have been called
      expect(sequence_checker.called_methods).to eq(%w[modify save])
      # If there may be other methods called in between
      expect(sequence_checker.received_in_order?('modify', 'save')).to be_true
    end

  end

このサポート クラスの使用:

class SequenceChecker
  attr_accessor :called_methods

  def initialize
    self.called_methods = []
  end

  def method_missing(method_name, *args)
    called_methods << method_name.to_s
  end

  def received_in_order?(*expected_methods)
    expected_methods.map!(&:to_s)
    called_methods & expected_methods == expected_methods
  end

end
于 2013-02-21T21:24:02.337 に答える
1

上記の答えは(明らかに)あなたの解決策です。でも:

を使用して:autosaveも問題ありませんが、外部関連付けの変更がコールバックの仕事だとは思いません。私はあなたについて話している:modify_barこの投稿で 見事に説明されているように、私は別のオブジェクトを使用して複数のモデルを一度に保存することを好みます。物事がより複雑になると、それはあなたの人生を本当に簡素化し、テストをはるかに簡単にします.

この状況では、これはコントローラーまたはサービス オブジェクトから実行される可能性があります。

于 2015-11-02T12:44:51.267 に答える