-
Notifications
You must be signed in to change notification settings - Fork 21.4k
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
Fix ActiveRecord::FinderMethods.find
when passing multiple ids and primary key is not selected
#45695
Conversation
The behavior in the bug report is what I would expect, not an exception. Selecting attributes without the primary key is a valid scenario. Also, checking if |
Sure, but you should not call
No, because the primary can not be |
I mean if the model in question doesn't use |
If you mean |
that I didn't know, good info! |
Why is |
We can't use it, at least currently, because, probably, not every dbms supports such ordering (but I was unable to find any by checking right now all the most popular). But at least not all activerecord adapters support it -
We can move |
Ok, let's focus on that one for now. 👀 |
Another reason to order in memory: |
I'm not sure that's the main purpose of AR to create nice clean and simple queries. Check the common query generated by |
I did a simple benchmark, and sorting in DB (using require "benchmark/ips"
id_list = 100.times.map { User.create!.id }.shuffle
Benchmark.ips do |x|
x.report("sort in ruby") { User.find(id_list) }
x.report("sort in DB") { User.in_order_of(:id, id_list).to_a }
x.compare!
end
The effect increases when |
05875f0
to
1216b64
Compare
Ok, I looked at the issue a bit, and I don't think either of the proposed resolutions so far are really satisfactory. Raising an explicit error while better than returning an empty array seems like giving up to me. Ordering in DB is mentioned before may have very detrimental performance effects. I'm wondering wether implicitly selecting the primary key when passing a list to |
@@ -507,6 +508,7 @@ def find_some_ordered(ids) | |||
result = except(:limit, :offset).where(primary_key => ids).records | |||
|
|||
if result.size == ids.size | |||
raise ArgumentError, "Primary key is not included in the custom select clause" unless result.first.id | |||
result.in_order_of(:id, ids.map { |id| @klass.type_for_attribute(primary_key).cast(id) }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That said, it's an orthogonal concern, but I think we should probably raise an error if in_order_of
returns less elements than result
.
…primary key is not selected
1216b64
to
b55f0c5
Compare
@byroot Thank you for the review!
Updated with this approach. |
thanks! |
@@ -448,6 +448,7 @@ def find_with_ids(*ids) | |||
ids = ids.flatten.compact.uniq | |||
|
|||
model_name = @klass.name | |||
_select!(table[primary_key]) unless select_values.empty? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hum, actually, this mutates the current instance, I don't think we should do that. Can you do a quick followup that doesn't do this?
I think you can just do it in find_some_ordered
, at the same point where where(primary_key => ids)
.
Sorry, I should have been more careful.
Fixes #45694.
I think it is easier and better to just raise than to introduce an implicit behavior by adding a primary key to the selected values.