3

我有一个Invoice模型可能包含许多Items

class Invoice < ActiveRecord::Base

  attr_accessible :number, :date, :recipient, :items_attributes

  belongs_to :user

  has_many :items

  accepts_nested_attributes_for :items, :reject_if => :all_blank, :allow_destroy => true

end

我正在尝试使用 RSpec 对此进行测试:

describe InvoicesController do

  describe 'user access' do

    before :each do
      @user = FactoryGirl.create(:user)
      @invoice = @user.invoices.create(FactoryGirl.attributes_for(:invoice))
      sign_in(@user)
    end

    it "renders the :show view" do
      get :show
      expect(response).to render_template :show
    end

  end

end

不幸的是,此测试(以及所有其他测试)失败,并显示来自 RSpec 的以下错误消息:

Failure/Error: @invoice = @user.invoices.create(FactoryGirl.attributes_for(:invoice))
ActiveModel::MassAssignmentSecurity::Error:
Can't mass-assign protected attributes: items

如何创建包含将通过我的测试的项目的发票?

我正在使用 FactoryGirl 来制作这样的对象:

factory :invoice do
  number { Random.new.rand(0..1000000) }
  recipient { Faker::Name.name }
  date { Time.now.to_date }
  association :user
  items { |i| [i.association(:item)] } 
end

factory :item do
  date { Time.now.to_date }
  description { Faker::Lorem.sentences(1) }
  price 50
  quantity 2
end
4

2 回答 2

1

- 要在您的示例中使用嵌套属性,您需要传入“item_attributes”而不是像您当前正在执行的“items”。

我不精通FactoryGirl,但也许这些方面的东西会起作用?:

invoice_attributes = FactoryGirl.attributes_for(:invoice)
invoice_attributes["item_attributes"] = invoice_attributes["items"]
invoice_attributes["items"] = nil
@invoice = @user.invoices.create(invoice_attributes)

那应该有希望模拟从您的表单传入的参数。

于 2013-03-05T20:54:38.360 回答
1

编辑:误解了这个问题。道歉。

代替

before :each do
  @user = FactoryGirl.create(:user)
  @invoice = @user.invoices.create(FactoryGirl.attributes_for(:invoice))
  sign_in(@user)
end

只需为使用用户参数传递的发票创建工厂,如下所示:

before :each do
  @user = FactoryGirl.create(:user)
  FactoryGirl.create :invoice, user: @user
  sign_in(@user)
end

此外,这是一个次要的样式建议,但您可以使用 let 代替实例变量,如下所示:

let(:user) { FactoryGirl.create :user }

before :each do
  FactoryGirl.create :invoice, user: user
  sign_in(user)
end

将“用户”传递给发票创建也将创建用户(并且可以简单地调用“用户”)。

小警告:我已经这样做了大约 6 个月,所以可能会有更博学的人不同意我的风格建议。

于 2013-03-05T19:19:32.960 回答