这个简单的例子使用DataMapper的before :save
回调(又名钩子)来递增callback_count
。 callback_count初始化为0,应该通过回调设置为1.
通过以下方式创建TestObject时调用此回调:
TestObject.create()
但是FactoryGirl通过以下方式创建了回调:
FactoryGirl.create(:test_object)
知道为什么吗? [注意:我正在运行ruby 1.9.3,factory_girl 4.2.0,data_mapper 1.2.0]
详细信息如下......
# file: models/test_model.rb
class TestModel
include DataMapper::Resource
property :id, Serial
property :callback_count, Integer, :default => 0
before :save do
self.callback_count += 1
end
end
# file: spec/factories.rb
FactoryGirl.define do
factory :test_model do
end
end
# file: spec/models/test_model_spec.rb
require 'spec_helper'
describe "TestModel Model" do
it 'calls before :save using TestModel.create' do
test_model = TestModel.create
test_model.callback_count.should == 1
end
it 'fails to call before :save using FactoryGirl.create' do
test_model = FactoryGirl.create(:test_model)
test_model.callback_count.should == 1
end
end
Failures:
1) TestModel Model fails to call before :save using FactoryGirl.create
Failure/Error: test_model.callback_count.should == 1
expected: 1
got: 0 (using ==)
# ./spec/models/test_model_spec.rb:10:in `block (2 levels) in <top (required)>'
Finished in 0.00534 seconds
2 examples, 1 failure
答案 0 :(得分:3)
至少对于factory_girl 4.2
(不知道从哪个版本支持它),通过使用custom methods to persist objects还有另一个工作变暖。正如a response to an issue about it in Github中所述,只需要调用save
而不是save!
。
FactoryGirl.define do
to_create do |instance|
if !instance.save
raise "Save failed for #{instance.class}"
end
end
end
当然它并不理想,因为它应该在FactoryGirl核心中起作用,但我认为现在它是最好的解决方案,而且目前我没有与其他测试发生冲突......
需要注意的是,你必须在每个工厂定义它(但对我来说这不是一个不方便)
答案 1 :(得分:1)
解决。
@Jim Stewart把我指向this FactoryGirl issue,它说“FactoryGirl在它创建的实例上调用save!”。在DataMapper的世界中,save!
明确表示不运行回调 - 这解释了我所看到的行为。 (但它没有解释为什么它适用于@enthrops!)
同一个链接提供了一些专门针对DataMapper的解决方法,我可能会选择其中一个。如果未修改的FactoryGirl与DataMapper一起玩得很好,那就太好了。
以下是思想机器人Joshua Clayton建议的代码。我将其添加到我的spec/factories.rb
文件中,test_model_spec.rb
现在无错误地传递。凉豆。
# file: factories.rb
class CreateForDataMapper
def initialize
@default_strategy = FactoryGirl::Strategy::Create.new
end
delegate :association, to: :@default_strategy
def result(evaluation)
evaluation.singleton_class.send :define_method, :create do |instance|
instance.save ||
raise(instance.errors.send(:errors).map{|attr,errors| "- #{attr}: #{errors}" }.join("\n"))
end
@default_strategy.result(evaluation)
end
end
FactoryGirl.register_strategy(:create, CreateForDataMapper)
好。也许我说得太早了。添加CreateForDataMapper修复了一个特定的测试,但似乎打破了其他测试。所以我现在没有回答我的问题。其他人有一个很好的解决方案吗?
答案 2 :(得分:1)
使用build构建对象,然后手动调用save ...
t = build(:test_model)
t.save