-
Notifications
You must be signed in to change notification settings - Fork 22k
Allow where
references association names as joined table alias names
#40106
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
Conversation
If a table is joined multiple times, those tables are aliased other than the first one. It happens easily on self referential associations, and in that case currently there is no way to work custom attribute (type casting) and attribute alias resolution for aliased tables in `where` conditions. To address the issue, it will allow `where` references association names as table aliases. If association names are referenced in `where`, those names are used for joined table alias names. ```ruby class Comment < ActiveRecord::Base enum label: [:default, :child] has_many :children, class_name: "Comment", foreign_key: :parent_id end # ... FROM comments LEFT OUTER JOIN comments children ON ... WHERE children.label = 1 Comment.includes(:children).where("children.label": "child") ``` Fixes rails#39727.
🤔 I think I do understand the original problem in here, but are you sure that aliasing part is not breaking change and if so, it is worth it? Also why not to alias everytime to keep the where API the same aka What are we looking here for is finally way to specify in PS: Also this seems to me similar kind of change in |
I'd not like to break existing apps, referencing original alias candidate name still should be valid call if people don't rely on custom type casting. e.g. # ... FROM comments LEFT OUTER JOIN comments children_comments ON ... WHERE children_comments.label = 1
Comment.includes(:children).where("children_comments.label": Comment.labels[:child]) |
I think a |
👍 |
@kamipo as I mentioned, IMHO this added alias already breaks compatibility in some cases. Also change in where "hash" keys logic should be probably better discussed (as asked in #39613). I think there's much more we can do if we decide to do changes in where "hash" keys handling, but adding this will make it harder in the future since we will need to support this behaviour as well. @tenderlove as one requesting better discussion in #39613 WDYT? |
@kamipo looking at this again, wouldn't be better to allow aliasing for |
As the API doc shows, `references` should be given table names. https://api.rubyonrails.org/classes/ActiveRecord/QueryMethods.html#method-i-references However, people (and test cases in the our codebase) sometimes give association names for `references`. Since the API example and all test cases in the codebase use symbols as arguments, so I regarded symbols as user given values in rails#40106. But as rails#40743 indicates, people also use string association names, it would have unexpected side-effect especially if singular association names given. As much as possible to avoid to use user given values, mark internal references for `where` and use only them for join aliases. Fixes rails#40743.
related: rails#39465, rails#40106 Fixed the attributes couldn't cast type in the where clause when the grandchild table is aliased. PR rails#40106 allows aliased table in where clause, but lookup of alias grandchild table isn't working.
Hey @kamipo — I just concluded a few hours of spelunking to figure out why a default scope on one of my models wasn't following the table aliasing that this PR introduced... long story short the default scope was set in part by calling Anyway, in the process I learned lots more about this particular feature-set and outside of my scoping breaking it partially, it is so cool. Being able to specify associations in the I know there've been a number of issues popping up here from folks getting into trouble with it all, so I just wanted to post back to you and say thank you for developing this. I think it's a super neat feature and really appreciate it. 🙂 |
Hi @jon-sully were you able to figure out your issue with default scopes? I just got to this pull while debugging something that sounds like it may be what you hit. I have a default scope on a model, and Arel is trying to merge that default The foreign key equality condition and the subsequent where clause both correctly use the join alias, but the default scope condition tries to reference the original table name, generating invalid SQL. Does this sound familiar? If so, did you resolve it? |
Hey @sholden 👋🏻 My context was a little special — an older project I'm working on is using permanent_records which gives the class scope where arel_table[:deleted_at].eq(nil) So where I was doing default_scope { not_deleted } It would fail — for the reasons we both mentioned. I instead just made my own default scope that does basically the some thing but without all the arel-level (unnecessary?) fanciness 😛. Truly this simple for me: default_scope { where deleted_at: nil } And that worked perfectly. If you're seeing a Hope that helps! |
If a model which has a user-defined `self.default_scope` is joined with table alias, a user-defined `self.default_scope` ignores table alias. This problem has potentially existed for a long time, but it has not become apparent because it is difficult to meet this condition. Since rails#40106, table alias is easily used if association names are used in `where`. So user-defined `self.default_scope` should be evaluated in the current aliased relation. Fixes rails#41857.
If a table is joined multiple times, those tables are aliased other than
the first one.
It happens easily on self referential associations, and in that case
currently there is no way to work custom attribute (type casting) and
attribute alias resolution for aliased tables in
where
conditions.To address the issue, it will allow
where
references association namesas table aliases. If association names are referenced in
where
, thosenames are used for joined table alias names.
Fixes #39727.