In a Rails application, given three models User, Article and Reviewer with the following relationships and validations:
class User < ActiveRecord::Base
has_many :articles
has_many :reviewers
end
class Reviewer < ActiveRecord::Base
belongs_to :user
belongs_to :article
end
class Article < ActiveRecord::Base
belongs_to :user
has_many :reviewers
validate :has_reviewers?
def has_reviewers?
errors.add(:base, "article must have at least one reviewer.") if self.reviewers.blank?
end
end
And the following factories using the newer DSL:
FactoryGirl.define do
factory :user do
name { (8...20).map{ ('a'..'z').to_a[rand(26)] }.join }
age { Kernel.rand(100) }
end
factory :article do
body "This is the article content"
title "This is the title"
user
after_create do |article|
article.reviewers = create_list(:user, 2)
end
end
factory :reviewer do
user
article
state { ["published","draft","rejected","archived"][Kernel.rand(4)] }
end
end
The factory to create the article doesn't work because the validation fails before the reviewers are created:
> FactoryGirl.create(:article)
ActiveRecord::RecordInvalid: Validation failed: article must have at least one reviewer.
I have made more attempts than I would like to admit trying to overcome this hurdle, but I am stuck! One idea I had was to create the reviewers like this:
factory :article do
body "This is the article content"
title "This is the title"
user
reviewers {|a| [FactoryGirl.create(:reviewer, article: a)] }
end
but in this context, the "a" is not the instance. So that doesn't work either, like it used to.
I reposted this over on the Factory Girl github page as an issue and worked my way around to the answer:
before_create do |article|
article.reviewers << FactoryGirl.build(:reviewer, article: article)
end
The key was doing it in a before_create, so the validations haven't fired yet, and making sure to push the newly created reviewer into the list of reviews on the instance being created. Thanks to Unixmonkey for responding and keeping me trying new things :)
https://github.com/thoughtbot/factory_girl/issues/369#issuecomment-5490908
factory :article do
reviewers {|a| [a.association(:reviewer)] }
end
or
factory :article do
before_create do |a|
FactoryGirl.create(:reviewer, article: a)
end
end
The new syntax is:
before(:create) do |article|
article.reviewers << FactoryGirl.build(:reviewer, article: article)
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With