Factory Girl - Why are Records being continually created? - ruby-on-rails

I'm new to factory girl. What I'm trying to do is create 2 users, which belong to a group, joined by the permission model. Here's what I have. When I run this one rspec, it creates more than 2 users, 4+. Why? thanks
factories.rb:
require 'factory_girl'
Factory.define :user do |f|
f.sequence(:fname) { |n| "fname#{n}" }
f.sequence(:lname) { |n| "lname#{n}" }
f.sequence(:email) { |n| "email#{n}#google.com" }
f.password "password"
f.password_confirmation { |u| u.password }
f.invitation_code "xxxxxxxx"
end
Factory.define :group do |f|
f.association :user
f.sequence(:name) { |n| "myGroup#{n}" }
f.sequence(:private_email) { |n| "myGroup#{n}" }
end
Factory.define :permission do |f|
f.role_id 1
f.user {|i| i.association(:user)}
f.group {|i| i.association(:group)}
f.creator_id {|i| i.association(:user).id}
end
incoming_mails_controller_spec.rb:
describe IncomingMailsController do
include Devise::TestHelpers
before do
#user = Factory.create(:user, :permissions => [Factory.create(:permission)])
#user2 = Factory.create(:user, :permissions => [Factory.create(:permission)])
#group = Factory(:group)
end
it "should create a new IncomingMail record in the db" do
....
end
....

This is because Factory.create(:user...) creates 1 one user (you have two of these, so thats two users right there). And creating two new Factory.create(:permissions) also creates a user by the rules you set up in your define(your associations), thus equaling 4.
If you wanted to to only create two users here, you could do
#user = Factory.create(:user)
#user1 = Factory.create(:user)
#perm1 = Factory.create(:permission, :user => #user)
#perm2 = Factory.create(:permission, :user => #user1)

Related

Use create_list method many times in Rails FactoryBot

I have two FactoryBots => user and post
And post has user_id column
FactoryBot.define do
factory :user do
sequence(:name) { |n| "user#{n}" }
end
end
FactoryBot.define do
factory :post do
sequence(:title) { |n| "title#{n}" }
sequence(:user_id) { |n| n }
end
end
I want to make 10 users, and 100 posts (10posts per each user) so i
tried .times method like this =>
10.times do
FactoryBot.define do
factory :post do
sequence(:title) { |n| "title#{n}" }
sequence(:user_id) { |n| n }
end
end
end
This not worked because of Factory already registered error
FactoryBot.define do
10.times do
factory :post do
sequence(:title) { |n| "title#{n}" }
sequence(:user_id) { |n| n }
end
end
end
This not worked too.
FactoryBot.create_list(:user, 10)
10.times do
FactoryBot.create_list(:post, 10)
end
This makes FactoryBot to make post num 11, user num 11 so foriegn key error occurs.
How can i use create_list method many times?
Just i want to make is, 10 posts per 10 users.
If you don't need to reference any of those users and/or posts afterward, then you can just 10 times create 10 posts using the same user per every 10 posts;
10.times do
create_list(:post, 10, user: create(:user))
end

method on model returning empty during rspec tests even though it should have a value

I am doing the following rspec test to test my '#clubs' method
context "#clubs" do
it "returns the users associated Clubs" do
club = create(:club)
user = club.host
expect(user.clubs).to contain(club)
end
end
The method in my User model:
class User < ActiveRecord::Base
has_many :host_clubs, :class_name => 'Club', :inverse_of => :host
has_and_belongs_to_many :volunteer_clubs, :class_name => 'Club', :inverse_of => :volunteers
def clubs
[host_clubs, volunteer_clubs].flatten
end
end
When I run the test and use p club.host, it returns the user as expected, however I cannot see why calling user.clubs => [] returns an empty array. Here is the factory for context.
factory :host, class: User do |f|
f.first_name { Faker::Name.first_name }
f.last_name { Faker::Name.last_name }
f.email { Faker::Internet.email }
f.password { Faker::Internet.password }
f.role { "host" }
f.onboarded_at { Date.today }
after(:create) do |host|
host.confirm_email_address
end
end
factory :club, class: Club do |f|
f.venue_type { "Primary school" }
f.name { Faker::Company.name }
f.address_1 { Faker::Address.street_address }
f.city { Faker::Address.city }
host
end
Can anyone give me a heads up to why it may not be returning the record?
It's worth noting that I am adding this test after the method was created. In the console the method behaves as expected.
(Making my comment as an answer with additional information)
Try user.reload before expecting the results in the test solves this issue.
This is because of club object is created independently from user. This is generally happens in rspec tests.

shoulda factory girl error Couldn't find model without an ID

Good day, i get this error from
ActiveRecord::RecordNotFound:
Couldn't find User without an ID
my model
has_many :objects, class_name: 'OrderObject', dependent: :destroy
belongs_to :user
belongs_to :tariff
validates :client, :phone, :tariff_id, :days, :user_id, presence: true
spec
before do
user = FactoryGirl.create(:user)
FactoryGirl.create(:order, user_id: user.id)
end
context "validations" do
it { should validate_presence_of :client }
it { should validate_presence_of :phone }
it { should validate_presence_of :tariff_id }
it { should validate_presence_of :days }
end
it { should have_many(:objects) }
it { should belong_to(:tariff) }
it { should belong_to(:user) }
factory
factory :order do
client "MyString"
phone "MyString"
tariff_id 1
days 1
# advt_payed_day 1
# firm_payed_day 1
user_id 1
end
UPDATE 1
changed to
before(:all) do
user = FactoryGirl.create(:user )
puts user.id
order = FactoryGirl.create(:order, user_id: user.id )
puts order.id
end
output
Order
45
32
should have many objects
should belong to tariff
should belong to user
validations
should require client to be set (FAILED - 1)
should require phone to be set (FAILED - 2)
should require tariff_id to be set (FAILED - 3)
should require days to be set (FAILED - 4)
should require user_id to be set (FAILED - 5)
so order & user are created...
Update 2
as Rubyman suggested, i've changed couple of things:
in spec
before(:all) do
user = FactoryGirl.create(:user )
#puts user.id
order = FactoryGirl.create(:order, user_id: user.id )
puts order
puts order.user_id
end
in the factory
factory :order do
client "MyString"
phone "MyString"
tariff_id 1
days 1
# user_id 1
association :user, factory: :user
end
and output is:
Order
#<Order:0x00000005a866a0>
46
should have many objects
should belong to tariff
should belong to user
validations
should require client to be set (FAILED - 1)
should require phone to be set (FAILED - 2)
should require tariff_id to be set (FAILED - 3)
should require days to be set (FAILED - 4)
should require user_id to be set (FAILED - 5)
1) Order validations
Failure/Error: it { should validate_presence_of :client }
ActiveRecord::RecordNotFound:
Couldn't find User without an ID
# ./app/models/order.rb:35:in `user_is_not_admin?'
# ./spec/models/order_spec.rb:14:in `block (3 levels) in <top (required)>'
update 3
after reading advice from tdgs here are the changes:
in model no changes :
validates :client, :phone, :tariff_id, :days, :user_id, presence: true
in spec
describe Order do
before(:each) do
user = FactoryGirl.create(:user )
#puts user.id
order = FactoryGirl.create(:order, user_id: user.id )
puts order
puts order.user_id
puts order.tariff_id
puts order.phone
puts order.days
puts order.client
puts '*****'
user = User.find(order.user_id)
puts user.login
end
context "validations" do
it { should validate_presence_of :client }
it { should validate_presence_of :phone }
it { should validate_presence_of :tariff_id }
it { should validate_presence_of :days }
it { should validate_presence_of :user_id }
end
it { should have_many(:objects) }
it { should belong_to(:tariff) }
it { should belong_to(:user) }
end
output:
#<Order:0x00000006c10ce0>
161
101
MyString
1
MyString
*****
user__7
should require days to be set (FAILED - 1)
output for every should is valid as far as i see...
UPDATE N
should have written it in the beginning. i've run (hoped that it'll solve this issue) in console
bundle exec rake db:migrate
bundle exec rake db:migrate:reset db:test:prepare
First, your factory definition is not defining associations correctly. You should have something like this:
FactoryGirl.define do
factory :user do
sequence(:username) {|n| "username_#{n}"}
# more attributes here
end
factory :tariff do
# attributes
end
factory :order do
client "MyString"
phone "MyString"
tariff
user
days 1
end
end
Then your tests should be written like this:
context "validations" do
it { should validate_presence_of :client }
it { should validate_presence_of :phone }
it { should validate_presence_of :tariff_id }
it { should validate_presence_of :days }
end
it { should have_many(:objects) }
it { should belong_to(:tariff) }
it { should belong_to(:user) }
All the code you currently have in the before filter is not relevant right now. Also notice that using before(:all) might have some strange effects when running your tests, because they do not run inside a transaction. before(:each) on the other hand does.
try this
before {
#user = FactoryGirl.create(:user, :email => "test.com", :password => "test123", ... )
#order = FactoryGirl.create(:order, :user_id => #user.id )
}
Factory
require 'factory_girl'
FactoryGirl.define do
factory :order do
client "MyString"
...
...
end
end
Check how to create associations with factory girl
https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md
i moved away from shoulda and rewrote checks for validation. This way it works:
before(:each) do
#user = FactoryGirl.create(:user )
#order = FactoryGirl.create(:order, user_id: #user.id )
end
it 'absence of client isn\'t acceptable' do
temp = #order.client
#order.client = ''
#order.should_not be_valid
#order.client = temp
#order.should be_valid
end

How can I force Forgery to return unqiue data within a Factory_girl definition

My factory looks like this:
Factory.define :coupon do |c|
c.title { Forgery(:lorem_ipsum).sentences(3, :random => true) }
end
And my call from Rspec looks like this:
coupons = []
5.times {|i| coupons << Factory(:coupon, :starts_at => i.days.ago) }
With my Coupon model I have a validation with requires the title to be unique. The only way I am able to run this test is by doing this in my factory:
Factory.define :coupon do |c|
c.title {|i| Forgery(:lorem_ipsum).sentences(3, :random => true) + "#{i}" }
end
Surely there must be a better way?
This is how I would do it (using the new Factory Girl syntax):
FactoryGirl.define do
factory :coupon do
sequence(:title) { |n| Forgery::LoremIpsum.words(n, :random => true) }
sequence(:starts_at) { |n| n.days.ago }
end
end
Then creating coupons in a spec:
coupons = FactoryGirl.create_list(:coupon, 5)

rspec with factory girl

I have the following factories:
Factory.define :producer, :class => User do |f|
f.sequence(:email) { |n| "producer_#{n}#shit.com" }
f.password "foobar"
f.password_confirmation "foobar"
f.role "producer"
end
Factory.define :business do |f|
f.sequence(:name) { |n| "business_#{n}" }
f.association(:producer, :factory => :producer)
end
Factory.define :deal do |d|
d.sequence(:title) { |n| "deal_#{n}" }
d.sequence(:desc) { |n| "deal_desc_#{n}" }
d.cap "50"
d.rate "2"
d.start Date.today - 1 # This is the date where you put in db
d.end Date.today + 7
d.association :business
end
now when I do the following:
before(:each) do
#consumer = test_sign_in(Factory(:consumer))
#deal = Factory(:deal)
end
I am getting an error:
Failure/Error: #deal = Factory(:deal)
NoMethodError:
undefined method `producer=' for #<Business:0x007fb494290090>
# ./deals_controller_spec.rb:15:in `block (4 levels) in <top (required)>
(Line 15 refers to #deal = Factory(:deal) )
Does anyone know why? I am very new to factory girl and I can't seem to find the documentation explaining association and sequence very well.
The problem here is obviously linked to the creation of your producer association.
Since you're using the old dsl, I'd suggest two solutions:
Factory.define :business do |f|
f.sequence(:name) { |n| "business_#{n}" }
#try this:
f.association(:user, :factory => :producer)
#or this:
f.after_build { |biz| biz.user = Factory.build(:producer) }
end
The use of after_build or after_create is really a matter of choice, depending on your tests purposes.
Here is a link to the new dsl lookup.

Resources