LoginSignup
95
137

More than 5 years have passed since last update.

Rails5でカート機能を作るためのロジックを作ってみた

Last updated at Posted at 2017-06-04

今回書くこと

  • 以前からショッピングカート機能を作りたい作りたいと思っていて、ようやく作れたのでそのもっとも簡単なルートを書いておく。
  • ビューをどのように書くかは今回は趣旨ではないため割愛するが、どのページにどのような操作を置くといいかは書く
  • 別にこれはベストのロジックだと断定はしません。ただ、いろいろ調べてみて、一番しっくりきたのを使っています

参考にしたページ

  • 最初こちらのページを真似て作ってみたのですが、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コントローラーにまとめて置くとみやすいこと
95
137
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
95
137