Tom Prats
Tom Prats

Reputation: 7911

Has Many Through two models

I have two models of importance here. There's more models interacting with them too, but only these should be relevant.

class Image < ActiveRecord::Base
  belongs_to :user
  belongs_to :trip
end

class Mission < ActiveRecord::Base
  belongs_to :user
  belongs_to :trip

  # has_many :images, through: :user
end

The commented out line gets me halfway there but I want to meet an additional condition of the image having the same Trip ID as the Mission.

  # has_many :images, through: [:user, :trip]

Using an array like some similar methods sometimes take, is invalid syntax.

   def images
     Image.where(user_id: user_id, trip_id: trip_id)
   end

Should I just do that? Or is there a better way to do it? I also tried with conditionals on the has_many but anything dynamic I put there was being called off of Image::ActiveRecord_Relation

Here are some sample records:

<User id=1>
<User id=2>
<Trip id=1>
<Trip id=2>
<Image id=1, user_id=1, trip_id=1>
<Image id=2, user_id=1, trip_id=1>
<Image id=3, user_id=1, trip_id=1>
<Mission id=1, user_id=1, trip_id=1>
<Mission id=2, user_id=2, trip_id=1>
<Mission id=3, user_id=2, trip_id=2>

So Mission.find(1).images gives back the 3 images, whereas 2 and 3 give an empty array.

Upvotes: 0

Views: 165

Answers (2)

Sanket
Sanket

Reputation: 490

I think you can try like this

class Mission < ActiveRecord::Base
    belongs_to :user
    belongs_to :trip
    has_many :images, ->(obj) { where("#{Image.quoted_table_name}.trip_id = ?", obj.trip_id)}, through: :user
    # or
    has_many :images, ->(obj) { where("#{Image.quoted_table_name}.user_id = ?", obj.trip_id)}, through: :trip
end

This obj represents the object of Mission class, so i have added the one more condition on images associations.

Mission.first.images.to_sql
#=> "SELECT \"images\".* FROM \"images\" INNER JOIN \"users\" ON \"images\".\"user_id\" = \"users\".\"id\" WHERE (\"images\".trip_id = 1) AND \"users\".\"id\" = ?"

Upvotes: 3

Tomanow
Tomanow

Reputation: 7357

A belongs_to association sets up a one-to-one connection with another model [...]

It looks like you could benefit making your image table have a mission_id instead of user_id and trip_id since then you could simply say

  • Image belongs_to Mission
  • Mission has_many Images
  • User has_many Images through Mission
  • Trip has_many Images through Mission

Upvotes: 0

Related Questions