EzDevInfo.com

factory_girl

A library for setting up Ruby objects as test data. Open Source - thoughtbot

Using factory_girl_rails with Rspec on namespaced models

I have a web service that serves Ads to several different clients. The structure of the Ad varies between clients, and therefore, I am using namespaces for my models and controllers by the client name to differentiate between Ads. From the high level, it looks like this:

'app/models/client1/ad.rb'

class Client1::Ad < ActiveRecord::Base
  attr_accessible :title, :description
end

'app/models/client2/ad.rb'

class Client2::Ad < ActiveRecord::Base
  attr_accessible :title, :description, :source
end

In reality, these models are more complex and have associations, but that is not the point.
I am writing some unit tests using rspec-rails 2.4.0 and factory_girl_rails 1.0.1, and all of my factories work great. However, I am not able to define factories for the namespaced models. I've tried something like:

Factory.define :client1_ad, :class => Client1::Ad do |ad|
  ad.title       "software tester"  
  ad.description "Immediate opening"
end  

and

Factory.define :client2_ad, :class => Client2::Ad do |ad|
  ad.title       "software tester"  
  ad.description "Immediate opening"
  ad.source      "feed"
end

It didn't do the job. I looked around, but every single example that I saw was using non-namespaced models. Anyone have any ideas? Any input is greatly appreciated.


Source: (StackOverflow)

Using factory_girl in Rails with associations that have unique constraints. Getting duplicate errors

I'm working with a Rails 2.2 project working to update it. I'm replacing existing fixtures with factories (using factory_girl) and have had some issues. The problem is with models that represent tables with lookup data. When I create a Cart with two products that have the same product type, each created product is re-creating the same product type. This errors from a unique validation on the ProductType model.

Problem Demonstration

This is from a unit test where I create a Cart and put it together in pieces. I had to do this to get around the problem. This still demonstrates the problem though. I'll explain.

cart = Factory(:cart)
cart.cart_items = [Factory(:cart_item, 
                           :cart => cart, 
                           :product => Factory(:added_users_product)),
                   Factory(:cart_item, 
                           :cart => cart, 
                           :product => Factory(:added_profiles_product))]

The two products being added are of the same type and when each product is created it is re-creating the product type and creating duplicates.

The error that gets generated is: "ActiveRecord::RecordInvalid: Validation failed: Name has already been taken, Code has already been taken"

Workaround

The workaround for this example is to override the product type being used and pass in a specific instance so only one instance is used. The "add_product_type" is fetched early and passed in for each cart item.

cart = Factory(:cart)
prod_type = Factory(:add_product_type)   #New
cart.cart_items = [Factory(:cart_item,
                           :cart => cart,
                           :product => Factory(:added_users_product,
                                               :product_type => prod_type)), #New
                   Factory(:cart_item,
                           :cart => cart,
                           :product => Factory(:added_profiles_product,
                                               :product_type => prod_type))] #New

Question

What is the best way to use factory_girl with "pick-list" types of associations?

I'd like for the factory definition to contain everything instead of having to assemble it in the test, although I can live with it.

Background and Extra Details

factories/product.rb

# Declare ProductTypes

Factory.define :product_type do |t|
  t.name "None"
  t.code "none"
end

Factory.define :sub_product_type, :parent => :product_type do |t|
  t.name "Subscription"
  t.code "sub"
end

Factory.define :add_product_type, :parent => :product_type do |t|
  t.name "Additions"
  t.code "add"
end

# Declare Products

Factory.define :product do |p|
  p.association :product_type, :factory => :add_product_type
  #...
end

Factory.define :added_profiles_product, :parent => :product do |p|
  p.association :product_type, :factory => :add_product_type
  #...
end

Factory.define :added_users_product, :parent => :product do |p|
  p.association :product_type, :factory => :add_product_type
  #...
end

The purpose of ProductType's "code" is so the application can give special meaning to them. The ProductType model looks something like this:

class ProductType < ActiveRecord::Base
  has_many :products

  validates_presence_of :name, :code
  validates_uniqueness_of :name, :code
  #...
end

factories/cart.rb

# Define Cart Items

Factory.define :cart_item do |i|
  i.association :cart
  i.association :product, :factory => :test_product
  i.quantity 1
end

Factory.define :cart_item_sub, :parent => :cart_item do |i|
  i.association :product, :factory => :year_sub_product
end

Factory.define :cart_item_add_profiles, :parent => :cart_item do |i|
  i.association :product, :factory => :add_profiles_product
end

# Define Carts

# Define a basic cart class. No cart_items as it creates dups with lookup types.
Factory.define :cart do |c|
  c.association :account, :factory => :trial_account
end

Factory.define :cart_with_two_different_items, :parent => :cart do |o|
  o.after_build do |cart|
    cart.cart_items = [Factory(:cart_item, 
                               :cart => cart, 
                               :product => Factory(:year_sub_product)),
                       Factory(:cart_item, 
                               :cart => cart, 
                               :product => Factory(:added_profiles_product))]
  end
end

When I try to define the cart with two items of the same product type, I get the same error described above.

Factory.define :cart_with_two_add_items, :parent => :cart do |o|
  o.after_build do |cart|
    cart.cart_items = [Factory(:cart_item,
                               :cart => cart,
                               :product => Factory(:added_users_product)),
                       Factory(:cart_item,
                               :cart => cart,
                               :product => Factory(:added_profiles_product))]
  end
end

Source: (StackOverflow)

Advertisements

Why isn't factory_girl operating transactionally for me? - rows remain in database after tests

I'm trying to use factory_girl to create a "user" factory (with RSpec) however it doesn't seem to be operating transactionally and is apparently failing because of remnant data from previous tests in the test database.

Factory.define :user do |user|
  user.name                   "Joe Blow"
  user.email                  "joe@blow.com" 
  user.password               'password'
  user.password_confirmation  'password'
end

@user = Factory.create(:user)

Running the first set of tests is fine:

spec spec/ 


...
Finished in 2.758806 seconds

60 examples, 0 failures, 11 pending

All good and as expected, however running the tests again:

spec spec/ 
...
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/validations.rb:1102:in `save_without_dirty!': Validation failed: Email has already been taken (ActiveRecord::RecordInvalid)
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/dirty.rb:87:in `save_without_transactions!'
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/transactions.rb:200:in `save!'
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/connection_adapters/abstract/database_statements.rb:136:in `transaction'
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/transactions.rb:182:in `transaction'
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/transactions.rb:200:in `save!'
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/transactions.rb:208:in `rollback_active_record_state!'
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/transactions.rb:200:in `save!'
    from /Library/Ruby/Gems/1.8/gems/factory_girl-1.2.3/lib/factory_girl/proxy/create.rb:6:in `result'
    from /Library/Ruby/Gems/1.8/gems/factory_girl-1.2.3/lib/factory_girl/factory.rb:316:in `run'
    from /Library/Ruby/Gems/1.8/gems/factory_girl-1.2.3/lib/factory_girl/factory.rb:260:in `create'
    from /Users/petenixey/Rails_apps/resample/spec/controllers/users_controller_spec.rb:7
    from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/example/example_group_methods.rb:183:in `module_eval'
    from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/example/example_group_methods.rb:183:in `subclass'
    from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/example/example_group_methods.rb:55:in `describe'
    from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/example/example_group_factory.rb:31:in `create_example_group'
    from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/dsl/main.rb:28:in `describe'
    from /Users/petenixey/Rails_apps/resample/spec/controllers/users_controller_spec.rb:3
    from /Library/Ruby/Gems/1.8/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:147:in `load_without_new_constant_marking'
    from /Library/Ruby/Gems/1.8/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:147:in `load'
    from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/runner/example_group_runner.rb:15:in `load_files'
    from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/runner/example_group_runner.rb:14:in `each'
    from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/runner/example_group_runner.rb:14:in `load_files'
    from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/runner/options.rb:133:in `run_examples'
    from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/lib/spec/runner/command_line.rb:9:in `run'
    from /Library/Ruby/Gems/1.8/gems/rspec-1.3.0/bin/spec:5
    from /usr/bin/spec:19:in `load'
    from /usr/bin/spec:19

Fix attempt - use Factory.sequence

Since I have a uniqueness constraint on my email field I attempted to fix the problem by using the sequence method of factory_girl:

Factory.define :user do |user|
  user.name                   "Joe Blow"
  user.sequence(:email) {|n| "joe#{n}@blow.com" }
  user.password               'password'
  user.password_confirmation  'password'
end

I then ran

rake db:test:prepare
spec spec/
.. # running the tests once executes fine
spec spec/
.. # running them the second time produces the same set of errors as before

Users seem to remain in the database

If I look at the /db/test.sqlite3 database it seems that the row for the test user is not being rolled back from the database between tests. I thought that these tests were supposed to be transactional but they don't seem to be so for me.

This would explain why the test runs correctly the first time (and if I clear the database) but fails the second time.

Can anyone explain what I should change to ensure that the tests run transactionally?

Thank you.


Source: (StackOverflow)

How do I use factories from FactoryGirl in rails console

I am using rails console in the development environment and I want to use factories. How can I get access to them?

I have tried require "FactoryGirl" which returns

1.9.3p393 :301 > require "FactoryGirl"
LoadError: cannot load such file -- FactoryGirl

Source: (StackOverflow)

FactoryGirl: attributes_for not giving me associated attributes

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,


Source: (StackOverflow)

Extra arguments for Factory Girl

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?


Source: (StackOverflow)

Can FactoryGirl generate factories after your models have been created?

When including the factory_girl_rails gem in your dev and test blocks in Gemfile, rails will generate factories automatically when your models are generated.

Is there a way to generate factories after your models have been generated?


Source: (StackOverflow)

Factory not registered: user

I am following Michal Hartls Rails tutorial Chapter 7. I have installed the Factory girl gem. I keep getting this error when I run my test

Failures:

 1) UsersController GET 'show' should be successful
     Failure/Error: @user = FactoryGirl.create(:user)
     ArgumentError:
       Factory not registered: user
     # ./spec/controllers/users_controller_spec.rb:10:in `block (3 levels) in <top (required)>'

Finished in 0.66336 seconds 42 examples, 1 failure

Failed examples:

rspec ./spec/controllers/users_controller_spec.rb:14 # UsersController GET 'show' should be successful

Gemfile

group :test do
  gem 'autotest', '4.4.6'
  gem "autotest-growl", "~> 0.2.16"
  gem "autotest-rails", "~> 4.1.2"
  gem "rspec", "~> 2.9.0"
  gem 'rspec-rails',  '2.9.0'
  gem 'webrat', '0.7.3'
  gem "spork",  '0.9.0'
  gem 'annotate', '~> 2.4.1.beta'
  gem "factory_girl", "~> 3.2.0"
end
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
gem 'therubyracer', :platform =>

My user_controller_spec.rb is

require 'spec_helper'

describe UsersController do

  render_views

  describe "GET 'show'" do
    before(:each) do
    @user = FactoryGirl.create(:user)
    end

    it "should be successful" do
      get :show, :id => @user
      response.should be_success
    end
  end

  describe "GET 'new'" do
    it "should be successful" do
      get :new
      response.should be_success
    end

    it "should have the right title" do
      get :new
      response.should have_selector('title', :content => "Sign up")
    end
  end
end

My factories.rb is

FactoryGirl.create :user do |user|
  user.name                   "Mark Brown"
  user.email                 "mbrown@yahoo.com"
  user.password               "foobar"
  user.password_confirmation  "foobar"
end

I changed

Factory(:name)

to

FactoryGirl.create(:user)

on line 10 in my user_controller_spec.rb becuase I was getting a deprication warning. I thought that would fix it but now im just getting.

Factory not registered: user

Can someone tell me what going on?


Source: (StackOverflow)

when does factory girl create objects in db?

i am trying to simulate a session using factory girl/shoulda (it worked with fixtures but i am having problems with using factories). i have following factories (user login and email both have 'unique' validations):

Factory.define :user do |u| 
 u.login 'quentin'
 u.email 'quentin@example.com'
end

Factory.define :session_user, :class => Session do |ses| 
 ses.association :user, :factory => :user
 ses.session_id 'session_user'
end

and here's the test

class MessagesControllerTest < ActionController::TestCase

 context "normal user" do
  setup do 
   @request.session[:user_id]=Factory(:user).id
   @request.session[:session_id]=Factory(:session_user).session_id
  end

  should "be able to access new message creation" do
   get :new
   assert_response :success
  end
 end
end

but when i run "rake test:functionals", i get this test result

 1) Error: 
  test: normal user should be able to access new message creation. (MessagesControllerTest):
  ActiveRecord::RecordInvalid: Validation failed: Account name already exists!, Email already exists!

which means that record already exists in db when i am referring to it in test setup. is there something i don't understand here? does factory girl create all factories in db on startup?

rails 2.3.5/shoulda/factory girl


Source: (StackOverflow)

Populating an association with children in factory_girl

I have a model Foo that has_many 'Bar'. I have a factory_girl factory for each of these objects. The factory for Bar has an association to Foo; it will instantiate a Foo when it creates the Bar.

I'd like a Factory that creates a Foo that contains a Bar. Ideally this Bar would be created through the :bar factory, and respect the build strategy (create/build) used to create the Foo.

I know I could just call the :bar factory and then grab the Foo reference from the new Bar. I'd like to avoid this; in my test case, the important object is Foo; calling the Bar factory seems a bit circuitous. Also, I can see the need for a Foo with multiple Bars.

Is this possible in factory_girl? How do you define this relationship in the parent?


Source: (StackOverflow)

Find or create record through factory_girl association

I have a User model that belongs to a Group. Group must have unique name attribute. User factory and group factory are defined as:

Factory.define :user do |f|
  f.association :group, :factory => :group
  # ...
end

Factory.define :group do |f|
  f.name "default"
end

When the first user is created a new group is created too. When I try to create a second user it fails because it wants to create same group again.

Is there a way to tell factory_girl association method to look first for an existing record?

Note: I did try to define a method to handle this, but then I cannot use f.association. I would like to be able to use it in Cucumber scenarios like this:

Given the following user exists:
  | Email          | Group         |
  | test@email.com | Name: mygroup |

and this can only work if association is used in Factory definition.


Source: (StackOverflow)

Factory-girl create that bypasses my model validation

I am using Factory Girl to create two instances in my model/unit test for a Group. I am testing the model to check that a call to .current returns only the 'current' groups according to the expiry attribute as per below...

  describe ".current" do
    let!(:current_group) { FactoryGirl.create(:group, :expiry => Time.now + 1.week) }
    let!(:expired_group) { FactoryGirl.create(:group, :expiry => Time.now - 3.days) }

    specify { Group.current.should == [current_group] }
  end

My problem is that I've got validation in the model that checks a new groups expiry is after today's date. This raises the validation failure below.

  1) Group.current 
     Failure/Error: let!(:expired_group) { FactoryGirl.create(:group, :expiry => Time.now - 3.days) }
     ActiveRecord::RecordInvalid:
       Validation failed: Expiry is before todays date

Is there a way to forcefully create the Group or get around the validation when creating using Factory Girl?


Source: (StackOverflow)

How to set up factory in FactoryGirl with has_many association

Can someone tell me if I'm just going about the setup the wrong way?

I have the following models that have has_many.through associations:

class Listing < ActiveRecord::Base
  attr_accessible ... 

  has_many :listing_features
  has_many :features, :through => :listing_features

  validates_presence_of ...
  ...  
end


class Feature < ActiveRecord::Base
  attr_accessible ...

  validates_presence_of ...
  validates_uniqueness_of ...

  has_many :listing_features
  has_many :listings, :through => :listing_features
end


class ListingFeature < ActiveRecord::Base
  attr_accessible :feature_id, :listing_id

  belongs_to :feature  
  belongs_to :listing
end

I'm using Rails 3.1.rc4, FactoryGirl 2.0.2, factory_girl_rails 1.1.0, and rspec. Here is my basic rspec rspec sanity check for the :listing factory:

it "creates a valid listing from factory" do
  Factory(:listing).should be_valid
end

Here is Factory(:listing)

FactoryGirl.define do
  factory :listing do
    headline    'headline'
    home_desc   'this is the home description'
    association :user, :factory => :user
    association :layout, :factory => :layout
    association :features, :factory => :feature
  end
end

The :listing_feature and :feature factories are similarly setup.
If the association :features line is commented out, then all my tests pass.
When it is

association :features, :factory => :feature

the error message is undefined method 'each' for #<Feature> which I thought made sense to me because because listing.features returns an array. So I changed it to

association :features, [:factory => :feature]

and the error I get now is ArgumentError: Not registered: features Is it just not sensible to be generating factory objects this way, or what am I missing? Thanks very much for any and all input!


Source: (StackOverflow)

FactoryGirl and polymorphic associations

The design

I have a User model that belongs to a profile through a polymorphic association. The reason I chose this design can be found here. To summarize, there are many users of the application that have really different profiles.

class User < ActiveRecord::Base
  belongs_to :profile, :dependent => :destroy, :polymorphic => true
end

class Artist < ActiveRecord::Base
  has_one :user, :as => :profile
end

class Musician < ActiveRecord::Base
  has_one :user, :as => :profile
end

After choosing this design, I'm having a hard time coming up with good tests. Using FactoryGirl and RSpec, I'm not sure how to declare the association the most efficient way.

First attempt

factories.rb

Factory.define :user do |f|
  # ... attributes on the user
  # this creates a dependency on the artist factory
  f.association :profile, :factory => :artist 
end

Factory.define :artist do |a|
  # ... attributes for the artist profile
end

user_spec.rb

it "should destroy a users profile when the user is destroyed" do
  # using the class Artist seems wrong to me, what if I change my factories?
  user = Factory(:user)
  profile = user.profile
  lambda { 
    user.destroy
  }.should change(Artist, :count).by(-1)
end

Comments / other thoughts

As mentioned in the comments in the user spec, using Artist seems brittle. What if my factories change in the future?

Maybe I should use factory_girl callbacks and define an "artist user" and "musician user"? All input is appreciated.


Source: (StackOverflow)

Upgrading to devise 3.1 => getting Reset password token is invalid

Solution

Thanks to this gist form Steven Harman, I got it working. devise_mail_helpers.rb

module Features
  module MailHelpers

    def last_email
      ActionMailer::Base.deliveries[0]
    end

    # Can be used like:
    #  extract_token_from_email(:reset_password)
    def extract_token_from_email(token_name)
      mail_body = last_email.body.to_s
      mail_body[/#{token_name.to_s}_token=([^"]+)/, 1]
    end

  end
end

I added the file devise_mail_helpers.rb to the same folder as the features specs and wrote this spec.

require 'devise_mail_helpers.rb'
include Features
include MailHelpers
describe "PasswordResets" do
  it "emails user when requesting password reset" do
    user = FactoryGirl.create(:user)
    visit root_url
    find("#login_link").click
    click_link "Forgot your password?"
    fill_in "Email", :with => user.email
    click_button "Send instructions"
    current_path.should eq('/users/sign_in')
    page.should have_content("You will receive an email with instructions about how to reset your password in a few minutes.")
    last_email.to.should include(user.email)
    token = extract_token_from_email(:reset_password) # Here I call the MailHelper form above
    visit edit_password_url(reset_password_token: token)
    fill_in "user_password", :with => "foobar"
    fill_in "user_password_confirmation", :with => "foobar1"
    find('.signup_firm').find(".submit").click
    page.should have_content("Password confirmation doesn't match Password")
  end
 end

This takes care of the specs, to make it work in the browser look at Dave's answer below.

Original Question

In my rails 4 app, I've upgraded devise to 3.1 and ran rails s, then I got this:

`raise_no_secret_key': Devise.secret_key was not set. 
 Please add the following to your Devise initializer: (RuntimeError)
 config.secret_key = '--secret--'

I added the secret key to the devise initializer.

After this I get the following error when I try to reset the password

Reset password token is invalid

It seems like the token that gets sent in the email is not correct. Everything else is working. I logging in and out like a warm knife trough butter.

Update

Now I guess that it's got to be something with the encryption of the reset_password_token Here from the feature spec:

user = FactoryGirl.create(:user, 
 :reset_password_token => "something", 
 :reset_password_sent_at => 1.hour.ago)
visit edit_password_url(user, :reset_password_token => 
  user.reset_password_token)
fill_in "user_password", :with => "foobar"
click_button "Change my password"
page.should have_content("Password confirmation doesn't match Password")

the error occured is:

Failure/Error: page.should have_content
("Password confirmation doesn't match Password")        
expected to find text "Password confirmation doesn't match Password" in 
"Reset password token is invalid"

Any ideas on what I am missing?


Source: (StackOverflow)