Search code examples
ruby-on-railsactiverecordruby-on-rails-5

Joining Nested Associations (Multiple Level)


I have the following models and relationships:

Picture of models

A User has many Offers (where he/she is the seller), an Offer has many Purchases, a Purchase has many Accbooks

Models and associations:

class User < ApplicationRecord
  has_many :offers, foreign_key: :seller_id
  has_many :purchases, foreign_key: :buyer_id
end

class Offer < ApplicationRecord
  has_many :purchases
  belongs_to :seller, class_name: 'User'
end

class Purchase < ApplicationRecord
  belongs_to :offer
  belongs_to :buyer, class_name: 'User'
  has_one :seller, through: :offer
  has_many :accbooks,  class_name: 'Admin::Accbook', foreign_key: 'purchase_id' 
end

module Admin
  class Accbook < ApplicationRecord
    belongs_to :purchase
  end
end  

I want to get all the Accbooks of any given user (as a seller). The equivalent SQL statement would look like this:

SELECT  "accbooks".* 
FROM "accbooks" 
INNER JOIN "purchases" ON "purchases"."id" = "accbooks"."purchase_id"
INNER JOIN "offers" ON "offers"."id" = "purchases"."offer_id"
INNER JOIN "users" ON "users"."id" = "offers"."seller_id"
WHERE "users"."id" = ?

So far I've tried this:

Admin::Accbook.joins( {purchase: :offer} )

Which gives me this SQL as a result:

SELECT  "accbooks".*
FROM "accbooks"
INNER JOIN "purchases" ON "purchases"."id" = "accbooks"."purchase_id"
INNER JOIN "offers" ON "offers"."id" = "purchases"."offer_id"

Now I don´t know how to add the join to the User model, and then how to add the Where condition.

Thanks for any insight.


Solution

  • You can joins the relations together and apply where clause on the joined relations:

    Admin::Accbook
      .joins(purchase: :offer)
      .where(offers: { seller_id: 123 })
    

    A thing to know, where uses the DB table's name. joins (and includes, eager_load, etc) uses the relation name. This is why we have:

    Admin::Accbook
      .joins(purchase: :offer)
      #                 ^^^^^ relation name
      .where(offers: { seller_id: 123 })
      #      ^^^^^^ table name