How to define polymorphic association with factory girl/bot
Asked Answered
H

2

14

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

Honewort answered 7/8, 2012 at 16:3 Comment(2)
You can also find solutions to this question here: #7748445Progression
i see all replies suggest using 2 factories or factory with traits - seems we can't make factory with polymorphic association then (makes sense tho)Sarmatia
K
16

First of all, I don't think you're quite done setting up your associations... I think this is what you want:

class Comment < AR
  belongs_to :commentable, polymorphic: true
end

class User < AR
  has_many :comments, as: :commentable
end

class Story < AR
  has_many :comments, as: :commentable
end

See: http://guides.rubyonrails.org/association_basics.html#polymorphic-associations

Don't forget the DB setup.

Second, the Factory Setup is returning two Users because you're telling it to. Try:

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 }
    association :commentable, factory: :user
  end

end

As a matter of style, the choice of model names is a little confusing here. How is a User "commentable"? If you mean some other kind of writing, I would choose a different name. Ditto if you mean "user profile" or something along those lines.

Kress answered 7/8, 2012 at 16:34 Comment(1)
Ok, but the point is, how I associate one user object to two belongs to association? I want to add the same commendable user to user attribute in the comment class.Honewort
E
8

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
Espinal answered 12/1, 2018 at 2:15 Comment(2)
I think your factory :post should be factory :story.Transition
:facepalm: You're totally right @Ritchie . Thanks for pointing that out! I just fixed it.Espinal

© 2022 - 2024 — McMap. All rights reserved.