本文介绍了FactoryGirl:为什么attributes_for 省略了一些属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在控制器测试中使用 FactoryGirl.attributes_for,如下所示:

I want to use FactoryGirl.attributes_for in controller testing, as in:

it "raise error creating a new PremiseGroup for this user" do
  expect {
    post :create, {:premise_group => FactoryGirl.attributes_for(:premise_group)}
  }.to raise_error(CanCan::AccessDenied)
end

... 但这不起作用,因为 #attributes_for 省略了 :user_id 属性.以下是 #create#attributes_for 之间的区别:

... but this doesn't work because #attributes_for omits the :user_id attribute. Here is the difference between #create and #attributes_for:

>> FactoryGirl.create(:premise_group)
=> #<PremiseGroup id: 3, name: "PremiseGroup_4", user_id: 6, is_visible: false, is_open: false)
>> FactoryGirl.attributes_for(:premise_group)
=> {:name=>"PremiseGroup_5", :is_visible=>false, :is_open=>false}

请注意,#attributes_for 中没有 :user_id.这是预期的行为吗?

Note that the :user_id is absent from #attributes_for. Is this the expected behavior?

FWIW,我的工厂文件包括 :premise_group:user:

FWIW, my factories file includes definitions for :premise_group and for :user:

FactoryGirl.define do
  ...
  factory :premise_group do
    sequence(:name) {|n| "PremiseGroup_#{n}"}
    user
    is_visible false
    is_open false
  end
  factory :user do
    ...
  end
end

推荐答案

Short Answer:

根据设计,FactoryGirl 的 attribues_for 有意省略了会触发数据库事务的内容,以便测试运行得更快.但是,如果您愿意花点时间,您可以编写一个 build_attributes 方法(如下)来为所有属性建模.

Short Answer:

By design, FactoryGirl's attribues_for intentionally omits things that would trigger a database transaction so tests will run fast. But you can can write a build_attributes method (below) to model all the attributes, if you're willing to take the time hit.

深入研究 FactoryGirl 文档,例如这个维基页面,你会发现attributes_for忽略的提及关联 - 请参阅下面的更新.作为一种解决方法,我在 FactoryGirl.build(...).attributes 周围封装了一个辅助方法,它去除了 idcreated_atupdated_at:

Digging deep into the FactoryGirl documentation, e.g. this wiki page, you will find mentions that attributes_for ignores associations -- see update below. As a workaround, I've wrapped a helper method around FactoryGirl.build(...).attributes that strips id, created_at, and updated_at:

def build_attributes(*args)
  FactoryGirl.build(*args).attributes.delete_if do |k, v|
    ["id", "created_at", "updated_at"].member?(k)
  end
end

现在:

>> build_attributes(:premise_group)
=> {"name"=>"PremiseGroup_21", "user_id"=>29, "is_visible"=>false, "is_open"=>false}

...这正是预期的结果.

... which is exactly what's expected.

吸收了 FactoryGirl 创建者的评论后,我明白了为什么 attributes_for 会忽略关联:引用关联会生成对 db 的调用,这在某些情况下会大大减慢测试速度.但是如果你需要关联,上面显示的 build_attributes 方法应该可以工作.

Having absorbed the comments from the creators of FactoryGirl, I understand why attributes_for ignores associations: referencing an association generates a call to the db which can greatly slow down tests in some cases. But if you need associations, the build_attributes approach shown above should work.

这篇关于FactoryGirl:为什么attributes_for 省略了一些属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-01 14:27