Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to define polymorphic association with factory girl/bot

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

like image 997
gilsilas Avatar asked Aug 07 '12 16:08

gilsilas


2 Answers

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.

like image 136
jordanpg Avatar answered Nov 12 '22 04:11

jordanpg


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
like image 35
richardsonae Avatar answered Nov 12 '22 06:11

richardsonae