如何在工厂内将参数传递给 FactoryGirl 的 `build()` 或 `create()` class
How to get the arguments passed into FactoryGirl's `build()` or `create()` within the factory class
鉴于:
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])
- 上面的解决方法有效,但我不想走这条路,因为它需要在从 Factory 构建或创建记录时将所有传递的属性写入
build_from
。
问题背景:
- 我需要知道参数才能创建 "valid" 用户对象,方法是根据传递的参数更改另一个用户属性值,如果传递了另一组参数,则该用户-属性值相应更改为 "valid"。问题的实际范围比这个简单的例子要复杂得多,但这就是为什么我想让我的问题尽可能简单和直接。
不幸的是,我无法从官方文档或互联网上找到任何内容。
在检查 factory_girl 源代码并阅读文档后,我找不到任何 public API 来访问参数, 因此我写了自己的 "safe" monkey-patch.
重要提示:
- 此 monkey-patch 仅经过测试与 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')
鉴于:
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])
- 上面的解决方法有效,但我不想走这条路,因为它需要在从 Factory 构建或创建记录时将所有传递的属性写入
build_from
。
问题背景:
- 我需要知道参数才能创建 "valid" 用户对象,方法是根据传递的参数更改另一个用户属性值,如果传递了另一组参数,则该用户-属性值相应更改为 "valid"。问题的实际范围比这个简单的例子要复杂得多,但这就是为什么我想让我的问题尽可能简单和直接。
不幸的是,我无法从官方文档或互联网上找到任何内容。
在检查 factory_girl 源代码并阅读文档后,我找不到任何 public API 来访问参数, 因此我写了自己的 "safe" monkey-patch.
重要提示:
- 此 monkey-patch 仅经过测试与 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')