rails console の中で、ただSQLをスッキリと直視したいだけのお話。

掲題の願望を満たすために、調べていましたら、学びがありましたので、「結論」と、
その**「過程からの学んだ4つのTIPS」**をお届けしたいと思います。 :grimacing:

# 結論

`explain` 使う。なので、もう興味を失った方はもう以下お読み頂く必要はないかと思います。。

# SQLをスッキリみたいというささやかな願望

`rais c` 使います。Active Record 使います。発行されるSQLを見たいです。

```irb
irb(main):001:0> User.first
  User Load (0.1ms)  SELECT  "users".* FROM "users"  ORDER BY "users"."id" ASC LIMIT 1
=> #<User id: 1, name: "name1", created_at: "2016-10-08 11:20:08", updated_at: "2016-10-08 11:20:08">
```

「見れてるやん。」 => SELECT  "users".* FROM "users"  ORDER BY "users"."id" ASC LIMIT 1

...いや、もっと長いやつ。

```irb
irb(main):028:0> Post.all
  Post Load (0.3ms)  SELECT "posts".* FROM "posts"
=> #<ActiveRecord::Relation [#<Post id: 1, title: "title1_of_user1", created_at: "2016-10-08 11:20:08",updated_at: "2016-10-08 11:20:08", user_id: 1>, 
#<Post id: 2, title: "title2_of_user1", created_at: "2016-10-08 11:20:08", updated_at: "2016-10-08 11:20:08", user_id: 1>, 
#<Post id: 3, title: "title3_of_user1", created_at: "2016-10-08 11:20:08", updated_at: "2016-10-08 11:20:08", user_id: 1>, 
#<Post id: 4, title: "title4_of_user1", created_at: "2016-10-08 11:20:08", updated_at: "2016-10-08 11:20:08", user_id: 1>, 
#<Post id: 5, title: "title5_of_user1", created_at: "2016-10-08 11:20:08", updated_at: "2016-10-08 11:20:08", user_id: 1>, 
#<Post id: 6, title: "title1_of_user2", created_at: "2016-10-08 11:20:08", updated_at: "2016-10-08 11:20:08", user_id: 2>, 
#<Post id: 7, title: "title2_of_user2", created_at: "2016-10-08 11:20:08", updated_at: "2016-10-08 11:20:08", user_id: 2>, 
#<Post id: 8, title: "title3_of_user2", created_at: "2016-10-08 11:20:08", updated_at: "2016-10-08 11:20:08", user_id: 2>, 
#<Post id: 9, title: "title4_of_user2", created_at: "2016-10-08 11:20:08", updated_at: "2016-10-08 11:20:08", user_id: 2>, 
#<Post id: 10, title: "title5_of_user2", created_at: "2016-10-08 11:20:08", updated_at: "2016-10-08 11:20:08", user_id: 2>, ...]>
irb(main):029:0>
```

「見れてるやん。。」 => SELECT "posts".* FROM "posts"

....いや、そうですけど、ちょっと見づらいです。このサンプルは、テーブルのカラム数もデータ数も少ないからいいですけど、大きくなってくるととても見づらいんです。**いちいちターミナルでスクロールして上に行って調べるのも面倒くさいなぁと思いまして。**

ということで、いろいろ調べてみました。


# その1: 最初はセミコロンとの出会いでした

```irb
irb(main):034:0> User.first; nil
  User Load (0.2ms)  SELECT  "users".* FROM "users"  ORDER BY "users"."id" ASC LIMIT 1
=> nil
```

このように末尾にセミコロンをつけると、出力を操作することができます。これで、出力結果を nil とかにしちゃえば、大量に出力されなくてスッキリみれるんじゃないか！

ところが、

```irb
irb(main):035:0> User.all; nil
=> nil
```

おい、どうした！ （よくわからないけど、出てこない....） ということで、駄目でした。

# その2: 次に出会ったのは to_sql

```irb
irb(main):047:0* User.all.to_sql
=> "SELECT \"users\".* FROM \"users\""
```

出た！ ...けど、バックスラッシュが、とても邪魔。。。。

そこで、puts を使う。

```irb
irb(main):048:0> puts User.all.to_sql
SELECT "users".* FROM "users"
=> nil
```

いいじゃないですか！

ところが、

```irb
irb(main):050:0> puts Post.preload(:user).to_sql
SELECT "posts".* FROM "posts"
=> nil
```

あれ....。本当は以下のように２つのSQLが発行されているはずなのに。。。。

```irb
irb(main):051:0> Post.preload(:user)
  Post Load (0.4ms)  SELECT "posts".* FROM "posts"
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
=> #略
```

to_sql は何故かひとつめのSQLしか出力してくれないため、これも駄目。

# その3: explain に出逢う

```irb
irb(main):052:0> Post.preload(:user).explain
  Post Load (0.3ms)  SELECT "posts".* FROM "posts"
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
=> EXPLAIN for: SELECT "posts".* FROM "posts"
0|0|0|SCAN TABLE posts

EXPLAIN for: SELECT "users".* FROM "users" WHERE "users"."id" IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
0|0|0|SEARCH TABLE users USING INTEGER PRIMARY KEY (rowid=?)
0|0|0|EXECUTE LIST SUBQUERY 1
```

いいじゃないですか！ セミコロンと組み合わせれば、よりスッキリするじゃないですか！

```irb
irb(main):053:0> Post.preload(:user).explain; nil
  Post Load (0.3ms)  SELECT "posts".* FROM "posts"
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
=> nil
```

でも、first とかに explain はエラーになる。

```irb
irb(main):054:0> Post.preload(:user).first.explain
  Post Load (0.2ms)  SELECT  "posts".* FROM "posts"  ORDER BY "posts"."id" ASC LIMIT 1
  User Load (0.1ms)  SELECT "users".* FROM "users" WHERE "users"."id" IN (1)
NoMethodError: undefined method `explain' for #<Post:0x007fba75e24dc0>
	from /Users/mochizuki/Developer/appStudy/vendor/bundle/gems/activemodel-4.2.3/lib/active_model/attribute_methods.rb:433:in `method_missing'
	from (irb):54
	from /Users/mochizuki/Developer/appStudy/vendor/bundle/gems/railties-4.2.3/lib/rails/commands/console.rb:110:in `start'
	from /Users/mochizuki/Developer/appStudy/vendor/bundle/gems/railties-4.2.3/lib/rails/commands/console.rb:9:in `start'
	from /Users/mochizuki/Developer/appStudy/vendor/bundle/gems/railties-4.2.3/lib/rails/commands/commands_tasks.rb:68:in `console'
	from /Users/mochizuki/Developer/appStudy/vendor/bundle/gems/railties-4.2.3/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
	from /Users/mochizuki/Developer/appStudy/vendor/bundle/gems/railties-4.2.3/lib/rails/commands.rb:17:in `<top (required)>'
	from bin/rails:4:in `require'
	from bin/rails:4:in `<main>'
```

# その4: オブジェクトのクラスが違うことを知る

```irb
irb(main):065:0* User.first.class.name
  User Load (0.2ms)  SELECT  "users".* FROM "users"  ORDER BY "users"."id" ASC LIMIT 1
=> "User"
irb(main):066:0> User.all.class.name
=> "ActiveRecord::Relation"
```

このように `.first` を使ったときと、`.all` を使ったときでは、返されるオブジェクトのクラスは異なります。今まで意識をしたことはありませんでした。

そして、 to_sql や explain は ActiveRecord::Relation に定義されているメソッドになります。


```irb
# こっちにはメソッドが存在

irb(main):071:0> User.all.methods.grep /\Aexplain\z/
=> [:explain]
irb(main):072:0> User.all.methods.grep /\Ato_sql\z/
=> [:to_sql]


# こっちには存在しない

irb(main):073:0> User.first.methods.grep /\Ato_sql\z/
  User Load (0.2ms)  SELECT  "users".* FROM "users"  ORDER BY "users"."id" ASC LIMIT 1
=> []
irb(main):074:0> User.first.methods.grep /\Aexplain\z/
  User Load (0.2ms)  SELECT  "users".* FROM "users"  ORDER BY "users"."id" ASC LIMIT 1
=> []
```


# 結論（再び）

`explain` を使えば、だいたい満たされます。 `.first` とかの場合は、explain も to_sql も使えないので、セミコロンとかでお茶を濁せばよいかと思います。（そもそも first しつつSQLを直視したいかは、わかりませんが。）

### 例
includes してジョインする方のテーブルの where 句で条件絞りこみするけど、references を使わなくても LEFT OUTER JOIN されていることを確認してみるサンプル。

```irb
irb(main):096:0> Post.includes(:user).where(users: {id: 5..Float::INFINITY}).explain; 'Thanks!'
  SQL (0.3ms)  
  SELECT 
    "posts"."id" AS t0_r0, "posts"."title" AS t0_r1, "posts"."created_at" AS t0_r2, "posts"."updated_at" AS t0_r3, "posts"."user_id" AS t0_r4, "users"."id" AS t1_r0, "users"."name" AS t1_r1, "users"."created_at" AS t1_r2, "users"."updated_at" AS t1_r3 FROM "posts" 
  LEFT OUTER JOIN 
    "users" ON "users"."id" = "posts"."user_id" 
  WHERE
     ("users"."id" >= 5)
=> "Thanks!"
```


以上、ありがとうございました。