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

时间:2017-05-30 15:49:10

标签: ruby-on-rails factory-bot

假设:

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

问题的背景:

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

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

1 个答案:

答案 0 :(得分:0)

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

重要:

  • 此猴子补丁仅经测试与 factory_girl 版本 4.7.0 兼容。如果您的不同,请首先确保 factory_girl-XXX / 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')