ややこしい、難しいN+1問題を解決する

今回はincludesとかを使ってN+1問題を解決していきたいです。
さっさと解決しようかと思ったのですが、一筋縄じゃいかなかったので、今から頑張って解決しようと思います！

https://qiita.com/hirotakasasaki/items/e0be0b3fd7b0eb350327

またこの方の記事を全面的に参考にして(パクって)記事を書いていこうと思います。

あとタイトルがクソすぎるので、いいタイトルあったら編集リクエスト待ってます。

# 今回のモデルのアソシエーション


drinkがいわゆる投稿です。

userはいろんな投稿をするので、

userとdrinkで１対多の関係

これだけだったら単純なのですが、

それらに加えて、imageがあります。

投稿画像とユーザー画像がそれぞれある感じ。

# bulletが検知したN+1


```
user: root USE eager loading detected Drink => [:image_attachment] Add to your query: .includes([:image_attachment])
```

DrinkモデルがN+1問題を引き起こしてるっぽい。

# 解決していこう

**drinks_controller**

```rb

    @pagy,@drinks = pagy(Drink.includes(image_attachment: :blob)
                    .where.not(user_id: 6)
                    .where("user_id IN (#{following_ids}) OR user_id = :user_id", user_id: @user.id)
                    .order('drinks.created_at DESC'))
```


んーややこしい。。。。


色々調べてみるとこーゆー感じで書き直したらいいんじゃないかと思った。

**drinks_controller**

```rb

    @pagy,@drinks = pagy(Drink.includes(user: {image_attachment: :blob})
                    .where.not(user_id: 6)
                    .where("user_id IN (#{following_ids}) OR user_id = :user_id", user_id: @user.id)
                    .order('drinks.created_at DESC'))
```


したら今度は、

user: root USE eager loading detected Drink => [:image_attachment] Add to your query: .includes([:image_attachment])
とbulletに検知された。


userの方は解決できたっぽいけど、、、。
今度はimageの方でN+1が発生してる。。。。


この書き方でどうだ！！！(無策)

```rb

    @pagy,@drinks = pagy(Drink.includes(:user ,{image_attachment: :blob})
                    .where.not(user_id: 6)
                    .where("user_id IN (#{following_ids}) OR user_id = :user_id", user_id: @user.id)
                    .order('drinks.created_at DESC'))
```

解決できた。

# ログを実際に見てみる

```

Processing by DrinksController#index as HTML
web_1              |   User Load (0.6ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 7 LIMIT 1
web_1              |   ↳ app/helpers/sessions_helper.rb:52:in `current_user'
web_1              |    (0.8ms)  SELECT COUNT(*) FROM `drinks` WHERE `drinks`.`user_id` != 6 AND (user_id IN (SELECT followed_id FROM relationships WHERE follower_id = 7) OR user_id = 7)
web_1              |   ↳ app/controllers/drinks_controller.rb:14:in `index'
web_1              |   Rendering layout layouts/application.html.erb
web_1              |   Rendering drinks/index.html.erb within layouts/application
web_1              |   Drink Load (1.1ms)  SELECT `drinks`.* FROM `drinks` WHERE `drinks`.`user_id` != 6 AND (user_id IN (SELECT followed_id FROM relationships WHERE follower_id = 7) OR user_id = 7) ORDER BY drinks.created_at DESC LIMIT 2 OFFSET 0
web_1              |   ↳ app/views/drinks/_drinks_index.html.erb:12
web_1              |   User Load (0.6ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 7
web_1              |   ↳ app/views/drinks/_drinks_index.html.erb:12
web_1              |   ActiveStorage::Attachment Load (0.7ms)  SELECT `active_storage_attachments`.* FROM `active_storage_attachments` WHERE `active_storage_attachments`.`record_type` = 'Drink' AND `active_storage_attachments`.`name` = 'image' AND `active_storage_attachments`.`record_id` IN (8, 7)
web_1              |   ↳ app/views/drinks/_drinks_index.html.erb:12
web_1              |   ActiveStorage::Blob Load (0.8ms)  SELECT `active_storage_blobs`.* FROM `active_storage_blobs` WHERE `active_storage_blobs`.`id` IN (12, 13)
web_1              |   ↳ app/views/drinks/_drinks_index.html.erb:12
web_1              |   ActiveStorage::Attachment Load (0.6ms)  SELECT `active_storage_attachments`.* FROM `active_storage_attachments` WHERE `active_storage_attachments`.`record_id` = 7 AND `active_storage_attachments`.`record_type` = 'User' AND `active_storage_attachments`.`name` = 'image' LIMIT 1
web_1              |   ↳ app/views/drinks/_drinks_index.html.erb:18
web_1              |   Like Load (0.7ms)  SELECT `likes`.* FROM `likes` WHERE `likes`.`user_id` = 7 AND `likes`.`drink_id` = 8 LIMIT 1
web_1              |   ↳ app/views/likes/_like.html.erb:2
web_1              |    (0.6ms)  SELECT COUNT(*) FROM `likes` WHERE `likes`.`drink_id` = 8
web_1              |   ↳ app/views/likes/_like.html.erb:6
web_1              |   Rendered likes/_like.html.erb (Duration: 9.1ms | Allocations: 1639)
web_1              |   Like Load (0.7ms)  SELECT `likes`.* FROM `likes` WHERE `likes`.`user_id` = 7 AND `likes`.`drink_id` = 7 LIMIT 1
web_1              |   ↳ app/views/likes/_like.html.erb:2
web_1              |    (0.7ms)  SELECT COUNT(*) FROM `likes` WHERE `likes`.`drink_id` = 7
web_1              |   ↳ app/views/likes/_like.html.erb:6
web_1              |   Rendered likes/_like.html.erb (Duration: 10.2ms | Allocations: 1558)
web_1              |   Rendered drinks/_drinks_index.html.erb (Duration: 56.6ms | Allocations: 12908)
web_1              |   Rendered drinks/index.html.erb within layouts/application (Duration: 57.9ms | Allocations: 12979)
web_1              | [Webpacker] Everything's up-to-date. Nothing to do

```

#　なぜこの書き方で上手くいったのかの僕の予想

```rb
@drinks = pagy(Drink.includes(:user ,{image_attachment: :blob})
```

って書き方は、
drinkとアソシエーション組んでるuserとimageをどっちもincludesメソッドの引数に指定したから上手くいったのでしょう。

一方失敗した下のような書き方は

```rb
@drinks = pagy(Drink.includes(user: {image_attachment: :blob})
```

userモデルとアソシエーションを組んでるimegeをN+1問題を起こさないようにしてーー。

って意味のコードになってしまったのでしょう。。。。きっと。。。

https://qiita.com/makitokezuka/items/f13b2e7bad77b5594911