2
4

More than 3 years have passed since last update.

RailsでECサイトのカート機能を実装する(改訂版)

Last updated at Posted at 2021-08-18

はじめに

RailsでECサイトのカート機能を実装する
での
- URI設計
- コントローラーに寄りすぎたロジック
の二点を改善しました。

ER図

Userモデルは除いています。
ec.png

Cart、Item、Productテーブルのmigrationファイルの作成

$ rails g model Cart
$ rails g model Product name:string price:integer
$ rails g model Item cart:references product:references quantity:integer
$ rails db:migarate

ルーティング

route.rb
  resources :carts, only: %i[create destroy] do
    resources :items, only: %i[create destroy update index], param: :item_id, controller: :cart_items
  end
  • id:cart_idを持つCartを示すリソースのパスはcarts/:cart_id
  • id:cart_idを持つCartに関連するid:item_idを持つItemを示すリソースのパスはcarts/:cart_id/items/:item_id といった感じでRESTfulな設計にします。 ただ、cart/:idといった形で商品カートにアクセスできるインターフェースを用意するべきなのかどうかは疑問です。セッションで紐付けたcartしかアクセスしないのであれば/cartのパスと現在のカートを紐付けても良いかもしれません。

モデル

models/cart.rb
class Cart < ApplicationRecord
  has_many :items, dependent: :destroy

  #    カートアイテムの追加
  def add_item(product_id:, quantity:)
    # カートに入っていない商品を追加する場合はItemレコードを新規作成
    item = items.find_by(product_id: product_id) || items.build(product_id: product_id)
    item.quantity += quantity.to_i
    item.save
  end

  #    カートアイテムの更新
  def update_item(product_id:, quantity:)
    items.find_by(product_id: product_id).update(quantity: quantity.to_i)
  end

  #    カートアイテムの削除
  def delete_item(product_id:)
    items.find_by(product_id: product_id).destroy
  end

  #    カートの合計の算出
  def total_price
    items.sum("quantity*price")
  end
end
models/item.rb
class Item < ApplicationRecord
  belongs_to :cart
  belongs_to :product
end

バリデーション等の処理を適宜追加します。

コントローラー

モデルの時点でほぼ完成なのですが、一応カート内商品の操作周りのコントローラーは以下となります。

app/controllers/cart_items_controller.rb
class CartItemsController < ApplicationController
  def index
    @total_price = my_cart.total_price
    @items = my_cart.items
  end

  def create
    if my_cart.add_item(product_id: params[:product_id], quantity: params[:quantity])
      # カートアイテムの追加に成功した時の処理
    else
      # 失敗した時の処理
    end
  end

  def update
    if my_cart.update_item(product_id: params[:product_id], quantity: params[:quantity])
      # カートアイテムの更新に成功した時の処理
    else
      # 失敗した時の処理
    end
  end

  def destroy
    if my_cart.delete_item(product_id: params[:product_id])
      # カートアイテムの削除に成功した時の処理
    else
      # 失敗した時の処理
    end
  end

  private

  def my_cart
    Cart.find(params[:cart_id])
  end
end

これらをViewで表示して完成です。

2
4
0

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
2
4