Extra arguments for Factory Girl
Asked Answered
P

5

22

I need to pass extra arguments to factory girl to be used in a callback. Something like this (but more complex really):

Factory.define :blog do |blog|
  blog.name "Blah"

  blog.after_create do |blog|
    blog.posts += sample_posts
    blog.save!
  end
end

and then create it with something like this:

Factory.create(:blog, :sample_posts => [post1, post2])

Any ideas how to do it?

Piccaninny answered 19/4, 2010 at 9:56 Comment(0)
P
32

This is now possible without any "hacks" thanks to transient attributes (see comment on issue #49)

example:

FactoryGirl.define do
  factory :user do
    transient do
      bar_extension false
    end
    name {"foo #{' bar' if bar_extension}"}
  end
end

# Factory(:user).name = "foo"
# Factory(:user, :bar_extension => true).name = "foo bar"

For Factory Girl versions < 5.0:

FactoryGirl.define do
  factory :user do
    ignore do
      bar_extension false
    end
    name {"foo #{' bar' if bar_extension}"}
  end
end

# Factory(:user).name = "foo"
# Factory(:user, :bar_extension => true).name = "foo bar"
Pichardo answered 16/2, 2012 at 3:42 Comment(1)
Useful set of docs here, including how to access a transient attribute from an after_create or other block: github.com/thoughtbot/factory_girl/blob/master/…Communicate
M
2

One option would be to create a virtual accessor for extra posts that the after_create hook checks:

class Blog
  has_many :posts
  attr_accessible :name, :title, ... # DB columns
  attr_accessor   :sample_posts      # virtual column
end

Factory.define :blog do |blog|
  blog.name 'Blah'

  blog.after_create do |b|
    b.posts += b.sample_posts
    b.save!
  end
end

Factory(:blog, :sample_posts => [post1, post2])
Mcgough answered 19/4, 2010 at 11:43 Comment(2)
For my example that would work, my real case is a little more complicated. Besides, I wouldn't like polluting models for the sake of FactoryGirl's limitations. Thanks anyway :)Piccaninny
You only need to pollute the model in your test environment. In fact, you can do it right there in factories.rb.Mcgough
P
2

Apparently, this is not possible at the moment without workarounds that require modifying the model itself. This bug is reported in: http://github.com/thoughtbot/factory_girl/issues#issue/49

Piccaninny answered 20/4, 2010 at 10:2 Comment(1)
issue #49 was closed recently, see my answerPichardo
M
1

Another option would be to use build instead of create and add :autosave to the collection:

class Blog
  has_many :posts, :autosave => true
end

Factory.define :blog do |blog|
  blog.name 'Blah'
  blog.posts { |_| [Factory.build(:post)] }
end

Factory(:blog, :posts => [post1, post2])
#or
Factory.build(:blog, :posts => [unsavedPost1, unsavedPost2])
Mcgough answered 19/4, 2010 at 16:36 Comment(0)
G
1

if you are opening the class inside the factorygirl file, i suggest doing it like

require "user"
class User
  attr :post_count
end

so that you are opening the class, instead of overwriting it

Gainey answered 20/3, 2012 at 7:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.