我的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
答案 0 :(得分: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个月,所以可能会有更多知识渊博的人不同意我的风格建议。
答案 1 :(得分: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)
应该希望模拟从表单中传入的参数。