Use create_list method many times in Rails FactoryBot - ruby-on-rails

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

Related

Rails FactoryGirl pass empty string after create

I have a ruby app that I'm using rspec and factorygirl with, and I'm having trouble building a factory. Let me explain with an example:
I've got two factories which are creating registrant.user_demographic like below:
FactoryGirl.define do
factory :registrant do
first_name { "Johnny #{Faker::Name.initials}" }
(...)
after(:build) do |registrant|
registrant.user_demographic ||= build(:user_demographic, user: registrant)
end
end
end
FactoryGirl.define do
factory :user_demographic do
user { create(:registrant) }
phone "1234567890"
(...)
end
end
Now I want to have registrant without phone number sth like: registrant.user_demographic.phone == ''. I've tried with transient defined in user_demographic but it won't work:
FactoryGirl.define do
factory :registrant do
first_name { "Johnny #{Faker::Name.initials}" }
(...)
after(:build) do |registrant|
registrant.user_demographic ||= build(:user_demographic, user: registrant)
end
trait :without_phone do
after(:build) do |registrant|
registrant.user_demographic ||= build(:user_demographic, user: registrant, phone_present: false)
end
end
end
end
FactoryGirl.define do
factory :user_demographic do
(...)
transient do
phone_present { true }
end
phone { '1234567890' if phone_present }
end
end

Factory Girl + Rspec gives following error: ActionView::Template::Error: (object id) is not id value

I defined a Course >> Level >> and Step in factory girl. Step belongs to level and level belongs to course (each of them has a has_many relationship the other way).
Here is the error (I am not even sure where to start):
Failure/Error: before { visit course_level_step_path(course.id, level.id, step.id)}
ActionView::Template::Error:
0x003fe5daf528a0 is not id value
Here is my required route:
course_level_step GET /courses/:course_id/levels/:level_id/steps/:id(.:format) steps#show
Here my rspec:
describe "attempting a step" do
let(:course) { FactoryGirl.create(:course)}
let(:level) { FactoryGirl.create(:level)}
let(:step) { FactoryGirl.create(:step)}
before { sign_in user}
describe "taking a course" do
before { visit course_level_step_path(course.id, level.id, step.id)} <<< here is the problem
it "should increment the user step count" do
expect do
click_button "check answer"
end.to change(user.user_steps, :count).by(1)
end
describe "toggling the button" do
before { click_button "check answer"}
it { should have_selector('input', value: 'remove step')}
end
end
Here are my factories:
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 :course do
sequence(:title) { |n| "Ze Finance Course #{n}" }
sequence(:description) { |n| "Description for course #{n}" }
end
factory :level do
course
sequence(:title) { |n| "Ze Finance Level #{n}" }
end
factory :step do
level
sequence(:description) { |n| "Description for course #{n}" }
end
end
Any guidance on the error and how to solve it would be much appreciated.
Your error seems to be coming from the view. Can you post the code for that and the controller too? Also to save you more trouble later: this line
before { visit course_level_step_path(course.id, level.id, step.id) }
creates one step, two levels, and three courses because of the way Factory Girl works. You probably want to re-write two of your let clauses to
let(:level) { FactoryGirl.create(:level, course: course) }
let(:step) { FactoryGirl.create(:step, level: level) }

FactoryGirl: Creating dynamic factories with parameters?

I have three factories that i want to DRY up. They look like this:
factory :sequenced_stamps_by_years, class: Stamp do
...
sequence(:day_date) { |n| n.years.ago }
end
factory :sequenced_stamps_by_months, class: Stamp do
...
sequence(:day_date) { |n| n.months.ago }
end
factory :sequenced_stamps_by_weeks, class: Stamp do
...
sequence(:day_date) { |n| n.weeks.ago }
end
How can i dry this up? I want to be able to create them something like this:
FactoryGirl.create_list(:sequenced_stamps_by_x, 4, x: "weeks") ## <- So that i can decide whether I want weeks, days, years, or months ago.
Is this possible?
If you don't favor the inheritance approach, there is an alternative using a parameter. Basically:
factory :stamps do
ignore do
interval :years # possible values => :years, :months, :weeks
end
sequence(:date_date) { |n| n.send(interval).ago }
# rest of attributes here
end
Now you can do:
FactoryGirl.create(:stamps, :interval => :months)
or
FactoryGirl.create(:stamps)
which defaults to years.
All this you can find in Factory Girl transient attributes
Factories can inherit from other factories. Therefore you can do something like:
factory :stamps do
# common attributes here
.....
factory: sequenced_stamps_by_years do
sequence(:day_date) { |n| n.years.ago }
end
factory: sequenced_stamps_by_months do
sequence(:day_date) { |n| n.months.ago }
end
factory: sequenced_stamps_by_weeks do
sequence(:day_date) { |n| n.weeks.ago }
end
end

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.

Factory Girl - Why are Records being continually created?

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)

Resources