Ruby-on-rails 工厂女孩在构建/创建时将参数传递给模型定义

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17967947/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 22:27:00  来源:igfitidea点击:

factory girl passing arguments to model definition on build/create

ruby-on-railsrubyfactory-botrspec-rails

提问by Furqan Asghar

models/message.rb

模型/消息.rb

class Message

  attr_reader :bundle_id, :order_id, :order_number, :event

  def initialize(message)
    hash = message
    @bundle_id = hash[:payload][:bundle_id]
    @order_id  = hash[:payload][:order_id]
    @order_number = hash[:payload][:order_number]
    @event = hash[:concern]
  end
end

spec/models/message_spec.rb

规格/模型/message_spec.rb

require 'spec_helper'

describe Message do
  it 'should save the payload' do
    payload = {:payload=>{:order_id=>138251, :order_number=>"AW116554416"}, :concern=>"order_create"}
    message = FactoryGirl.build(:message, {:payload=>{:order_id=>138251, :order_number=>"AW116554416"}, :concern=>"order_create"})
    message.event.should == "order_create"
  end
end

error_log

错误日志

Failures:

失败:

1) Message should save the payload

1) 消息应保存有效载荷

 Failure/Error: message = FactoryGirl.build(:message, {:payload=>{:order_id=>138251, :order_number=>"AW116554416"}, :concern=>"order_create"})
 ArgumentError:
   wrong number of arguments (0 for 1)
 # ./app/models/message.rb:4:in `initialize'
 # ./spec/models/message_spec.rb:7:in `block (2 levels) in <top (required)>'

回答by cryo28

FactoryGirl requires you to define factory first. Let's say in a file spec/factories/messages.rb:

FactoryGirl 要求您首先定义工厂。让我们在文件 spec/factories/messages.rb 中说:

FactoryGirl.define do
  factory :message do
    bundle_id 1
    order_id 2
    ...etc...
  end
end

After this you'll be able to invoke factory build create like this:

在此之后,您将能够像这样调用 factory build create:

FactoryGirl.build(:message)  # => bundle_id == 1, order_id == 2
FactoryGirl.build(:message, order_id: 3) # => bundle_id == 1, order_id == 3

However, there is one problem in your particular case. FactoryGirl's default builders operate on top of ActiveRecord-alike interface. It sets defined attributes through setters, not through a hash of attrs passed to the model constructor:

但是,在您的特定情况下存在一个问题。FactoryGirl 的默认构建器在类似 ActiveRecord 的界面上运行。它通过 setter 设置定义的属性,而不是通过传递给模型构造函数的属性哈希:

m = Message.new
m.bundle_id = 1
m.order_id  = 2

So you have to create a custom constructor to work with the interface of your model (which doesn't conform to ActiveRecord-alike model) and register it in your factory definition. See factory girl docsfor details.

因此,您必须创建一个自定义构造函数来处理模型的接口(不符合 ActiveRecord 类似模型)并将其注册到您的工厂定义中。有关详细信息,请参阅工厂女孩文档

Let me show you an example of doing so. Sorry I didn't test it but it should give you a clue:

让我向你展示一个这样做的例子。对不起,我没有测试它,但它应该给你一个线索:

FactoryGirl.define do
  factory :message do
    ignore do
      # need to make all attributes transient to avoid FactoryGirl calling setters after object initialization
      bundle_id 1
      order_id 2
    end

    initialize_with do
      new(payload: attributes)
    end
  end
end

回答by Mikey Hogarth

It's because you have a constructor with mandatory arguments. You have a few options;

这是因为您有一个带有强制参数的构造函数。你有几个选择;

1) Make the argument non-mandatory (although this would mean you're changing your code to suit your tests - naughty!)

1)使参数成为非强制性的(尽管这意味着您正在更改代码以适合您的测试 - 顽皮!)

def initialize(message = nil)

2) Use the "initialize_with" syntax in your factory;

2)在你的工厂中使用“initialize_with”语法;

describe Message do
  it 'should save the payload' do
    payload = {:payload=>{:order_id=>138251, :order_number=>"AW116554416"},   :concern=>"order_create"}
    message = FactoryGirl.build(:message, {:payload=>{:order_id=>138251, :order_number=>"AW116554416"}, :concern=>"order_create"})
    message.event.should == "order_create"
  end

  initialize_with { new(message) }
end