Nat*_*ong 11 ruby ruby-on-rails callback rails-activerecord
我有一个看起来像这样的ActiveRecord类.
class Foo
belongs_to :bar, autosave: true
before_save :modify_bar
...
end
Run Code Online (Sandbox Code Playgroud)
如果我做一些日志记录,我看到bar
正在修改,但它的更改不会保存.怎么了?
Nat*_*ong 24
这里的问题是autosave: true
简单地设置一个正常的before_save
回调,并且before_save
回调按照它们被创建的顺序运行.**
因此,它试图保存bar
没有变化的,然后调用modify_bar
.
解决方案是确保modify_bar
回调在自动保存之前运行.
一种方法是使用该prepend
选项.
class Foo
belongs_to :bar, autosave: true
before_save :modify_bar, prepend: true
...
end
Run Code Online (Sandbox Code Playgroud)
另一种方法是将before_save
声明置于之前belongs_to
.
另一种方法是bar
在modify_bar
方法结束时显式保存,而根本不使用该autosave
选项.
感谢Danny Burkes的有用博客文章.
**此外,它们在所有after_validation
回调之后和任何before_create
回调之前运行- 请参阅文档.
这是检查此类回调顺序的一种方法.
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
Run Code Online (Sandbox Code Playgroud)
使用此支持类:
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
Run Code Online (Sandbox Code Playgroud)