Reputation: 7866
I am using the Rolify gem in a Rails 4.2 application.
I am using seed data in the factory which works. However, from what I have read, that's not the correct way to do it.
I'm having trouble getting my head around how to do so correctly without having to use complex factory calls in my spec files.
Here is my Employee factory:
require 'faker'
#Seed the database before running the tests only if in test mode
#Fixes problem with rake routes running this command and deleting out the database
Rails.application.load_seed if Rails.env.test?
FactoryGirl.define do
factory :employee do
first_name { Faker::Name.first_name}
last_name { Faker::Name.last_name}
sequence(:email) { |n| "peterjohnson#{n}@example.com" }
mobile 66816927867
bio "MyText"
address { Faker::Address.street_address}
province_state { Faker::Address.state}
country { Faker::Address.country}
postal_code { Faker::Address.postcode}
status :active
bachelor_degree "B.Sc"
password Faker::Internet.password(8)
sequence(:paypal_email) { |n| "paypal_peterJohnson#{n}@example.com" }
sequence(:skype_id) {|n| "peterjohnson_skype#{n}" }
os :mac
role_ids [Role.first.id]
trait :proofreader do
after(:create) {|employee| employee.add_role(:proofreader)}
end
trait :admin do
after(:create) {|employee| employee.add_role(:admin)}
end
trait :super_admin do
after(:create) {|employee| employee.add_role(:super_admin)}
end
end
end
I need to have the roles created before the Employee so that I can save their IDs in the Employee model.
In my application Roles are added via a form when an employee is registered. So I can't do an after create to add the role for some of the tests.
If I create the roles within the Employee factory as follows:
factory :employee do
["proofreader", "admin", "super_admin"].each do |role|
FactoryGirl.create(:role, name: role)
end
first_name { Faker::Name.first_name}
...
I get an error telling me that it can't find the factory named role. It exists as follows:
FactoryGirl.define do
factory :role do
name :proofreader
end
end
Here is my Employee model which validates that an Employee must have a role:
class Employee < ActiveRecord::Base
# returns the full name of the employee. This code is found in a concern called name.rb
include Name
rolify
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
enum status: [:active, :vacation, :unemployed]
enum os: [:mac, :windows]
validates :first_name,
presence: true,
length: {minimum: 2}
validates :last_name,
presence: true,
length: {minimum: 2}
validates :email, email: true, presence: true, uniqueness: true
validates :paypal_email, email: true, presence: true, uniqueness: true
validates :skype_id, presence: true, uniqueness: true
validates :mobile, presence: true, numericality: true, length: {minimum: 10}
validates :address, :province_state, :country, :postal_code, :bachelor_degree, :os,:status, :role_ids, presence: true
end
So how can I create the Employee with a role without seeding the database?
Upvotes: 1
Views: 137
Reputation: 37657
You're attempting to FactoryGirl.create(:role)
when factory_girl reads the :employee
factory definition. The :employee
factory is in employee.rb
and the :role
factory is in role.rb
(or something like that), and factory_girl probably reads factory definitions in alphabetical order by file name, so when :employee
is defined :role
doesn't exist yet.
You need to create all roles when the test runs, after all factories have been defined.
In the :employee
factory, change how you initialize role_ids
:
role_ids { [(Role.first || FactoryGirl.create(:role, name: :default)).id] }
(Actually you should just be able to set roles
instead of role_ids
so you don't have to call .id
on the default role.)
Then add the additional role in a callback in a trait:
trait :proofreader do
after(:create) do |employee|
FactoryGirl.create :role, name: :proofreader
employee.add_role(:proofreader)
end
end
However, assuming your roles don't change except when your application code also changes, I'd use seeds. It would be a lot simpler, and I don't know why it would be incorrect. I've done it with seeds on several projects and it works well.
Upvotes: 1