今回書くこと
- 以前からショッピングカート機能を作りたい作りたいと思っていて、ようやく作れたのでそのもっとも簡単なルートを書いておく。
- ビューをどのように書くかは今回は趣旨ではないため割愛するが、どのページにどのような操作を置くといいかは書く
- 別にこれはベストのロジックだと断定はしません。ただ、いろいろ調べてみて、一番しっくりきたのを使っています
参考にしたページ
- 最初こちらのページを真似て作ってみたのですが、Railsのバージョンの問題(?)もあって綺麗に動かなかったので、動くように作り直したものになります
作る手順
モデル作り
- 今回はログイン機能をつけないので、Userモデルは割愛します。
- Userモデルを使う場合はCartモデルをhas_manyさせてあげればいいように使えるかと
rails g model product name price:integer
rails g model cart
# cart_itemのquantityに対しては、必ずdefaultで0を入れて置くこと
rails g model cart_item quantity:integer product:references cart:references
-
product
は商品モデルで、言わずもがな商品名と価格が入る。お好みで原価とかを入れてもいいかも -
cart
はカートモデル。商品カートを表し、 セッションで管理する(どのページでも必要になるので、いちいちPOSTするよりも、セッションにIDを持たせておいた方が楽だから) -
cart_item
はカートにはいっている商品モデル。productとcartの中間テーブル的な役割を持ち、 カートに入っている特定の商品の個数を管理するのに必須。
class Product < ApplicationRecord
end
class Cart < ApplicationRecord
has_many :cart_items
end
class CartItem < ApplicationRecord
belongs_to :product
belongs_to :cart
end
helperメソッド、current_cart
の定義
- ショッピングカート作りの肝となるメソッドの作成
- これを定義することで、セッション情報を元に、現在のカートを呼び出すことができるようになる
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
helper_method :current_cart
def current_cart
if session[:cart_id]
@cart = Cart.find(session[:cart_id])
else
@cart = Cart.create
session[:cart_id] = @cart.id
end
end
end
必要なルーティング設定
- 今回使うルーティングは以下のようになる
Rails.application.routes.draw do
root 'home#index'
resources :products
resources :carts, only: [:show]
post '/add_item' => 'carts#add_item'
post '/update_item' => 'carts#update_item'
delete '/delete_item' => 'carts#delete_item'
end
- ルートディレクトリは別にいきなり
products#index
にしてしまってもいいが、ここは私の好みにしてある。 - 今回作る流れとしては、
1. 商品一覧画面から一つの商品を選び、個数を入力して「購入」ボタンを押す
2. カート詳細画面に移動し、現在カートに入っている商品一覧を出す。
3. カート詳細画面の中からでも、個数は自由に変更でき、「更新」ボタンで個数を変更できる。
4. カートから特定の商品を取り出したい場合は、その商品の「削除」ボタンを押す
というものにする
- メインとなるビューは以下に挙げている3つであり、細かくは書かないが、それぞれのページの機能をまとめておく
# home#index
- 最初に表示されるページ。
- なくてもいいが、もし作るならproducts#indexへのリンクを貼る
# products#index
- 商品一覧。
- それぞれの商品に「購入数入力欄」と「決定ボタン」とを作る。
- ボタンを押すとcarts#add_itemへとPOSTアクションを飛ばし、購入数と商品IDを飛ばしたあと、carts#showへとリダイレクトするようにする。
# carts#show
- カート詳細画面
- 現在カートに入っている商品一覧(なければ空っぽの表示)をだす
- 商品が入っている場合は、個数の変更(carts#update_item)、及び商品の取り消し(cart_item)ができるようにする。
- 合計金額、お支払いボタンがあるとなおいいかも(今回は説明していない)
コントローラの作成
class ProductsController < ApplicationController
# 商品一覧画面
def index
@products = Product.all
end
end
class CartsController < ApplicationController
before_action :setup_cart_item!, only: [:add_item, :update_item, :delete_item]
def show
@cart_items = current_cart.cart_items
end
# 商品一覧画面から、「商品購入」を押した時のアクション
def add_item
if @cart_item.blank?
@cart_item = current_cart.cart_items.build(product_id: params[:product_id])
end
@cart_item.quantity += params[:quantity].to_i
@cart_item.save
redirect_to current_cart
end
# カート詳細画面から、「更新」を押した時のアクション
def update_item
@cart_item.update(quantity: params[:quantity].to_i)
redirect_to current_cart
end
# カート詳細画面から、「削除」を押した時のアクション
def delete_item
@cart_item.destroy
redirect_to current_cart
end
private
def setup_cart_item!
@cart_item = current_cart.cart_items.find_by(product_id: params[:product_id])
end
end
まとめ
- 必要最低限必要なモデルは「商品」と「カート」、それらを紐づけて個数を記録する「カート内商品」モデルであること。
- カートモデルはsessionで管理し、カートに入っている商品の増減の管理はcartコントローラーにまとめて置くとみやすいこと