Factorygirl Admin Creation - ruby-on-rails

I am following Michael Hartl's online tutorial and in Listing 9.42, I am having trouble comprehending the code.
FactoryGirl.define do
factory :user do
sequence(:name) { |n| "Person #{n}" }
sequence(:email) { |n| "person_#{n}#example.com"}
password "foobar"
password_confirmation "foobar"
factory :admin do
admin true
end
end
end
Then admin is created in listing 9.43
describe "as an admin user" do
let(:admin) { FactoryGirl.create(:admin) }
What I don't understand is how that is possible to create an admin without any
code of
sequence(:name) { |n| "Person #{n}" }
sequence(:email) { |n| "person_#{n}#example.com"}
password "foobar"
password_confirmation "foobar"
inside the admin block?
It seems :admin block is nested inside :user block and so the :user block code is executed during FactoryGirl.create(:admin) creating an admin with users name, email, password inside the :user block?
Is that right?
Thank you!

Assuming you already know how FactoryGirl library works, the explanation to your question is that the :admin factory is defined inside the :user factory
FactoryGirl.define do
factory :user do
...
factory :admin do
admin true
end
end
end
In this case, :admin will inherit all the properties of the user, plus the specific admin: true setting.
FactoryGirl.create(:admin)

Yes, that is correct. When you create a nested FactoryGirl object, that object inherits all attributes of its parent.

Related

Nested factory girl with nested attributes in Rails

There are 2 factories (using FactoryGirl):
FactoryGirl.define do
factory :owner do
name 'Some name'
email 'test#gmail.com'
phone '89020000000'
password '123456'
password_confirmation '123456'
role
end
end
And roles:
FactoryGirl.define do
factory :role do
description 'Owner'
end
factory :superuser_role do
description 'Superuser'
end
end
I want to add a :superuser factory that has the same fields as :owner except role. How can I do it? Thanks.
I think this will work
FactoryGirl.define do
factory :owner do
name 'Some name'
email 'test#gmail.com'
phone '89020000000'
password '123456'
password_confirmation '123456'
role
factory :superuser do
association :role, factory: :superuser_role
end
end
end

how to create a factory for a relationship between two users

I want create a factory for a Relationship model which contains two attributes followed_id and follower_id but i have no idea how to do this, this is my factories file :
FactoryGirl.define do
factory :user do
sequence(:name) { |n| "Person #{n}" }
sequence(:email) { |n| "person_#{n}#example.com"}
password "foobar"
password_confirmation "foobar"
end
factory :relationship do
# i need something like this
# followed_id a_user.id
# follower_id another_user.id
end
end
update
what i want to do with this relationship factory is to test that if i destroy a user, all his relationships will be destroyed too, this is my test :
describe "relationships associations" do
let!(:relationship) { FactoryGirl.create(:relationship) }
it "should destroy associated relationships" do
relationships = #user.relationships.to_a
#user.destroy
expect(relationships).not_to be_empty
relationships.each do |relationship|
expect(Relationships.where(id: relationship.id)).to be_empty
end
end
end
In my experience such "relationship" factory is rarely needed in test. Instead, "user_with_followers" and "user_following_some_ones" are often used.
factory :user do
sequence(:name) { |n| "Person #{n}" }
sequence(:email) { |n| "person_#{n}#example.com"}
password "foobar"
password_confirmation "foobar"
factory :user_with_followers do
ignore do
followers_count 5
end
after_create do |user, evaluator|
followers = FactoryGirl.create_list(:user, evaluator.followers_count)
followers.each do |follower|
follower.follow(user) # Suppose you have a "follow()" method in User
end
end
factory :user_following_some_ones do
# Do the similar
end
end
# Use
FactoryGirl.create :user_with_followers
use association
factory :relationship do |r| # 'r' is how you call relationship in the block
...
r.association :followed #relationship is associated with followed user
#(i'm not sure how your application is set up,
#so you'll have to do this as best makes sense.
#is followed an attribute of user?
#then it would look like `r.association :user`
f.association :follower #same here
end
In the more recent versions of FactoryGirl, you should be able to do this:
factory :relationship do
association :followed, :factory => :user
association :follower, :factory => :user
end
What each of those two association lines does is set up a user instance (using your :user factory), and then assign to followed or follower of the current relationship instance.
Note that you need to specify the factory unless the association name and factory name are the same.
Update:
When creating the Relationship, specify :followed or :follower (whichever is applicable to you). Otherwise, it creates new user records for each of those and uses them.
FactoryGirl.create(:relationship, :followed => #user)

is there a problem with the way I set up factory girl

I'm following micheal hartl rails tutorial. I'm on chapter 10. is there something wrong with the way I've define the cotent part in factory girl .
I'm getting this error from factory girl when I'm calling rspec .
Failure/Error: FactoryGirl.create(:micropost, user: #user, created_at: 1.day.ago)
NoMethodError:
undefined method `content=' for #<User:0x0000010343f018>
factories.rb
FactoryGirl.define do
factory :user do
sequence(:name) { |n| "Person #{n}" }
sequence(:email) { |n| "person_#{n}#example.com" }
password "foobar"
password_confirmation "foobar"
factory :admin do
admin true
end
factory :micropost do
content "Lorem ipsum "
#association :user
user
end
end
end
the part that's been called
before { #user.save }
let!(:older_micropost ) do
FactoryGirl.create(:micropost, user: #user, created_at: 1.day.ago)
end
let!(:newer_micropost) do
FactoryGirl.create(:micropost, user: #user, created_at: 1.hour.ago)
end
it " should have the right micropost in the right order" do
#user.microposts.should == [newer_micropost, older_micropost]
end
Get factory :micropost out of factory :user, otherwise it will consider the content as an attribute of user.
This should work:
FactoryGirl.define do
factory :user do
sequence(:name) { |n| "Person #{n}" }
sequence(:email) { |n| "person_#{n}#example.com" }
password "foobar"
password_confirmation "foobar"
factory :admin do
admin true
end
end
factory :micropost do
content "Lorem ipsum "
association :user
end
end

Where do I confirm user created with FactoryGirl?

Using rails, devise, rspec & factorygirl:
Trying to create some tests for my site. I'm using the confirmable model for devise so when I create a user using FactoryGirl, the user isn't confirmed.
This is my factories.rb:
FactoryGirl.define do
factory :user do
full_name "Aren Admin"
email "aren#example.com"
password "arenaren"
password_confirmation "arenaren"
role_id ADMIN
end
end
And this is my rspec test file:
require 'spec_helper'
describe "Admin pages" do
subject { page }
describe "home page" do
let(:user) { FactoryGirl.create(:user) }
before { visit admin_home_path }
it { should have_content("#{ROLE_TYPES[user.role_id]}") }
end
end
I'm getting an error because the user is not confirmed. By searching around I'm pretty sure I need to use the method 'confirm!' and that it belongs in the factories.rb file, but I'm not sure where to put it.
You could also set the confirmed_at attribute as follows. Works for me:
FactoryGirl.define do
factory :user do
full_name "Aren Admin"
email "aren#example.com"
password "arenaren"
password_confirmation "arenaren"
role_id ADMIN
confirmed_at Time.now
end
end
Better yet, do the following (then you don't need to create a before filter for every test suite)
Factory.define :confirmed_user, :parent => :user do |f|
f.after_create { |user| user.confirm! }
end
found here:
https://stackoverflow.com/a/4770075/1153149
Edit to add non-deprecated syntax
FactoryGirl.define do |f|
#Other factory definitions
factory :confirmed_user, :parent => :user do
after_create { |user| user.confirm! }
end
end
Edit 01/27 To Update Syntax Again
FactoryGirl.define do
#Other factory definitions
factory :confirmed_user, :parent => :user do
after(:create) { |user| user.confirm! }
end
end
Try user.confirm! in your before block
found here
This is the factory that worked for me
FactoryGirl.define do
factory :user do
sequence :email do |n|
"address#{n}#example.com"
end
sequence :password do |n|
"password#{n}"
end
factory :confirmed_user do
before(:create) {|user| user.skip_confirmation! }
end
end
end
Put the Devise confirmable logic in the after(:build) callback...
FactoryGirl.define do
factory :user do
after(:build) do |u|
u.confirm!
u.skip_confirmation_notification!
end
...
end
For me, putting confirm! or skip_confirmation! in the after(:create) block caused validation errors on the email parameter and did not work.
Add this line to your User factory definition:
before(:create) { |user| user.skip_confirmation! }
You should call skip_confirmation! before create so this is persisted on the user.
before(:create) do |user|
user.skip_confirmation!
end
2023
Does not work:
before(:create, &:skip_confirmation!)
Works:
after(:build, &:skip_confirmation!)

has_one relation with validates_presence_of and the latest factory_girl

I am facing the same problem as the question here. The post is quite outdated. I was wondering how to do the same thing. My factory is:
FactoryGirl.define do
factory :user do
sequence(:email) {|n| "email#{n}#factory.com" }
password "foobar"
password_confirmation { |u| u.password }
profile
end
end
But FactoryGirl.create(:user) fails because of a validation error in the profile model with the user being blank.
What I would do is to use the after_create. This ensures it only creates profile after it creates user.
factory :user do
sequence(:email) {|n| "email#{n}#factory.com" }
password "foobar"
password_confirmation { |u| u.password }
after_create do |user|
FactoryGirl.create(:profile, :user => user)
end
end
You can call Factory(:user) afterward.

Resources