4
1

More than 1 year has passed since last update.

rails consoleでActiveRecordの検索メソッドを実行するときに注意するべきこと

Last updated at Posted at 2022-02-16

前提知識

ActiveRecordの検索メソッドは、DBアクセスの有無という点で大きく分けると以下の2種類がある。

  • DBアクセスを行うメソッド
    • ActiveRecord::FinderMethodsのメソッド
      • find, find_by, take, first, last など
      • すぐにクエリを発行し、データベースにアクセスし、レコード(Modelのインスタンス or インスタンスの配列)を返す。
  • DBアクセスを行わずActiveRecord::Relationのオブジェクトを返すメソッド
    • all, where, limit, eager_load, preload, joinsなど

問題

上記の通りallwhereはそれ単体ではDBへのアクセスは発生しない。
そこで実際にrails consolewhereを実行してみる。

pry(main)> User.where(id: 1)
  User Load (3.6ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 1
=> #<User:0x000055e9e1dd7e00
 id: 1,
 last_name: "田中",
 first_name: "太郎",
 created_at: Wed, 09 Feb 2022 17:57:33 JST +09:00,
 updated_at: Wed, 09 Feb 2022 17:57:33 JST +09:00 >

むむ、DBへのアクセスは発生しないはずだけど、明らかにDBからデータを取得してますね。(田中太郎さんのデータを取得している)

ログをみてもやはりSQLが発行してDBアクセスが発生していることがわかります。

log/development.log
  User Load (3.6ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 1

一見すると矛盾しているように見えますね。
なぜDBにアクセスが発生しないはずのwhereでDBアクセスが発生しているのか?

ActiveRecord::Relation を返す他のメソッド( all, preload など)も上記と同じ挙動になります。

原因

上記の問題は、railsコンソールの仕様が原因となっています。
railsコンソールにおいて、User.where(id: 1)は以下のような流れで処理されます。

  • コンソールでUser.where(id: 1)を実行
  • ActiveRecord::Relationオブジェクトが帰ってくる
  • コンソールはオブジェクトを画面に表示するため#inspectを呼ぶ
  • ActiveRecord::RelationオブジェクトはDBにアクセスしにいく

つまりrails consoleでは、オブジェクトを画面に表示するために式にinspectが実行されているんですね。
その時に、ActiveRecord::Relationが評価されDBアクセスが発生してしまいます。

まとめ

  • rails consoleでは、画面表示のためにinspectが実行されており、それが原因でwhereallでもDBアクセスが発生している。
  • それを知らないと、allwhereはDBアクセスしないという情報と、rails consoleでの実行結果が矛盾しているように見え混乱を招く。
  • なので、内部的にinspectを実行するという作りになっていることを知っておこう!

追記

行末にセミコロンをつけると実際の挙動になるようです。

 User.where(id: 1); # DBアクセスなし

User.find(1); # DBアクセスあり
User Load (1.6ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1

参考

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1