参考にした記事
おそらくこの記事を読みに来てくださる読者の方は上記の記事も読んでる可能性が高いのでモデルの設計は似せようと思います。
STEP.1 モデル設計
rails g model product name price:integer
rails g model cart
rails g model cart_item quantity:integer product:references cart:references
ここらへんは記事と全く一緒です。
因みに補足としてマイグレーション部分のコードをあげとくと以下のようになると思います。
CartItemのデフォルト値のところは後から追記してます。
マイグレーションの内容
class CreateProducts < ActiveRecord::Migration[6.0]
def change
create_table :products do |t|
t.string :name
t.integer :price
t.timestamps
end
end
end
class CreateCarts < ActiveRecord::Migration[6.0]
def change
create_table :carts do |t|
t.timestamps
end
end
end
class CreateCartItems < ActiveRecord::Migration[6.0]
def change
create_table :cart_items do |t|
t.integer :quantity, default: 0
t.references :product, null: false, foreign_key: true
t.references :cart, null: false, foreign_key: true
t.timestamps
end
end
end
上記の内容でマイグレートを通した後であればコンソールで軽く遊んでみたりしてデフォルト値が設定されているかとか確認しておくと良いかもですね。
(因みに補足ですがCartItemの外部キーは存在しないものを指定するとrollbackするので先にCartとProductを作らないとハマります)
アソシエーションの内容
class Product < ApplicationRecord
end
class Cart < ApplicationRecord
has_many :cart_items
end
class CartItem < ApplicationRecord
belongs_to :product
belongs_to :cart
end
※参考記事と一緒
因みに、もしここのアソシエーションを指定している意味が曖昧な人のために↓
このアソシエーションを追加することで以下のように親のモデルから関連する子のモデルが抽出出来たりするってことですね。
Cart.fitst.cart_items
な感じで
詳しくは本家の Active Record の関連付け を
STEP.2 コントローラー設計
次にコントローラーですが無駄なコードは極力無くしてます。
例えばこの記事では一旦、View側まで書かないので helper_method
などは記述してません。
必要に応じて設定して頂ければと思います。
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
def current_cart
Cart.find(session[:cart_id])
rescue ActiveRecord::RecordNotFound
cart = Cart.create
session[:cart_id] = cart.id
cart
end
end
個人的に find
を使う場合はできるだけ例外処理で丁寧に扱うことを意識しています。
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 ''
end
def update_item
@cart_item.update(quantity: params[:quantity].to_i)
redirect_to ''
end
def delete_item
@cart_item.destroy
redirect_to ''
end
private
def setup_cart_item!
@cart_item = current_cart.cart_items.find_by(product_id: params[:product_id])
end
end
setup_cart_item!
部分でインスタンス変数を使ってますがViewで引っ張ってくる予定がないのであれば普通の変数にリファクタリングして良いと思います。
またリダイレクト部分はよしなに変更していけば良いかなと
STEP.3 ルーティング設定
参考記事通り以下の部分を追加すればカート周りは大丈夫そうですね。
resource :carts, only: [:show]
post '/add_item' => 'carts#add_item'
post '/update_item' => 'carts#update_item'
delete '/delete_item' => 'carts#delete_item'