-
Notifications
You must be signed in to change notification settings - Fork 21.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ActiveRecord's .where.not()
improperly negates polymorphic associations
#16983
Comments
Ignore 77e5a82; I'd accidentally left some debugging code in the tests. |
This issue has been automatically marked as stale because it has not been commented on for at least The resources of the Rails team are limited, and so we are asking for your help. If you can still reproduce this error on the Thank you for all your contributions. |
The attached Gist still fails under |
I confirm this under ruby 2.2.2 and rails 4.2.3 I have a Conversation with polymorphic associated records (User and Company):
From the log I see that the query is |
I can also confirm I am getting this on Rails 4.2.4 and Ruby 2.2.3. Template.where.not(entity: entity) => Template Load (0.6ms) SELECT "templates".* FROM "templates" WHERE ("templates"."entity_type" != 'Country') AND ("templates"."entity_id" != 1) |
+1 rails 5.0 |
+1 to keep this issue active. Should replace the generated SQL Template.where.not(entity: entity) => SELECT "templates".* FROM "templates" WHERE ("templates"."entity_type" != 'Country') AND ("templates"."entity_id" != 1) |
check the analysis on #26269 the where.not query should have OR, not an AND. |
workaround:
|
…ails 6.1 `where.not` with polymorphic association is partly fixed incidentally at 213796f (refer rails#33493, rails#26207, rails#17010, rails#16983, rails#14161), and I've added test case e9ba12f to avoid lose that fix accidentally in the future. In Rails 5.2, `where.not(polymorphic: object)` works as expected as NAND, but `where.not(polymorphic_type: object.class.polymorphic_name, polymorphic_id: object.id)` still unexpectedly works as NOR. To will make `where.not` working desiredly as NAND in Rails 6.1, this deprecates `where.not` working as NOR. If people want to continue NOR conditions, we'd encourage to them to `where.not` each conditions manually. ```ruby all = [treasures(:diamond), treasures(:sapphire), cars(:honda), treasures(:sapphire)] assert_equal all, PriceEstimate.all.map(&:estimate_of) ``` In Rails 6.0: ```ruby sapphire = treasures(:sapphire) nor = all.reject { |e| e.estimate_of_type == sapphire.class.polymorphic_name }.reject { |e| e.estimate_of_id == sapphire.id } assert_equal [cars(:honda)], nor without_sapphire = PriceEstimate.where.not( estimate_of_type: sapphire.class.polymorphic_name, estimate_of_id: sapphire.id ) assert_equal nor, without_sapphire.map(&:estimate_of) ``` In Rails 6.1: ```ruby sapphire = treasures(:sapphire) nand = all - [sapphire] assert_equal [treasures(:diamond), cars(:honda)], nand without_sapphire = PriceEstimate.where.not( estimate_of_type: sapphire.class.polymorphic_name, estimate_of_id: sapphire.id ) assert_equal nand, without_sapphire.map(&:estimate_of) ``` Resolves rails#31209.
Example: https://gist.github.com/pvande/90ee91d4f09d0a125da2
ActiveRecord's default behavior around
.where.not(hash)
is to ensure that each key is appropriately filtered out from the query, with the effect being that the query is populated with(key1 != value1) AND (key2 != value2)
. In general, this feels like a fair implementation, despite not being a direct negation of.where(hash)
.However, ActiveRecord also supports filtering on a polymorphic association. This works as expected, internally being expanded to a condition that verifies both the
relation_id
and therelation_type
. Negating one of these conditions, however, excludes rows that share arelation_type
or arelation_id
.The text was updated successfully, but these errors were encountered: