rails/rails — pull request #15892 by jamesyang124 (2014-06-24 08:49:56+00:00)
Title: fix polymorphic relation call exists? #15821.

After explore the differences for `JoinAssociation#join_constraints` between rails 4.2.0 alpha and 4.1.2.rc2, I find the method returns `JoinInformation` structure which carry a `bind_values` array and does not directly substitute the dynamic parameter holders `(?)` of sql statement anymore.

```ruby
# rails 4.1.2.rc2
# /active_record/associations/join_dependency/join_association.rb
def join_constraints(foreign_table, foreign_klass, node, join_type, tables, scope_chain, chain)
#...
if reflection.type
constraint = constraint.and table[reflection.type].eq foreign_klass.base_class.name
end

joins
end

# result
# Post Load (0.1ms) SELECT "posts".* FROM "posts" INNER JOIN "slugs" ON
"slugs"."sluggable_id" = "posts"."id" AND "slugs"."sluggable_type" = 'Post'
WHERE "slugs"."name" = 'the-slug'

# rails 4.2.0 alpha
# /active_record/associations/join_dependency/join_association.rb
def join_constraints(foreign_table, foreign_klass, node, join_type, tables, scope_chain, chain)
#...
if reflection.type
# ...
substitute = klass.connection.substitute_at(column, bind_values.length)
bind_values.push [column, value]
constraint = constraint.and table[reflection.type].eq substitute
end

JoinInformation.new joins, bind_values
end

# result
Post Load (0.1ms) SELECT "posts".* FROM "posts" INNER JOIN "slugs" ON
"slugs"."sluggable_id" = "posts"."id" AND "slugs"."sluggable_type" = ?
WHERE "slugs"."name" = 'the-slug' [[nil, "Post"]]
```

It turns out to fix [issue_15821](https://github.com/rails/rails/issues/15821) in a general way is to prepend `relation.arel.bind_values` to `binds` from `DatabaseStatements#binds_from_relation`.

```ruby
# /active_record/relation/finder_methods.rb
def exists?(conditions = :none)
connection.select_value(relation, "#{name} Exists", relation.bind_values) ? true : false
end

# /active_record/connection_adapters/abstract/database_statements.rb
def select_value(arel, name = nil, binds = [])
# select_one method then call binds_from_relation
if result = select_one(arel, name, binds)
result.values.first
end
end

def binds_from_relation(relation, binds)
if relation.is_a?(Relation) && binds.blank?
# should prepend relation.arel.bind_values to binds
relation, binds = relation.arel, relation.bind_values
end
[relation, binds]
end
```

I try to solve this few days ago, the first commit in [pull request 15861](https://github.com/rails/rails/pull/15861) only fix `FinderMethods#exists?`. Eventually I think put the modification on `DatabaseStatements#binds_from_relation` will better. This help lower level methods `#select_values` and `#select_all` to transform the `ActiveRecord::Relation` to `Arel` with correct binds.