Skip to content

Instantly share code, notes, and snippets.

@jmwelch
Last active February 23, 2017 23:10
Show Gist options
  • Save jmwelch/ed8a008b7ab7630fae7972c1601f3eab to your computer and use it in GitHub Desktop.
Save jmwelch/ed8a008b7ab7630fae7972c1601f3eab to your computer and use it in GitHub Desktop.
Multiple Joins with Foreign Keys
class User < ApplicationRecord
has_many :created_budgets, class_name: "Budget", foreign_key: "creator_id"
has_many :client_budgets, class_name: "Budget", foreign_key: "client_id"
end
class Bugdet < ApplicationRecord
belongs_to :creator, class_name: "User"
belongs_to :client, class_name: "User"
end
# The joins clause requires the ActiveRecord name of the relation, whereas
# the where clause requires the actual reference to the table
Budget.joins(:client).where(users: { state: "active" } )
# As you can see in the second example below, using the AR name results in incorrect SQL:
Budget.joins(:client).where(users: { state: "active" } ).to_sql
# => "SELECT \"budgets\".* FROM \"budgets\" INNER JOIN \"users\" ON \"users\".\"id\" = \"budgets\".\"client_id\" WHERE \"users\".\"state\" = 'active'"
Budget.joins(:client).where(clients: { state: "active" } ).to_sql
# => "SELECT \"budgets\".* FROM \"budgets\" INNER JOIN \"users\" ON \"users\".\"id\" = \"budgets\".\"client_id\" WHERE \"clients\".\"state\" = 'active'"
# When joining on the same table twice (using different foreign keys), Rails will alias the second reference for you
# The alias will be the pluralized AR relation (`clients`) prepended to the pluralized class name of the table being joined on (`budgets`)
# e.g. `clients_budgets`
Budget.joins(:creator, :client).to_sql
# => "SELECT \"budgets\".* FROM \"budgets\" INNER JOIN \"users\" ON \"users\".\"id\" = \"budgets\".\"creator_id\" INNER JOIN \"users\" \"clients_budgets\" ON \"clients_budgets\".\"id\" = \"budgets\".\"client_id\""
# To run where queries, use the the aliased table names:
Budget.joins(:creator, :client).where(users: { state: "active" }, clients_budgets: { state: "active" } )
Budget.joins(:creator, :client).where(users: { state: "active" }, clients_budgets: { state: "active" } ).to_sql
# => "SELECT \"budgets\".* FROM \"budgets\" INNER JOIN \"users\" ON \"users\".\"id\" = \"budgets\".\"creator_id\" INNER JOIN \"users\" \"clients_budgets\" ON \"clients_budgets\".\"id\" = \"budgets\".\"client_id\" WHERE \"users\".\"state\" = 'active' AND \"clients_budgets\".\"state\" = 'active'"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment