如何在工厂类中将参数传递到 FactoryGirl 的 'build()' 或 'create()' 中



给定:

FactoryGirl.define do
factory :user do
name ''
email ''
after(:build) do |user, evaluator|
# is there any way to get the following returned result?
puts some_code_that_will_return_the_arguments_passed    
# => {name: 'Foo', email: 'foobar@example.com'}
end
end
end
FactoryGirl.build(:user, name: 'Foo', email: 'foobar@example.com')

我的解决方法:

FactoryGirl.define do
factory :user do
transient do
build_from []
end
name ''
email ''
after(:build) do |user, evaluator|
puts evaluator.build_from.map{|attribute| [attribute, user[attribute]] }.to_h
# => {name: 'Foo', email: 'foobar@example.com'}
end
end
end
FactoryGirl.build(:user, name: 'Foo', email: 'foobar@example.com', build_from: [:name, :email])
  • 上述解决方法有效,但我不想走这条路线,因为它需要在从工厂构建或创建记录时将所有传递的属性写入build_from

问题背景:

我需要知道参数才能创建一个"有效"用户对象,方法是根据传递的参数更改另一个用户属性值,
  • 如果传递了另一组参数,则该用户属性值会相应地更改为"有效"。问题的实际范围比这个简单的例子要复杂得多,但这就是为什么我想让我的问题尽可能简单和直接。

不幸的是,我无法从官方文档或互联网上的任何内容中找到任何内容。

在检查factory_girl源代码并阅读文档后,我找不到任何公共 API 来访问参数,因此我编写了自己的"安全"猴子补丁。

重要:

  • 此猴子补丁仅经过测试factory_girl与版本4.7.0兼容。如果你的不同,首先确保在factory_girl-X.X.X/lib/factory_girl/evaluator.rb中找到的def initialize完全相同(除了猴子修补的修改)

解决方法:

  • 创建一个新文件:config/initializers/factory_girl_patch.rb,其中包含以下内容:

    require 'factory_girl/evaluator'
    module FactoryGirl
    class Evaluator
    attr_reader :overrides_arguments # MONKEY-PATCH: ADDED LINE
    def initialize(build_strategy, overrides = {})
    # MONKEY-PATCH-START: ADDED LINES
    monkey_patch_tested_version = '4.7.0'
    if Gem.loaded_specs['factory_girl'].version.version != monkey_patch_tested_version
    raise "This monkey-patched code is only tested on #{monkey_patch_tested_version}. Verify source code differences with your version first by inspecting lib/factory_girl/evaluator.rb file."
    end
    @overrides_arguments = overrides.clone # WHAT WE NEED
    # MONKEY-PATCH-END
    @build_strategy = build_strategy
    @overrides = overrides
    @cached_attributes = overrides
    @instance = nil
    @overrides.each do |name, value|
    singleton_class.define_attribute(name) { value }
    end
    end
    end
    end
    

用法:

FactoryGirl.define do
factory :user do
name ''
email ''
after(:build) do |user, evaluator|
puts evaluator.overrides_arguments
# => {name: 'Foo', email: 'foobar@example.com'}
end
end
end
FactoryGirl.build(:user, name: 'Foo', email: 'foobar@example.com')

相关内容

最新更新