[Rails]N+1問題の解決策

##問題が発生している様子

画面を読み込んでいるときのターミナル

```sql:Terminal
Processing by PagesController#index as HTML
  Rendering layout layouts/application.html.slim
  Rendering pages/index.html.slim within layouts/application
  Product Load (0.9ms)  SELECT `products`.* FROM `products`
  ↳ app/views/pages/index.html.slim:25
  Brand Load (0.9ms)  SELECT `brands`.* FROM `brands` WHERE `brands`.`id` = 1 LIMIT 1
  ↳ app/views/pages/index.html.slim:30
  Brand Load (0.9ms)  SELECT `brands`.* FROM `brands` WHERE `brands`.`id` = 12 LIMIT 1
  ↳ app/views/pages/index.html.slim:30
  Brand Load (0.8ms)  SELECT `brands`.* FROM `brands` WHERE `brands`.`id` = 15 LIMIT 1
  ↳ app/views/pages/index.html.slim:30
  Brand Load (0.9ms)  SELECT `brands`.* FROM `brands` WHERE `brands`.`id` = 2 LIMIT 1
  ↳ app/views/pages/index.html.slim:30
  Brand Load (0.8ms)  SELECT `brands`.* FROM `brands` WHERE `brands`.`id` = 6 LIMIT 1
  ↳ app/views/pages/index.html.slim:30
  Brand Load (0.8ms)  SELECT `brands`.* FROM `brands` WHERE `brands`.`id` = 3 LIMIT 1
  ↳ app/views/pages/index.html.slim:30
  Rendered pages/index.html.slim within layouts/application (Duration: 44.1ms | Allocations: 14640)
```

複数のクエリが発行されている。
最初にproductsテーブル中の全てを取り出すのに1回、その中からbrandを6回取り出している。

これは今後クエリ発生数が、何万回のように膨大になると動作が悪化するので対策をとる。

##解決策
Controllerで、includesメソッドを使用する。(N+1問題が発生している箇所)
自分はallメソッドを使用していた。

```ruby:app/controllers/pages_controller.rb
class PagesController < ApplicationController
  def index
    - @products = Product.all
    + @products = Product.includes(:brand)
  end
end
```

```ruby:includeメソッド基礎構文
モデル名.include(:関連名)
```

- 関連名 ≠ テーブル名 (下記 app/models/product.rb 参照)

##対策した結果

```sql:Terminal
Processing by PagesController#index as HTML
  Rendering layout layouts/application.html.slim
  Rendering pages/index.html.slim within layouts/application
  Product Load (0.9ms)  SELECT `products`.* FROM `products`
  ↳ app/views/pages/index.html.slim:25
  Brand Load (1.1ms)  SELECT `brands`.* FROM `brands` WHERE `brands`.`id` IN (1, 12, 15, 2, 6, 3)
  ↳ app/views/pages/index.html.slim:25
  Rendered pages/index.html.slim within layouts/application (Duration: 24.3ms | Allocations: 10596)
```

Brandに関するクエリの発生数が一回になった。

##その他詳細

<details><summary> コード </summary><div>


###View

index.html.slim
![スクリーンショット 2021-04-17 13.01.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561297/6f372ef7-f8c3-fda4-fcd4-2d03efab9d76.png)


```slim:app/views/pages/index.html.slim
.container
  .row
    .col-12
      table.table.table-hover.table--index-product
        thead
          (省略)
        tbody
          - @products.each do |product|
            tr
              th scope="row"
              td
                p = link_to product.name, product
                p = link_to product.brand.name, product.brand
              td.d-none.d-md-table-cell
                p = link_to product.battery_capacity, product
              td
                p = link_to product.soc_antutu_score, product
```

###Model

- ER図
![スクリーンショット 2021-04-17 15.17.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561297/0e14aa06-1292-d307-a334-3b323ec71a88.png)
複数のProductは、一つのBrandに属している。
Productテーブルに対して、Brandは必ず１レコード存在させる。

```ruby:app/models/brand.rb
class Brand < ApplicationRecord
  has_many :products
end
```

```ruby:app/models/product.rb
class Product < ApplicationRecord
  belongs_to :brand #関連名
  validates :brand_id, presence: true
end
```

・belongs_toメソッドの引数の関連名は単数形

###Controller

```Pages_controller.rb
class PagesController < ApplicationController
  def index
    @products = Product.includes(:brand)
  end
end
```
</div></details>




##参考URL
####includesメソッド
- [
  Active Record クエリインターフェイス - Railsガイド](https://railsguides.jp/active_record_querying.html#%E9%96%A2%E9%80%A3%E4%BB%98%E3%81%91%E3%82%92%E4%B8%80%E6%8B%AC%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BF%E3%81%99%E3%82%8B)
- [【Rails】N+1問題をincludesメソッドで解決しよう！ | Pikawaka - ピカ1わかりやすいプログラミング用語サイト](https://pikawaka.com/rails/includes)

####ER図
- [若手プログラマー必読！５分で理解できるER図の書き方５ステップ](https://it-koala.com/entity-relationship-diagram-1897#ER-3)
- [【Rails】アソシエーションを図解形式で徹底的に理解しよう！ | Pikawaka - ピカ1わかりやすいプログラミング用語サイト](https://pikawaka.com/rails/association)