user1099123
user1099123

Reputation: 6673

How do I achieve polymorphic relationships that reference a user?

First, I have a polymorphic association setup because comments can belong to any object(in my case post and articles).

I want to be able to say:

u = user.first
u.comments #This will list all comments from a user
u.comments.where(:commentable_type => "Post")  

This above line doesn't work. it generates a sql: SELECT "comments".* FROM "comments" WHERE "comments"."commentable_id" = 1 AND "comments"."commentable_type" = 'User' AND "comments"."commentable_type" = 'Post'

obviously this would return an empty list because a comment can't belong to 2 types. I also want to be able to say:

f = Food.first
f.comments.first.user #give me the user that posted the first comment

Here's my basic model... any tips on changing this?

class Comment < ActiveRecord::Base
  belongs_to :commentable, :polymorphic => true
end

class Post < ActiveRecord::Base
  has_many :comments, :as => :commentable
end

class Article < ActiveRecord::Base
  has_many :comments, :as => :commentable
end

class User < ActiveRecord::Base
    has_many :comments, :as => :commentable
end

Upvotes: 1

Views: 121

Answers (2)

likethesky
likethesky

Reputation: 846

You should be able to do the following to achieve what you want:

u.comments.map { |cmt| Post.find(cmt.commentable) }

and likewise for Article. This returns an array of posts or articles. It'll give an error if they don't exist, so you'll have to modify it for that.

I don't totally understand your second question. If f.comments.first returns you just one comment, then .user should return you the user for that comment, assuming you have the classes User and Comment set-up correctly (with User has_many comments / Comment belongs_to user, as Alexandre Abreu points out), but maybe I'm misunderstanding your question.

Upvotes: 0

Alexandre Abreu
Alexandre Abreu

Reputation: 1417

I think you should review your comment model, it should look like:

class Comment < ActiveRecord::Base
  belongs_to :user
  belongs_to :commentable, :polymorphic => true
end

So you'd have two relationships, the first will point to who posted the comment, the other will point to the object being commented.

Comment.first.user # this will return the user

Comment.first.commentable # this will return the object which the comment was attached (Post, Article or ?Food?)

Dont forget the migrations if you wish to try this approach.

Upvotes: 4

Related Questions