mirror of
https://github.com/jbranchaud/til
synced 2026-01-07 00:58:02 +00:00
Add Empty find_by Returns First Record as a Rails TIL
This commit is contained in:
@@ -10,7 +10,7 @@ pairing with smart people at Hashrocket.
|
|||||||
|
|
||||||
For a steady stream of TILs, [sign up for my newsletter](https://crafty-builder-6996.ck.page/e169c61186).
|
For a steady stream of TILs, [sign up for my newsletter](https://crafty-builder-6996.ck.page/e169c61186).
|
||||||
|
|
||||||
_1505 TILs and counting..._
|
_1506 TILs and counting..._
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -942,6 +942,7 @@ _1505 TILs and counting..._
|
|||||||
- [Demodulize A Class Name](rails/demodulize-a-class-name.md)
|
- [Demodulize A Class Name](rails/demodulize-a-class-name.md)
|
||||||
- [Different Ways To Add A Foreign Key Reference](rails/different-ways-to-add-a-foreign-key-reference.md)
|
- [Different Ways To Add A Foreign Key Reference](rails/different-ways-to-add-a-foreign-key-reference.md)
|
||||||
- [Disambiguate Where In A Joined Relation](rails/disambiguate-where-in-a-joined-relation.md)
|
- [Disambiguate Where In A Joined Relation](rails/disambiguate-where-in-a-joined-relation.md)
|
||||||
|
- [Empty find_by Returns First Record](rails/empty-find-by-returns-first-record.md)
|
||||||
- [Ensure A Rake Task Cannot Write Data](rails/ensure-a-rake-task-cannot-write-data.md)
|
- [Ensure A Rake Task Cannot Write Data](rails/ensure-a-rake-task-cannot-write-data.md)
|
||||||
- [Ensure Migrations Use The Latest Schema](rails/ensure-migrations-use-the-latest-schema.md)
|
- [Ensure Migrations Use The Latest Schema](rails/ensure-migrations-use-the-latest-schema.md)
|
||||||
- [Ensure Record Saved With after_commit Callback](rails/ensure-record-saved-with-after-commit-callback.md)
|
- [Ensure Record Saved With after_commit Callback](rails/ensure-record-saved-with-after-commit-callback.md)
|
||||||
|
|||||||
43
rails/empty-find-by-returns-first-record.md
Normal file
43
rails/empty-find-by-returns-first-record.md
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# Empty find_by Returns First Record
|
||||||
|
|
||||||
|
During a RubyConf 2024 talk, a speaker mentioned that if you pass `nil` to
|
||||||
|
[ActiveRecord's `#find_by`
|
||||||
|
method](https://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-find_by),
|
||||||
|
it will return the first record from the database. This is a bit unintuitive,
|
||||||
|
so lets look at an example and then I'll show you why.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
> Book.first
|
||||||
|
#=> #<Book:0x00000001142e4c48 id: 13, title: "The Secret History", ... >
|
||||||
|
|
||||||
|
> Book.find_by(nil)
|
||||||
|
#=> #<Book:0x00000001142ca3c0 id: 13, title: "The Secret History", ... >
|
||||||
|
```
|
||||||
|
|
||||||
|
So, that is the same object in both cases, but why?
|
||||||
|
|
||||||
|
Our first hint is in the SQL that gets constructed when making that method
|
||||||
|
call.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
Book Load (2.5ms) SELECT "books".* FROM "books" LIMIT $1 [["LIMIT", 1]]
|
||||||
|
```
|
||||||
|
|
||||||
|
It's grabbing all books and limiting to _one_ result.
|
||||||
|
|
||||||
|
Lets look at the underlying implementation of the `#find_by` method.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
# File activerecord/lib/active_record/relation/finder_methods.rb, line 111
|
||||||
|
def find_by(arg, *args)
|
||||||
|
where(arg, *args).take
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
Sure enough, the implementation is a `#where` followed by a `#take`. Since the
|
||||||
|
`#where` is receiving `nil` as its `arg`, there are no conditions _filtering_
|
||||||
|
the query. And the `#take` corresponds to the `limit 1`.
|
||||||
|
|
||||||
|
Knowing that, we can understand that we will also get the first record from the
|
||||||
|
database if we call `#find_by` with `{}`. Again, no conditions to filter on, so
|
||||||
|
give me all books limited to one.
|
||||||
Reference in New Issue
Block a user