FactoryGirl: attributes_for not giving me associated attributes
Asked Answered
I

7

31

I have a Code model factory like this:

Factory.define :code do |f|
    f.value "code"
    f.association :code_type
    f.association(:codeable, :factory => :portfolio)
end

But when I test my controller with a simple test_should_create_code like this:

  test "should create code" do
    assert_difference('Code.count') do
      post :create, :code => Factory.attributes_for(:code)
    end
    assert_redirected_to code_path(assigns(:code))
  end

... the test fails. The new record is not created.

In the console, it seems that attributes_for does not return all required attributes like the create does.

rob@compy:~/dev/my_rails_app$ rails console test
Loading test environment (Rails 3.0.3)
irb(main):001:0> Factory.create(:code)
=> #<Code id: 1, code_type_id: 1, value: "code", codeable_id: 1, codeable_type: "Portfolio", created_at: "2011-02-24 10:42:20", updated_at: "2011-02-24 10:42:20">
irb(main):002:0> Factory.attributes_for(:code)
=> {:value=>"code"}

Any ideas?

Thanks,

Iowa answered 24/2, 2011 at 10:48 Comment(0)
P
23

You can try something like this:

(Factory.build :code).attributes.symbolize_keys 

Check this: http://groups.google.com/group/factory_girl/browse_thread/thread/a95071d66d97987e)

Presentiment answered 24/2, 2011 at 12:28 Comment(3)
This has the unwanted side-effect of returning timestamps, id, etc... Not really a solution for all problemsEndways
@coneybeare: there's a simple fix for that. See the solution at #10290786Patrica
Not work for me: it shows "MassAssignmentSecurity::Error: Can't mass-assign protected attributes: id, created_at, updated_at.."Laidlaw
H
10

This one doesn't return timestamps etc., only attributes that are accessible for mass assignment:

(FactoryGirl.build :position).attributes.symbolize_keys.reject { |key, value| !Position.attr_accessible[:default].collect { |attribute| attribute.to_sym }.include?(key) }

Still, it's quite ugly. I think FactoryGirl should provide something like this out of the box.

I opened a request for this here.

Heterozygous answered 11/7, 2012 at 17:53 Comment(0)
S
9

I'd suggest yet an other approach, which I think is clearer:

attr = attributes_for(:code).merge(code_type: create(:code_type))
Sequoia answered 11/9, 2012 at 12:28 Comment(1)
You can also do attributes_for(:code).merge(code_type_attributes: attributes_for(:code_type))Dichroic
A
2

heres what I end up doing...

conf = FactoryGirl.build(:conference)
post :create, {:conference => conf.attributes.slice(*conf.class.accessible_attributes) }
Atrabilious answered 9/12, 2012 at 21:9 Comment(0)
H
2

I've synthesized what others have said, in case it helps anyone else. To be consistent with the version of FactoryGirl in question, I've used Factory.build() instead of FactoryGirl.build(). Update as necessary.

def build_attributes_for(*args)
  build_object = Factory.build(*args)
  build_object.attributes.slice(*build_object.class.accessible_attributes).symbolize_keys
end

Simply call this method in place of Factory.attributes_for:

post :create, :code => build_attributes_for(:code)

The full gist (within a helper module) is here: https://gist.github.com/jlberglund/5207078

Husein answered 20/3, 2013 at 18:32 Comment(0)
G
0

In my APP/spec/controllers/pages_controllers_spec.rb I set:

let(:valid_attributes) { FactoryGirl.attributes_for(:page).merge(subject: FactoryGirl.create(:theme), user: FactoryGirl.create(:user)) } 

Because I have two models associated. This works too:

 FactoryGirl.define do
    factory :page do
       title      { Faker::Lorem.characters 12 }
       body       { Faker::Lorem.characters 38 }
       discution  false
       published  true
       tags       "linux, education, elearning"
       section   { FactoryGirl.create(:section) }
       user      { FactoryGirl.create(:user)    }                                                                                                                            
     end
  end
Gisellegish answered 14/8, 2013 at 1:48 Comment(0)
S
0

Here's another way. You probably want to omit the id, created_at and updated_at attributes.

FactoryGirl.build(:car).attributes.except('id', 'created_at', 'updated_at').symbolize_keys

Limitations:

  • It does not generate attributes for HMT and HABTM associations (as these associations are stored in a join table, not an actual attribute).
  • Association strategy in the factory must be create, as in association :user, strategy: :create. This strategy can make your factory very slow if you don't use it wisely.
Suffuse answered 3/7, 2017 at 20:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.