I have two ActiveRecord models User and posts. This is my user model.
class User < ActiveRecord::Base
has_many :posts
end
and this is my Post model.
class Post < ActiveRecord::Base
belongs_to :user
after_initialize :set_name
private
def set_name
self.name = "Post #{self.user.posts.count + 1}"
end
end
all this is working fine but when I write my factories
FactoryGirl.define do
factory :post do
content 'blah blah'
user
end
factory :user do
name 'Dummy name'
end
end
and this is my post_spec.rb file
require 'rails_helper'
RSpec.describe Post do
context 'with valid values' do
it 'should be valid' do
expect(build(:post)).to be_valid
end
end
end
and my test case fails saying that
undefined method posts for nil class in set_name
I don't know where I'm going wrong.
patkoperwas is correct, you're attempting to initialize a Post before you have an associated User object, which your after_initialize demands exist first. If you must use after_initialize, you could create a factory that creates a User before creating a Post and build with that instead.
FactoryGirl.define do
factory :user do
name "blah blah"
factory :user_with_posts do
transient do
post_count = 1
end
after(:create) do |user, evaluator|
evaluator.post_count.times do
create :post, user: user
end
end
end
end
end
I don't believe there is before(:build) functionality built into FactoryGirl. So you can't really use a callback to create a User before building your Post object. I would either create a user_with_post or explicitly create a user and pass it in when you create a post object.
RSpec.describe Post do
context 'with valid values' do
it 'should be valid' do
user = FactoryGirl.create :user_with_posts
post = user.posts.first
expect(post).to be_valid
end
end
You need to configure that association https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md#associations
FactoryGirl.define do
factory :user do
name 'Dummy name'
end
factory :post do
content 'blah blah'
association :user
end
end
If you create a post using the factory without a user, FactoryGirl will create the user for you, if you create the user before and pass it when creating a post, FactoryGirl will use the user you provided.
You can use with_initialize
in your Post factory like this:
factory :post do
content 'blah blah'
user
initialize_with { new(user: user) }
end
The reason for the issue is described in the factory_bot docs: https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md#custom-construction
For maximum compatibility with ActiveRecord, the default initializer builds all instances by calling new on your build class without any arguments. It then calls attribute writer methods to assign all the attribute values.
This is why the Post factory doesn't have the associated User within the after_initialize
hook.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.