mirror of
https://github.com/jbranchaud/til
synced 2026-01-04 23:58:01 +00:00
Add Prefer select_all Over execute For Read Queries 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).
|
||||||
|
|
||||||
_1493 TILs and counting..._
|
_1494 TILs and counting..._
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -980,6 +980,7 @@ _1493 TILs and counting..._
|
|||||||
- [Parse Request Params In Rack::Attack Block](rails/parse-request-params-in-rack-attack-block.md)
|
- [Parse Request Params In Rack::Attack Block](rails/parse-request-params-in-rack-attack-block.md)
|
||||||
- [Perform SQL Explain With ActiveRecord](rails/perform-sql-explain-with-activerecord.md)
|
- [Perform SQL Explain With ActiveRecord](rails/perform-sql-explain-with-activerecord.md)
|
||||||
- [Polymorphic Path Helpers](rails/polymorphic-path-helpers.md)
|
- [Polymorphic Path Helpers](rails/polymorphic-path-helpers.md)
|
||||||
|
- [Prefer select_all Over execute For Read Queries](rails/prefer-select-all-over-execute-for-read-queries.md)
|
||||||
- [Pretend Generations](rails/pretend-generations.md)
|
- [Pretend Generations](rails/pretend-generations.md)
|
||||||
- [Prevent Writes With A Sandboxed Rails Console](rails/prevent-writes-with-a-sandboxed-rails-console.md)
|
- [Prevent Writes With A Sandboxed Rails Console](rails/prevent-writes-with-a-sandboxed-rails-console.md)
|
||||||
- [Query A Single Value From The Database](rails/query-a-single-value-from-the-database.md)
|
- [Query A Single Value From The Database](rails/query-a-single-value-from-the-database.md)
|
||||||
|
|||||||
54
rails/prefer-select-all-over-execute-for-read-queries.md
Normal file
54
rails/prefer-select-all-over-execute-for-read-queries.md
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# Prefer select_all Over execute For Read Queries
|
||||||
|
|
||||||
|
Though the `#execute` function provided by ActiveRecord technically works as a
|
||||||
|
general-purpose query runner for strings of raw SQL, it has some downsides.
|
||||||
|
|
||||||
|
First, let's say we have a large semi-complex (better in SQL than ActiveRecord
|
||||||
|
DSL) SQL query defined in a heredoc.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
books_by_status_query = <<-SQL
|
||||||
|
select
|
||||||
|
books.*,
|
||||||
|
latest_statuses.status as current_status,
|
||||||
|
array_to_json(array_agg(...)) as reading_statuses
|
||||||
|
from books
|
||||||
|
-- plus several left joins
|
||||||
|
-- where clause, group by, and order by
|
||||||
|
SQL
|
||||||
|
```
|
||||||
|
|
||||||
|
I reflexively reach for
|
||||||
|
[`#execute`](https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/DatabaseStatements.html#method-i-execute)
|
||||||
|
in a situation like that:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
result = ActiveRecord::Base.connection.execute(books_by_status_query)
|
||||||
|
```
|
||||||
|
|
||||||
|
However, if we're doing a read-only query and we are expecting multiple rows in
|
||||||
|
the result, then we are better off reaching for
|
||||||
|
[`#select_all`](https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/DatabaseStatements.html#method-i-select_all).
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
result = ActiveRecord::Base.connection.select_all(books_by_status_query)
|
||||||
|
```
|
||||||
|
|
||||||
|
It has the advantage of semantically communicating that it's just a read and
|
||||||
|
won't have any side-effects.
|
||||||
|
|
||||||
|
> Note: the query is assumed to have side effects and the query cache will be
|
||||||
|
> cleared. If the query is read-only, consider using select_all instead.
|
||||||
|
|
||||||
|
We can then iterate through and transform the results just as we would have
|
||||||
|
done with `#execute`.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
result.map do |row|
|
||||||
|
row.tap do |hash|
|
||||||
|
hash["reading_statuses"] = JSON.parse(hash["reading_statuses"])
|
||||||
|
end
|
||||||
|
|
||||||
|
OpenStruct.new(row)
|
||||||
|
end
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user