3

I have a (polymorphic) object Comment (which will be used for Vehicle and Review objects). How can I get all comments for User's Vehicles: @user.vehicles.comments? It says that method comments is undefined for ActiveRecord::Relation. Any simple way to get it working? Is it many-to-many relation: many vehicles have many comments? Or am I wrong? @user.vehicles.first.comments works properly.

Relationships between objects (not full):

User 
has_many Vehicles. 

Vehicle 
belongs_to User. 
has_many Comments (as commentable). 

Comment 
belongs_to Commentable, :polymorphic => true
sawa
  • 165,429
  • 45
  • 277
  • 381
Dmitri
  • 2,451
  • 6
  • 35
  • 55
  • Could you please add the model code about relationship between User, Vehicle, Comment ? – Adrien Coquio Nov 19 '12 at 10:14
  • User has many Vehicles. Vehicle belongs_to User. Vehicle has many Comments (as commentable). Comment belongs_to Commentable, :polymorphic => true. – Dmitri Nov 19 '12 at 10:18
  • Please edit your question to add this, it will be a lot more readable than in the comment. – Adrien Coquio Nov 19 '12 at 10:18
  • I think you are not getting the vehicle if you use user.vehicles. instead you are getting all the vehicles. – ytsejam Nov 19 '12 at 10:25
  • Of course not. I want to get all comments for all of the Vehicles, belonging to the User. – Dmitri Nov 19 '12 at 10:34
  • The problem is that `@user.vehicles` is a **collection** of vehicles and a collection doesn't have a `comments` method (an object as you pointed out does). `has_many :through` may be an option, but no one has shown how you can do that for both vehicles and reviews. Maybe this [SO post](http://stackoverflow.com/questions/1683265/activerecord-has-many-through-and-polymorphic-associations) is useful. – Mischa Nov 19 '12 at 11:12

4 Answers4

5

The comments part of it is just fine. The thing is - you are calling:

@user.vehicles.comments

Here, the vehicles is a AR relationship object which doesn't know anything about the comments. ie - @user.vehicles is the collection of vehicles for that user.

To get all comments on vehicles linked to the user, you can do this:

@user.vehicles.to_a.collect{|v| v.comments.to_a }.flatten

Which will return an array of all comments on any of the user's vehicles.

vvohra87
  • 5,594
  • 4
  • 22
  • 34
  • Yeah. Straightforward solution. I just wanted it to be prettier :)) – Dmitri Nov 19 '12 at 11:49
  • For those, who experiece the same problem: in associated object: def self.comments all.collect { |v| v.comments }.flatten end And that's pretty much it. At least it works :) – Dmitri Nov 19 '12 at 12:26
  • @Dmitri glad to help. Actually got me thinking - maybe I'll write this and submit to acts_as_taggable gem. Seems like a fairly common issue. – vvohra87 Nov 19 '12 at 12:42
  • It could be a great support for many of us. :) Also, I've slightly improved your solution, using "includes" command, thanks to "prashantsahni", to get rid of N+1 queries problem. The only thing, that confused me, though, (:include => :comments) didn't work, while includes(:comments) works like a charm. – Dmitri Nov 19 '12 at 15:42
2

Try this:

Write this in user.rb:

    has_many :comments, :through => :vehicles

Now do

 @user.comments  

It will fetch all the comments created for your vehicles

you can also fetch comments through:

    @user.vehicles(:include => :comments).collect{|v| v.comments}.flatten

But this is not the right way, in my opinion.

prashantsahni
  • 2,128
  • 19
  • 20
  • 1) I need comments not only for the Vehicles. 2) It may be wrong, but it works 100% properly. All other solutions don't work – Dmitri Nov 19 '12 at 12:32
1

I think you are try doing complex association or maybe you misunderstand about polymorphic association. It's simpler than you think. Here is associtation you should define:

User 
has_many vehicles 

Vehicle 
belongs_to user 
has_many comments, as: :commentable

Comment 
belongs_to :commentable, polymorphic: true

To get all comments of vehicle of your user, you can define a has_many :through association in User model:

User 
has_many vehicles 
has_many comments, through: :vehicles

Now you can use @user.comments to get all comments about vehicles of user.

Thanh
  • 8,219
  • 5
  • 33
  • 56
  • I need to collect comments for different objects. That's why I have it defined so and not the other way around. Using your approach I will be only gettings comments for Vehicles, and what about other objects ? (Reviews, etc ..) – Dmitri Nov 19 '12 at 10:41
  • Thank you for your support, but I still don't see why would It work. I need it to work: user.reviews.comments, @user.vehicles.comments, user..comments. Hm. – Dmitri Nov 19 '12 at 10:50
  • i have no idea now, but maybe this link can help you (or not) [polymorphic has many through](http://www.unixgods.org/~tilo/Rails/Rails_polymprphic_has_many_through_relationships.html) – Thanh Nov 19 '12 at 11:12
  • Maybe it it will. Thank you very much! – Dmitri Nov 19 '12 at 11:26
1

Try this one :

in the user model add :

has_many :comments, :through => :vehicles

Edit for vehicle and reviews :

In the user model :

has_many :comments, :through => :vehicles, :as => :comments_vehicles
has_many :comments, :through => :reviews, :as => :comments_reviews

def comments
  self.comments_vehicles + self.comments_reviews
end
Intrepidd
  • 19,772
  • 6
  • 55
  • 63