With the latest way that joins and the where clauses work in Rails 4.2, it appears there is not a clean (using symbols...or just not using string SQL) way to join to the same table from a single query.
For instance, we have a user model, and it has a reference to a home address, and a work address. If we want to get all of the users that live and work in Indianapolis, what is the best way to go about building this query?
The ideal option would be something like this:
User.joins(:home_address).join(:work_address).
where(home_address: { city: 'Indianapolis' } ).
where(work_address: { city: 'Indianapolis' } ).count
However, the home_address and work_address (which are belongs_to associations on the User model) don't have any effect on the where clause. You have two user addresses, and obviously that is nearly good enough (since I am querying on that table twice).
Here is something that works, but just isn't as clean as the solution from above:
User.joins('INNER JOIN addresses as home_address ON home_address_id = home_address.id').
joins('INNER JOIN addresses as work_address ON work_address_id = work_address.id').
where(home_address: { city: 'Indianapolis' } ).
where(work_address: { city: 'Indianapolis' } ).count
So the point of the question is, was this intentional (in previous versions of Rails, the belongs_to association name could be referenced in the where clause)? And, if it was, is there a technique that I'm not seeing of how to clean this up without using string SQL?
To be clear, in an earlier version of Rails, the belongs_to association worked for this type of query: That used to work...in Rails 4.2 it no longer works:
irb(main):001:0> User.joins(:home_address, :work_address).where(home_address: { city: 'Indianapolis' }, work_address: { city: 'Indianapolis' }).to_sql
"SELECT \"users\".* FROM \"users\" INNER JOIN \"addresses\" ON \"addresses\".\"id\" = \"users\".\"home_address_id\" INNER JOIN \"addresses\" \"work_addresses_users\" ON \"work_addresses_users\".\"id\" = \"users\".\"work_address_id\" WHERE ((\"addresses\".\"city\" = 'Indianapolis' AND \"work_addresses_users\".\"city\" = 'Indianapolis'))"
irb(main):002:0> Rails::VERSION::STRING
"4.0.5"
irb(main):003:0>
However in the latest version of Rails, it no longer works:
[1] pry(main)> User.joins(:home_address, :work_address).
[1] pry(main)* where(home_address: { city: 'Indianapolis' }, work_address: { city: 'Indianapolis' }).count
ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR: missing FROM-clause entry for table "home_address"
LINE 1: ...ses_users"."id" = "users"."work_address_id" WHERE "home_addr...
^
: SELECT COUNT(*) FROM "users" INNER JOIN "addresses" ON "addresses"."id" = "users"."home_address_id" INNER JOIN "addresses" "work_addresses_users" ON "work_addresses_users"."id" = "users"."work_address_id" WHERE "home_address"."city" = $1 AND "work_address"."city" = $2
from /Users/ar3/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:637:in `prepare'
[2] pry(main)> Rails::VERSION::STRING
"4.2.1"
[3] pry(main)> User.last.home_address.present?
true
[4] pry(main)> User.last.work_address.present?
true
[5] pry(main)> User.joins(:home_address, :work_address).where(home_address: { city: 'Indianapolis' }, work_address: { city: 'Indianapolis' }).to_sql
"SELECT \"users\".* FROM \"users\" INNER JOIN \"addresses\" ON \"addresses\".\"id\" = \"users\".\"home_address_id\" INNER JOIN \"addresses\" \"work_addresses_users\" ON \"work_addresses_users\".\"id\" = \"users\".\"work_address_id\" WHERE \"home_address\".\"city\" = 'Indianapolis' AND \"work_address\".\"city\" = 'Indianapolis'"
[6] pry(main)>
Notice the difference in the .to_sql...one uses the alias defined by the belongs_to association, the new one, uses whatever we put in the where hash.