rails/rails — pull request #15078 by nbudin (2014-05-12 21:54:39+00:00)
Title: Make filter_binds filter out symbols that are equal to strings

*This comment copied, mostly, from PR #15077. I've made a new gist for the test case against master.*

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 as well as master. I've got a small test case for it, but it's possible it could be simplified further: https://gist.github.com/nbudin/24b44fb127df86d46ca7

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.)