irbでデータを取得したらLIMIT 11される件

普段はpryを使っているので全然気づかなかったのですが、とある時にirbを使うと謎に`limit 11`がついてしまう事象に出会いました。

`LIMIT 11`ってなんやねん！
気になって仕方ないので、雑にぐぐったりしたのですがわからず、、、うーん気になる。
どうしても気になるので調べたところ、`LIMIT 11`がつく理由がわかったので記事にしてみました。

# 事象の確認

このようなモデルがあるとします。

```ruby
class User < ApplicationRecord
  has_many :reviews
end

class Review < ApplicationRecord
  belongs_to :user
end
```

userの持っているreviewsを取得する処理をirbで実行してみます。

```irb
irb(main):006:0> user = User.find 1
  User Load (0.6ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
=> #<User id: 1, name: "1234567890", created_at: "2019-12-12 05:43:52", updated_at: "2019-12-12 05:43:52">
irb(main):007:0> user.reviews
  Review Load (1.0ms)  SELECT `reviews`.* FROM `reviews` WHERE `reviews`.`user_id` = 1 LIMIT 11
=> #<ActiveRecord::Associations::CollectionProxy [#<Review id: 1, content: "hoge", user_id: 1, book_id: 0, status: "draft", created_at: "2020-06-11 05:27:55", updated_at: "2020-06-11 05:27:55">, #<Review id: 2, content: "fuga", user_id: 1, book_id: 0, status: "draft", created_at: "2020-06-11 05:45:12", updated_at: "2020-06-11 05:45:12">, #<Review id: 3, content: "fuga1", user_id: 1, book_id: 0, status: "draft", created_at: "2020-06-11 05:45:14", updated_at: "2020-06-11 05:45:14">, #<Review id: 4, content: "fuga12", user_id: 1, book_id: 0, status: "draft", created_at: "2020-06-11 05:45:15", updated_at: "2020-06-11 05:45:15">, #<Review id: 5, content: "fuga123", user_id: 1, book_id: 0, status: "draft", created_at: "2020-06-11 05:45:17", updated_at: "2020-06-11 05:45:17">, #<Review id: 6, content: "fuga1234]", user_id: 1, book_id: 0, status: "draft", created_at: "2020-06-11 05:45:18", updated_at: "2020-06-11 05:45:18">, #<Review id: 7, content: "fuga12345", user_id: 1, book_id: 0, status: "draft", created_at: "2020-06-11 05:45:20", updated_at: "2020-06-11 05:45:20">, #<Review id: 8, content: "fuga123456", user_id: 1, book_id: 0, status: "draft", created_at: "2020-06-11 05:45:22", updated_at: "2020-06-11 05:45:22">, #<Review id: 9, content: "fuga1234567", user_id: 1, book_id: 0, status: "draft", created_at: "2020-06-11 05:45:24", updated_at: "2020-06-11 05:45:24">, #<Review id: 10, content: "fuga12345678", user_id: 1, book_id: 0, status: "draft", created_at: "2020-06-11 05:45:27", updated_at: "2020-06-11 05:45:27">, ...]>
irb(main):008:0>
```

`LIMIT 11`がついてますね！どこのことかわかりましたか？
`user.reviews`で発行されるクエリーに注目してください。↓に当該部分の画像を貼っておきます。
<img width="369" alt="スクリーンショット 2020-06-11 18.03.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83424/9448eb89-dc66-978d-a430-baef1671149a.png">

なんで何もしてないのに`LIMIT 11`やねん。ここから原因調査の旅が始まります。

# Railsのリポジトリから`LIMIT 11`を探した件
十中八九Railsが何かやっているのだろうと思ったのでGithubのRailsリポジトリで愚直に`LIMIT 11`で検索してみました。
<img width="565" alt="スクリーンショット 2020-06-11 18.16.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83424/7fa611be-5293-80ea-e363-5f50afcdd6aa.png">

35件見つかりました。目視でいけるレベルなのでざっとみてみると、、、

それっぽいコードがありました！
<img width="658" alt="スクリーンショット 2020-06-11 18.20.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83424/b384014f-81ad-bfaa-ebd7-25129daeb00c.png">

該当のメソッドを転記しました（Githubへのリンクは[こちら](https://github.com/rails/rails/blob/2ad2425fd3b3a58e937f97b1fa05306c4d3166ae/activerecord/lib/active_record/relation.rb#L736)）

```ruby:activerecord/lib/active_record/relation.rb
def inspect
  subject = loaded? ? records : self
  entries = subject.take([limit_value, 11].compact.min).map!(&:inspect)

  entries[10] = "..." if entries.size == 11

  "#<#{self.class.name} [#{entries.join(', ')}]>"
end
```

メソッドの名前でピンとくると思いますが、`inspect`を使った時に`LIMIT 11`を付加しているようです。
処理をみるとデータ自体は10個返却して、11個目は"..."に変えているようですね。

ちなみに`inspect`を知らない方は[こちら](https://docs.ruby-lang.org/ja/latest/method/Object/i/inspect.html)を参照
> オブジェクトを人間が読める形式に変換した文字列を返します。

というデバッグ時によく使うメソッドです。

使い慣れているpryでも`inspect`をつけると`LIMIT 11`が発行されることがわかりました。

```pry
[12] pry(main)> user = User.find 1
  User Load (0.6ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
=> #<User:0x00005599999f28a0
 id: 1,
 name: "1234567890",
 created_at: Thu, 12 Dec 2019 05:43:52 UTC +00:00,
 updated_at: Thu, 12 Dec 2019 05:43:52 UTC +00:00>
[13] pry(main)> user.reviews.inspect
  Review Load (0.6ms)  SELECT `reviews`.* FROM `reviews` WHERE `reviews`.`user_id` = 1 LIMIT 11
=> "#<ActiveRecord::Associations::CollectionProxy [#<Review id: 1, content: \"hoge\", user_id: 1, book_id: 0, status: \"draft\", created_at: \"2020-06-11 05:27:55\", updated_at: \"2020-06-11 05:27:55\">, #<Review id: 2, content: \"fuga\", user_id: 1, book_id: 0, status: \"draft\", created_at: \"2020-06-11 05:45:12\", updated_at: \"2020-06-11 05:45:12\">, #<Review id: 3, content: \"fuga1\", user_id: 1, book_id: 0, status: \"draft\", created_at: \"2020-06-11 05:45:14\", updated_at: \"2020-06-11 05:45:14\">, #<Review id: 4, content: \"fuga12\", user_id: 1, book_id: 0, status: \"draft\", created_at: \"2020-06-11 05:45:15\", updated_at: \"2020-06-11 05:45:15\">, #<Review id: 5, content: \"fuga123\", user_id: 1, book_id: 0, status: \"draft\", created_at: \"2020-06-11 05:45:17\", updated_at: \"2020-06-11 05:45:17\">, #<Review id: 6, content: \"fuga1234]\", user_id: 1, book_id: 0, status: \"draft\", created_at: \"2020-06-11 05:45:18\", updated_at: \"2020-06-11 05:45:18\">, #<Review id: 7, content: \"fuga12345\", user_id: 1, book_id: 0, status: \"draft\", created_at: \"2020-06-11 05:45:20\", updated_at: \"2020-06-11 05:45:20\">, #<Review id: 8, content: \"fuga123456\", user_id: 1, book_id: 0, status: \"draft\", created_at: \"2020-06-11 05:45:22\", updated_at: \"2020-06-11 05:45:22\">, #<Review id: 9, content: \"fuga1234567\", user_id: 1, book_id: 0, status: \"draft\", created_at: \"2020-06-11 05:45:24\", updated_at: \"2020-06-11 05:45:24\">, #<Review id: 10, content: \"fuga12345678\", user_id: 1, book_id: 0, status: \"draft\", created_at: \"2020-06-11 05:45:27\", updated_at: \"2020-06-11 05:45:27\">, ...]>"
[14] pry(main)>
```

繰り返しになりますが、`inspect`がやってくれることは「オブジェクトを人間が読める形式に変換した文字列を返します。」です。
確かに大量にデータが出力されても目視じゃ読む気がなくなるのでキリよく最大１0個表示するように制御してくれているのですね！

ここまででそれっぽい処理が見つかりましたが、まだ解決ではありません。
なぜなら、irbでは`inspect`をつけていないのになぜか`LIMIT 11`がついているのです。

# irbで`LIMIT 11`される件
次にirbでコマンドを実行した時の出力結果に着目してみます。
`LIMIT 11`された時の11個目のデータの表示が"..."に変換されています。
これはもう完全に先ほど調べた`inspect`の動作そのものですね。

そこで"irb" "inspect"でぐぐってみると、
<img width="709" alt="スクリーンショット_2020-06-11_23_05_36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83424/826102b0-2914-94dd-9f16-12cf024f743e.png">

結果出力にInspectを用いるだと！
早速クリックしてみると、下記のように書かれていました。
https://docs.ruby-lang.org/ja/latest/library/irb.html#inspect_mode
> irb のプロンプト中では conf.inspect_mode で、.irbrc 中では IRB.conf[:INSPECT_MODE] に以下のいずれかの値を設定する事で、結果 出力の方式を変更する事ができます。
false, :to_s, :raw
　　出力結果を to_s したものを表示します。
true, :p, :inspect
　　出力結果を inspect したものを表示します。
:pp, :pretty_inspect
　　出力結果を pretty_inspect したものを表示します。
:yaml, :YAML
　　出力結果を YAML 形式にしたものを表示します。
:marshal, :Marshal, :MARSHAL, Marshal
　　出力結果を Marshal.#dump したものを表示します。

早速デフォルト値を調べてみるると、

```ruby
irb(main):004:0> conf.inspect_mode
=> true
```

「出力結果をinspectしたものを表示します。」ですね。
これの影響で`inspect`をつけなくても常に`inspect`がついている状態になるようです。

試しに別の設定(:pretty_inspect)にして試してみました。

```irb
irb(main):010:0> conf.inspect_mode = :pp
=> :pp
- !ruby/object:Review
  concise_attributes:
irb(main):012:0> user = User.find 1
  User Load (0.8ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
=> #<User:0x000055fcbd833780
 id: 1,
 name: "1234567890",
 created_at: Thu, 12 Dec 2019 05:43:52 UTC +00:00,
 updated_at: Thu, 12 Dec 2019 05:43:52 UTC +00:00>
irb(main):013:0> user.reviews
  Review Load (0.8ms)  SELECT `reviews`.* FROM `reviews` WHERE `reviews`.`user_id` = 1
=> [#<Review:0x000055fcbd87b120
  id: 1,
  content: "hoge",
  user_id: 1,
  book_id: 0,
  status: "draft",
  created_at: Thu, 11 Jun 2020 05:27:55 UTC +00:00,
  updated_at: Thu, 11 Jun 2020 05:27:55 UTC +00:00>,
 #<Review:0x000055fcbd87af68
  id: 2,
・・・（長いので省略）
```

`LIMIT 11`はついてないようです。

これにて調査完了です。ちゃんと原因がわかるとすっきりしますね！

# まとめ
今回の調査の結果、「irbでデータを取得したらLIMIT 11される件」の原因は、

* `inspect`でデータ取得すると人間が読みやすいように自動的に`LIMIT 11`が追加される
* irbをデフォルト設定で使うとデータ取得時に`inspect`が自動で追加される

でした。

てか、`LIMIT 11`の原因より、irbでは`inspect`より`pretty_inspect`の方が見やすいということがわかったことが今後の役に立つ成果だったかもしれません。