Question

I am using rolify with a User model and a Task model (Rails 4). One of the roles a user can have is "owner." I want to use Factory Girl to create a user object and assign it a role. Here is my factory:

FactoryGirl.define do

  factory :task do  
    owner "Steve"
    agency "an agency"
    facility "a facility"
    description "This task must absolutely be done"
    due_date "2013-12-22 03:57:37"
    completed_date "2013-12-22 03:57:37"

    factory :task_with_owner do
      ignore do
        user_id nil
      end

      after(:create) do |task, user_id|
        User.find(user_id).add_role :owner, task
      end
    end 
  end
end

This spec passes:

  it 'is capable of creating a valid object with owner' do
    @user = create(:user)
    task = create(:task_with_owner, user_id: @user.id)
    expect(@user.has_role? :owner, task).to be_true
  end

This spec fails:

  it 'is capable of creating two valid objects with an owner' do
    @user = create(:user, username: 'janeblow')
    task = create(:task_with_owner, user_id: @user.id)
    expect(@user.has_role? :owner, task).to be_true
    task = create(:task_with_owner, user_id: @user.id)
    expect(@user.has_role? :owner, task).to be_true
  end

The error is:

Failure/Error: task = create(:task_with_owner, user_id: @user.id)                                   
ActiveRecord::RecordNotFound:                                                                       
  Couldn't find User with id=#<#<Class:0x000000050f5e10>:0x00000004c9ed08>                          
 # ./spec/factories/tasks.rb:19:in `block (4 levels) in <top (required)>'                            
 # ./spec/models/role_spec.rb:15:in `block (2 levels) in <top (required)>'

Why?

Was it helpful?

Solution

Your after(:create) block looks a little wrong. Try changing it to the following:

after(:create) do |task, vars|
  User.find(vars.user_id).add_role :owner, task
end

Then re-run your failing spec.

Because you told the factory to ignore the user_id being passed in and to use nil instead, in your after(:create) block you have to access it from the passed in attributes (in the second block argument, vars in this case). You were almost there, but were passing the object factory_girl uses to hold the attributes rather than the attribute itself from within that object.

See the Transient Attributes section here for another example - https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top