rails/rails — pull request #15077 by nbudin (2014-05-12 21:41:53+00:00)
Title: ActiveRecord::Relation::Merger#filter_binds doesn't account for Symbol/String equality

I ran into this when attempting to upgrade a large, complex, very old Rails application from Rails 3.2 to 4.0, but it appears to also be a problem in 4.1. I've got a small test case for it, but it's possible it could be simplified further: https://gist.github.com/nbudin/c5fa13c3963514ec4ef9

The problem is that ActiveRecord::Relation::Merger's filter_binds method does not filter out bind variables when one of the attribute nodes has a string name, but the other has a symbol name, even when those names are actually equal. To trigger this, I used a symbol parameter in `:foreign_key` the `has_many` declaration, which the `Comment` class's `after_save` callback is going to use. Something earlier in the chain, I suspect the `Post` class's `before_save` callback, will have already put an automatically generated `Association` object into the cached relation here with a string for that bind parameter, so the merger compares them as unequal even though they are actually for the same column.

The end result is that PostgreSQL gets two bind parameters for a SQL query with only one placeholder in it and ActiveRecord raises a `StatementInvalid`.

This patch changes the filter_binds method to make it convert both attribute names to strings before comparing, which makes the test case pass. (It is entirely possible there's a more performant way to fix this bug.)