現在プログランミングスクールでチーム開発にてフリマアプリを作成中です。
やりたいこと
- トップページの商品一覧でitemテーブルのアソシエーション先であるimageテーブルから複数ある画像の一つだけを表示させたい。
- 表示させたいのは出品中の商品のみ。
解決までの思考
とりあえず一覧表示するため商品全部の情報を持ってきてみる
def index
@items = Item.all
end
でもこれだと画像がない
def index
@items = Item.includes([:images]).order(created_at: :desc)
end
モデルにアソシエーションがあれば.includesで取得可能!
class Item < ApplicationRecord
belongs_to :brand
belongs_to :category
has_many :images
念のためアソシエーション確認
これで商品情報と画像を持ってこれた。
でもそも欲しい情報は出品中の商品のみなので、このままだと販売済みなどの必要ない商品まであるよね?
じゃあモデルで定義しちゃおう!
class Item < ApplicationRecord
belongs_to :brand
belongs_to :category
has_many :images
enum status: { sell: 0, buy: 1 , trading:2}
scope :on_sell, -> { where(status: 0) }
end
まずenumで出品中、購入済み、取引中を定義しておく。
これによってstatusカラムに数字で保存されている。
さらにscopeメソッドを使ってメソッドを定義する。
where句を使ってstatusが0(出品中)のレコードだけをon_sellに代入できた。
(コントローラーにも記述できるがこの方が可読性がいいのでモデル推奨)
def index
@items = Item.on_sell.includes([:images]).order(created_at: :desc)
end
あとはコントローラーに記述してあげれば
出品中の商品とそれに紐づいた画像を持ってこれた。ついでに.orderで最新順に表示できるようソートしておく。
あとはビューに表示させるだけ!
.top-main__product__list__box
- @items.each do |item|
= link_to item_path(id: item.id) ,class:"top-main__product__list__box__item" do
- item.images.first(1).each do |image|
= image_tag image.url,class:"top-main__product__list__box__item__img"
.top-main__product__list__box__item__body
%h3.top-main__product__list__box__item__body__name
= item.name
.top-main__product__list__box__item__body__details
%ul
%li
= item.price
= "円"
%p (税込)
itemをeachで順番に表示させたはいいもののそのままだと紐づいた画像を全て表示してしまう。
- item.images.first(1).each do |image|
eachは回数を指定できる、、、
じゃあ一回だけ回せば一枚だけ表示できるやん!とひらめき実装完了
(ただこの方法はあまり美しくない気が、、、)
今回学べたこと
- 関連するテーブルからの取得方法
- アソシエーションの必要性
- スコープを使ってモデルに定義しコントローラーに記述することで可読性アップ
初めはどこに何を定義し、どう記述するのか見当もつきませんでしたが必要なポイントを箇条書きにすることで少しずつ近づけました。
ビューの画像表示の方法はもう少しいい表示方法がありそう?なので今後の課題として!