class Program < ActiveRecord::Base
has_many :contacts
class Contact < ActiveRecord::Base
belongs_to :program
FactoryGirl.define do
factory :contact do
sequence(....
...
program_id 1 #foreign key
program #association
(byebug) contact
Contact id: 949, display_name: "Contact-3", business_phone: "1234567894", fax_number: "1234567894", created_at: "2017-03-05 00:43:24", updated_at: "2017-03-05 00:43:24", first_name: "First-4", last_name: "Last-4", middle_initial: "4", email: "Email4#Something.Com", program_id: 1193, 287g: nil, active: true, call_office_id: 4
The program_id is 1193 in the contact record created with the contact factory but the program table has only four records with ids 1-4. Not sure where 1193 originates from. At this point the rspec test more or less succeeds. But once the validation code below gets added to the contact model the rspec test fails.
Contact Model with Association Validation Added For Program
class ProgramValidator < ActiveModel::Validator
def validate(record)
if record.program.nil?
record.errors[:base] << "Program cannot be blank"
end
end
end
class Contact < ActiveRecord::Base
belongs_to :program
validates_with ProgramValidator
Running rspec now it complains that "Program cannot be blank". Question: how can the contact factory get created to satisfy the validation? Why are associations so friggin difficult, much harder than creating the associations in ROR. Thanks for reading.
According to Factory Girl's documentation try something like:
factory :contact do
# ...
association :program, factory: :program
end
For more ifnromation about Factory Girl's associations please follow the link:
https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md#associations
This:
FactoryGirl.define do
program #association
creates new Program record, which is attached as association (with some other id, which can be also 1193 or any other id).
If you don't want any new program record to be created, just leave program_id 1 only in your factory class. Also, remember that you run your tests in empty database.
This factory class definition will work if you create Program record, for example, before your test suite and specify explicitly its ID as 1.
Related
I have 3 following models like this:
# model/timeline.rb
class Timeline
belongs_to :series
belongs_to :creator
end
def series_belongs_to_creator
if creator_id
creator = Creator.find_by id: creator_id
related_series = creator.series.find_by id: series_id
errors.add(:series_id, :not_found_series) unless related_series
end
end
# model/creator.rb
class Creator
has_many :timelines
has_many :series, through: :contents
end
# model/series.rb
class Series
has_many :timelines
has_many :creators, through: :contents
end
This is not many to many relation, timelines table has two fields creator_id and series_id beside another fields. creator_id and series_id must be entered when create Timeline and i have a method series_belongs_to_creator to validates series_id must belong to creator_id to create successful.
So how should I write factory for timeline model if using FactoryGirl. Im so confused about Unit test in Rails.
If you're using Rails 5, you have to keep in mind that belongs_to is no longer optional by default: https://blog.bigbinary.com/2016/02/15/rails-5-makes-belong-to-association-required-by-default.html
So creator_id will always need to be present unless you specify the relation is optional.
For the factories, you're going to end up with something like this (FactoryGirl was recently renamed to FactoryBot):
http://www.rubydoc.info/gems/factory_bot/file/GETTING_STARTED.md#Associations
FactoryBot.define do
factory :timeline do
creator
series
end
end
FactoryBot.define do
factory :creator do
...
end
end
FactoryBot.define do
factory :series do
...
end
end
The issue I'm having is specific to a relationship with a belongs_to and has_many where the has_many relationship has a requirement of at least one association. This requirement is causing my Factories to fail my model level validation and not be created.
My Group model
Group < ActiveRecord::Base
has_many :organizations, dependent: nullify
# commenting out the following line will make the tests pass
validates :organizations, presence: true
...
end
The Organization model
Organization < ActiveRecord::Base
belongs_to :group
...
end
Organization Factory
FactoryGirl.define do
factory :organization
name "test organization"
end
end
And finally the problem child:
Group Factory
FactoryGirl.define do
factory :group do
name "test group"
after(:create) do |group|
create(:organization, group: group)
end
end
end
and in my test, I declare the factory instance:
describe "something happens with a Group" do
let(:group) { FactoryGirl.create :group }
it "should work" do
...
end
end
The errors my tests return are varied, but generally all point to FactoryGirl being unable to create an instance of the Group factory. e.g.
# when a test relies on creating an instance of 'Group'
ActiveRecord::RecordInvalid:
Validation failed: Organizations can't be blank
The method I'm using (callback) to create my Group factory is from this Thoughtbot post https://robots.thoughtbot.com/aint-no-calla-back-girl
There are many similar posts, but all of them that I've found as well as the Thoughtbot documentation don't mention this specific use case. Thanks in advance.
How about something like
FactoryGirl.define do
factory :group do
name 'test group'
organizations { [association(:organization)] }
end
end
The main idea is to build the needed objects before saving them. You may also try build_list if you need more.
I have a typical requirement, I have to address user object as follows
user.referrer and user.referrers.
Basically, user can refer more than one person and one person should be referred by one particular user. So I build associations as follows. They are working great.
class User < ActiveRecord::Base
attr_accessible :account_number, :display_name, :referrer_id
has_many :referrers, :class_name => "User", :foreign_key => "referrer_id"
belongs_to :referrer, :class_name => "User"
end
Now I would like to test assoications in Rspec. I am using factory girl so any one help me to build factories.
I tried as follows but end up with an errors
factory :user do
gender :male
name "super test"
.....
.....
factory :referrer do
end
association :referrer
end
You need to build two factories here, one for user with a referrer and second one for user without a referer - otherwise you'll end up in the infinite creation loop. You might use traits for this:
factory :user do
gender :male
name "super test"
trait :with_referrer do
association :referrer, factory: :user
end
end
FactoryGirl.create(:user, :with_referrer)
I have model Student, which has_one :account.
All input-related data is stored inside of account. Student model just plays it's role when it comes to relations (some other models belong to student).
Problem: I can't test it with factory girl.
factory :student do
end
As I can't define anything besides it.
What I get on every attempt of #student = FactoryGirl.create(:student):
undefined method `valid?' for nil:NilClass
Any fixes?
Additional code
class Account < ActiveRecord::Base
belongs_to :account_holder, :polymorphic => true
...
end
factory :account do
sequence :name do |n|
"Name#{n}"
end
sequence :surname do |n|
"Surname#{n}"
end
sequence :phone do |n|
"8911222332#{n}"
end
sequence :email do |n|
"somemail#{n}#mail.ru"
end
student
end
Source of issue
Student has:
validates_associated_extended :account
which is basically usual validate but with error extraction for parent model.
So when FactoryGirl attempts to create student, it validates account, which is nil.
I tried this:
before(:create) {|student| build(:account, :account_holder =>student )}
in student factory, while in account factory:
association :account_holder, :factory=>:student
But it still doesn't work.
factory :student do
after :build do |student|
student.account << create(:account, :account_holder => student) if student.account_holder.nil?
end
end
This allows you to have both a valid student and to specify an account if you want to force one.
I think latest versions of FactoryGirl even allow that to be written as lazy attribute syntax:
factory :student do
account { create(:account) }
end
I'm learning about associations and I'm having trouble testing my associations using RSpec, shoulda-matchers and FactoryGirl.
I have a Game model who's instances must belong_to a manufacturer, so I'm using a presence validation.
Manufactures can have more than one game associated to them so there is a has_many games relationship from the manufacturer's point of view. Also, I want to ensure that a manufacturer is only created if it is associated with a game (through validation) (I don't want to track any manufacturer that does not have any games associated with it).
Here is the code:
class Game < ActiveRecord::Base
belongs_to :manufacturer
validates :name, presence: {message: 'The game name is required'}
validates :description, presence: {message: 'A short game description is required'}
validates :manufacturer, presence: true
end
class Manufacturer < ActiveRecord::Base
has_many :games
validates :name, presence: {message: 'The manufacturer name is required and must be unique'}
validates :name, uniqueness: {message: 'A manufacturer by this name already exits.'}, if: "name.present?"
validates :games, presence: { message: 'Every manufacturer must be associated with at least one game.' }
end
So as you can see both validate each other, so there will be no games without manufacturer and no manufacturers without games.
I'm having a hard time trying to create a Factory using FactoryGirl to create a valid manufacturer instance for testing.
How can I create the manufacturer factory and the games factory in order to have a valid Factory where I can test the associations using shoulda-matchers?
(the DB is properly set up with the columns for foreign keys and ids)
EDIT
I have tried the following without luck...
TRY 1
FactoryGirl.define do
factory :game do
name "Space Invaders"
description "Space Invaders was one of the early blockbuster shooting games."
release_date '1978'
association :manufacturer, strategy: :build
end
end
FactoryGirl.define do
factory :manufacturer do
name 'Atari'
games {create_list(:game, 1)}
end
end
Error:
/Users/mymac/.rvm/gems/ruby-2.1.5#sr-arcade-nomad/bin/ruby_executable_hooks:15: stack level too deep (SystemStackError)
TRY 2
FactoryGirl.define do
factory :game do
name 'Space Invaders'
description "Space Invaders was one of the early blockbuster shooting games."
manufacturer 'Atari'
end
end
FactoryGirl.define do
factory :manufacturer do
name 'Atari'
games {create_list(:game, 1)}
end
end
Error:
.../gems/activerecord-4.1.1/lib/active_record/associations/association.rb:216:in `raise_on_type_mismatch!': Manufacturer(#70244044131760) expected, got String(#70244001467180) (ActiveRecord::AssociationTypeMismatch)
Try the following code:
factory :game do
name
description
manufactor
end
factory :manufacturer do
name
games { create_list(:game, 1) }
end
I'm looking for a solution with which I can easily override the games association. If that's no concern in this case, you can use an after build hook:
factory :manufacturer do
…
after(:build) do |m|
m.games << build(:game, manufacturer: m)
end
end
The problem with overriding is "kind of solved" if you put that after(:build) in a trait, but then build(:manufacturer) is no longer valid. So still no ideal but nevertheless a working factory.
Then again, this situation with circular presence validation is not ideal to start with. The only way in Rails to do this (the Rails way) is with a nested form. You will then create nested objects with params like { name: … , games_attributes: {1 => {<attributes for game 1}, …}. You probably should build the factory like with games_attributes too then. Other cases are just not possible:
game = Game.new …
manufacturer = Manufacturer.new …
Now save them (nested) with those validations in place …, one will have to go first …