How to define polymorphic association with factory girl/bot

Viewed 11160

I have a user and story models which both of them have comments.

I declared the following models as below:

class Comment
  belongs_to :commentable, polymorphic: true
  belongs_to :user
end

class User
end

class Story
end

Now, I want to declare a comment object with FactoryGirl that belongs to the same user as commendable and as user.

Here is my code so far:

FactoryGirl.define do
  factory :user do
    sequence(:email) {|n| "person#{n}@exmaple.com"}
    sequence(:slug) {|n| "person#{n}"}
  end

  factory :comment do    
    occured_at { 5.hours.ago }
    user
    association :commentable, factory: :user
  end

end

The problem here is that the user that write the comment and the commendable user are not the same.

Why should I fix that?

Many TNX

2 Answers

I came across this question because I personally had a similar one and just resolved it. Like @jordanpg, I am curious as to how a User is commentable. If I am understanding correctly, the problem is that the user who wrote the story and the user who wrote the comment on the story could be different users:

  • user_1 writes a story
  • user_2 (or any user) can comment on user_1's story

In order to do that, I'd set up model associations like this:

# app/models/user.rb
class User < ApplicationRecord
  has_many :stories
  has_many :comments
end

# app/models/story.rb
class Story < ApplicationRecord
  belongs_to :user
  has_many :comments, as: :commentable
end

# app/models/comment.rb
class Comment < ApplicationRecord
  belongs_to :user
  belongs_to :commentable, polymorphic: true
end

And then in my factory, it would look like this:

# spec/factories.rb
FactoryBot.define do

  factory :user do
    sequence(:email) {|n| "person#{n}@example.com"}
    sequence(:slug) {|n| "person#{n}"}
  end

  factory :story do
    body "this is the story body"
    user
  end

  factory :comment do
    body "this is a comment on a story"
    user
    association :commentable, factory: :story
  end
end

Part of why this works is because factory_bot will automatically build the parent of any child you're creating. Their docs on associations are pretty good: http://www.rubydoc.info/gems/factory_bot/file/GETTING_STARTED.md#Associations

If you need users to be able to comment on comments, you could do it like this:

  factory :comment_on_story, class: Comment do
    body "this is a comment on a story"
    user
    association :commentable, factory: :story
  end

  factory :comment_on_comment, class: Comment do
    body "this is a comment on a comment"
    user
    association :commentable, factory: :comment_on_story
  end
Related