我有一个接受invoice
及其嵌套items
的模型:
class Invoice < ActiveRecord::Base
belongs_to :user
has_many :items
attr_accessible :number, :date, :recipient, :project_id, :items_attributes
accepts_nested_attributes_for :items, :reject_if => :all_blank
end
我觉得用RSpec和FactoryGirl测试这个很困难。这就是我所拥有的:
describe 'POST #create' do
context "with valid attributes" do
it "saves the new invoice in the database" do
expect {
post :create, invoice: attributes_for(:invoice), items_attributes: [ attributes_for(:item), attributes_for(:item) ]
}.to change(Invoice, :count).by(1)
end
end
end
这是我在控制器中的创建操作:
def create
@invoice = current_user.invoices.build(params[:invoice])
if @invoice.save
flash[:success] = "Invoice created."
redirect_to invoices_path
else
render :new
end
end
每当我运行此操作时,都会收到错误:Can't mass-assign protected attributes: items
有人可以帮我解决这个问题吗?
...谢谢
答案 0 :(得分:3)
首先:items
是嵌套的,所以它们在params中的名称是items_attributes
。改变它。
第二:嵌套意味着......嵌套!
基本上,替换:
post :create, invoice: attributes_for(:invoice, items: [ build(:item), build(:item) ])
使用:
post :create, invoice: { attributes_for(:invoice).merge(items_attributes: [ attributes_for(:item), attributes_for(:item) ]) }
SideNote,你在这里做一个真正的集成测试,你可以存根来保持单元测试。
答案 1 :(得分:1)
我遇到了同样的问题所以我创建了一个补丁,它将FactoryGirl.nested_attributes_for方法添加到FactoryGirl:
module FactoryGirl
def self.nested_attributes_for(factory_sym)
attrs = FactoryGirl.attributes_for(factory_sym)
factory = FactoryGirl.factories[factory_sym]
factory.associations.names.each do |sym|
attrs["#{sym}_attributes"] = FactoryGirl.attributes_for sym
end
return attrs
end
end
所以现在你可以打电话:
post :create, invoice: FactoryGirl.nested_attributes_for(:invoice) }
你将获得所有嵌套形式的善良,你知道并喜欢:)
(要应用补丁,您需要将我的答案顶部的代码复制到config / initializers文件夹中的新文件中)