【Rails＋Ancestry＋Carrierwave】商品一覧表示〜出品した複数の画像から最初の1枚を添えて〜

# はじめに

今日も投稿いたします！最近は投稿することに楽しみを覚えてきました^^

某プログラミングスクールの最終課題で某フリマアプリのクローンにて、商品出品後の一覧表示が大変だった件について投稿いたします。indexの部分になります。

結論は

instance_variable_setメソッド

を使用いたしました。こちらは変数名を変えて繰り返し使いたいメソッドになります。
当初はレディースごと、メンズごとに変数を定義していたのですが、
「じゃあカテゴリーが増えた時は、またいちいち変数を定義しないといけないのか」
というメンテナンス性に欠けておりスマートではなかったので、リファクタリングも込みで修正することにいたしました。

<img width="1440" alt="スクリーンショット 2020-03-07 10.18.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586820/f370873e-45e7-8759-9fa2-e83efba0585f.png">


これが商品出品後に

<img width="1440" alt="スクリーンショット 2020-03-07 10.10.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586820/1baaf609-e4cc-ee63-616e-998e0cc05e1c.png">

こうなればいいでヤンスね！

# 前提条件
1. ancestryでのカテゴリー階層化が終わっている
2. carrierwaveでの複数画像投稿が終わっている

もし、複数画像投稿が終わっていない場合は

[【Ajax+Rails＋Carrierwave】個別削除可能な画像複数（10枚まで）投稿](https://qiita.com/syoma/items/09a0d7bbadad35771a4d)

をご覧ください。

# テーブルの関係
商品テーブル：画像テーブル＝１：多
1つの商品は複数の画像を持っている

商品テーブル：カテゴリテーブル＝１：多
1つの商品は複数カテゴリー（3階層先まで）をもっている

# controllerでの記述

```ruby:goods_controller.rb
class GoodsController < ApplicationController

 before_action :index_brand_set, only: :index

 private

 def index_category_set
  array = [1, 2, 3, 4]
    for num in array do
      search_anc = Category.where('ancestry LIKE(?)', "#{num}/%")
      ids = []
      search_anc.each do |i|
        ids << i[:id]
      end
      goods = Good.where(category_id: ids).order("id DESC").limit(10)
      instance_variable_set("@cat_no#{num}", goods)
    end
 end
```

私の場合はprivateの中に書いてしまい、before_actionでindexに呼び出ししました！

1ずつ解説していくと

```ruby:goods_controller.rb
 array = [1, 2, 3, 4]
  for num in array do
```
arrayという配列に1, 2, 3, 4を入れてnumという変数に順番に放り込んでいます。

```ruby:goods_controller.rb
 search_anc = Category.where('ancestry LIKE(?)', "#{num}/%")
```
そしてsearch_ancでカテゴリーを絞っていくわけですが、Categoryテーブルのancestryカラムで、
先ほど、numに格納していた1（メンズ）,2（レディース）,3（家電）,4（おもちゃ）ごとに取り出します。
おいおいsyomaさん。3階層も取り出せたの！？ご安心を！

"#{1}/%"

の場合、レディースに関連しているもの（idの5~13）をすべてひっぱり出せます。

<img width="1440" alt="スクリーンショット 2020-03-07 10.33.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586820/2db82165-205d-6b06-c258-96f8b5960525.png">


```ruby:goods_controller.rb
 ids = []
  search_anc.each do |i|
   ids << i[:id]
```

そしてidsという配列の中に先ほど抽出したCategoryテーブルのidを入れてます。

```ruby:goods_controller.rb
 goods = Good.where(category_id: ids).order("id DESC").limit(10)
 instance_variable_set("@cat_no#{num}", goods)
```
goodsという変数の中にGoodテーブルで先ほど絞ったcategory_idをもつ商品を抽出し、降順の10個まで表示できるようにしております。

最後のinstance_variable_setで

"@cat_no#{1}",@cat_no#{2}",@cat_no#{3}",@cat_no#{4}"

と複数展開できるわけです。

ここで私は1つの疑問を抱きます。

「画像は！？」

ご安心を！
has_manyの関係があれば（リレーションを張っていれば）viewの方で簡単に引っ張ってこれまする^^

# viewでの記述
レディースで表示させてみましょう！

```haml:index.html.haml
.main__contents__center__item__ladies__image
 %ul.main__contents__center__item__ladies__image__ul
  - @cat_no1.each do |good|
   %li.main__contents__center__item__ladies__image__ul__li
    .main__contents__center__item__ladies__image__ul__li__top-image
     = link_to good_path(good.id) do
      = image_tag "#{good.photos[0].image.url}"
       %area-label
        = "¥#{good.fee}"
    .main__contents__center__item__ladies__image__ul__li__under-text
     %span
      = good.name
```

こんな感じ。1つずつ見ていきましょう！

```haml:index.html.haml
- @cat_no1.each do |good|
```
ではgoodという変数に先ほど、抽出したレディースを格納しています。

```haml:index.html.haml
= link_to good_path(good.id) do
```
こちらはshowへ飛ぶリンクなので気にせずに。

```haml:index.html.haml
= image_tag "#{good.photos[0].image.url}"
```
こちらで画像を引っ張るわけですが

変数.テーブル名s[0].カラム名.url

ですね！先ほど作成したgoodという変数に紐づいているphotoテーブルのimageカラムをひっぱり出しています。
テーブル名が複数形になっているのはhas_manyの関係だからです。
[0]は配列に入っている1番目の画像を引っ張っております。

# メンズの場合

```haml:index.html.haml
- @cat_no2.each do |good|
```
@cat_no2に変更して同じように展開するんだぁーーーーーーーーーーーーーー

# ブランドは！？
privateの中に別で書いてみてください！
要領をご理解いただければ同じように展開できます。

以上です！

# 最後に

twitterやっておりますので是非フォローよろしくお願いいたします。
https://twitter.com/syomabusiness
youtubeも始める予定です。