↓↓クリックして頂けると励みになります。
【16 | エラー処理】 << 【ホーム】 >> 【18 | Ajax】
カートを空にする機能を実装します。
まずは、カートに入れられた複数の商品を1つにまとめるという処理を行います。
マイグレーションファイルを作成します。
ターミナルで以下のコマンドを入力して下さい。
コマンド
rails generate migration combine_items_in_cart
~/Desktop/Rails7_1/SampleCart $ rails generate migration combine_items_in_cart invoke active_record create db/migrate/20240119052941_combine_items_in_cart.rb
生成されたファイルの「change()」メソッドを「up()」「down()」という別のメソッドに書き換えなます。
「SampleCart/db/migrate」フォルダに作成された「20240119052941_combine_items_in_cart.rb」ファイルを以下のように編集します。
記述編集 【SampleCart/db/migrate/20240119052941_combine_items_in_cart.rb】
class CombineItemsInCart < ActiveRecord::Migration[7.1] def up # カート内に1つの商品に対して複数のLineItemがあった場合は1つのLineItemに置き換える Cart.all.each do |cart| # カート内の各商品の数をカウントする sums = cart.line_items.group(:good_id).sum(:quantity) sums.each do |good_id, quantity| if quantity > 1 # 個別のLineItemを削除する cart.line_items.where(good_id: good_id).delete_all # 1つのLineItemに置き換える item = cart.line_items.build(good_id: good_id) item.quantity = quantity item.save! end end end end def down # 数量>1 のLineItemを複数のLineItemに分割する LineItem.where("quantity >1").each do |line_item| # 個別のLineItemを追加する line_item.quantity.times do LineItem.create( cart_id: line_item.cart_id, good_id: line_item.good_id, quantity: 1 ) end # 元のLineItemを削除する line_item.destroy end end end
マイグレーションを実行します。
ターミナルで以下のコマンドを入力します。
コマンド
rails db:migrate
~/Desktop/Rails7_1/SampleCart $ rails db:migrate == 20240119052941 CombineItemsInCart: migrating =============================== == 20240119052941 CombineItemsInCart: migrated (0.1274s) ======================
upメソッドでは数量が2以上のLineItemを見つけ、このカートと商品にそれぞれ数量1で新しいLineItemを追加し最後に元のLineItemを削除します。
このように、通常のマイグレーションを行うと、upメソッドが実行され、「rails db:rollback
」としてロールバックを行うと、downメソッドが実行されます。
モデル
「total_price()」メソッドを「line_itemモデル」に記述します。
「SampleCart/app/models」フォルダにある「line_item.rb」ファイルを以下のように編集します。
記述追加 【SampleCart/app/models/line_item.rb】
class LineItem < ApplicationRecord belongs_to :good belongs_to :cart def total_price good.price * quantity end end
同じく「total_price()」メソッドを「cartモデル」にも記述します。
「SampleCart/app/models」フォルダにある「cart.rb」ファイルを以下のように編集します。
記述追加 【SampleCart/app/models/cart.rb】
class Cart < ApplicationRecord has_many :line_items, dependent: :destroy def add_good(good) current_item = line_items.find_by(good_id: good.id) if current_item current_item.quantity += 1 else current_item = line_items.build(good_id: good.id) end current_item end def total_price line_items.to_a.sum {|item| item.total_price } end end
カートコントローラの「destroy()」メソッドを修正してセッションをクリーンにする記述を追加します。
ユーザの同意を得てカートを削除し、セッションからカートを削除したうえでフラッシュメッセージを出し、トップページにリダイレクトするようにします。
「SampleCart/app/controllers」フォルダにある「carts_controller.rb」ファイルを以下のように編集します。
変更した部分は52行目の「destroy()」メソッドのみです。
記述編集 【SampleCart/app/controllers/carts_controller.rb】52行目
class CartsController < ApplicationController before_action :set_cart, only: %i[ show edit update destroy ] rescue_from ActiveRecord::RecordNotFound, with: :invalid_cart # GET /carts or /carts.json def index @carts = Cart.all end # GET /carts/1 or /carts/1.json def show end # GET /carts/new def new @cart = Cart.new end # GET /carts/1/edit def edit end # POST /carts or /carts.json def create @cart = Cart.new(cart_params) respond_to do |format| if @cart.save format.html { redirect_to cart_url(@cart), notice: "Cart was successfully created." } format.json { render :show, status: :created, location: @cart } else format.html { render :new, status: :unprocessable_entity } format.json { render json: @cart.errors, status: :unprocessable_entity } end end end # PATCH/PUT /carts/1 or /carts/1.json def update respond_to do |format| if @cart.update(cart_params) format.html { redirect_to cart_url(@cart), notice: "Cart was successfully updated." } format.json { render :show, status: :ok, location: @cart } else format.html { render :edit, status: :unprocessable_entity } format.json { render json: @cart.errors, status: :unprocessable_entity } end end end # DELETE /carts/1 or /carts/1.json def destroy @cart.destroy if @cart.id == session[:cart_id] session[:cart_id] = nil respond_to do |format| format.html { redirect_to markets_index_url, notice: 'カートが空になりました。' } format.json { head :no_content } end end private # Use callbacks to share common setup or constraints between actions. def set_cart @cart = Cart.find(params[:id]) end # Only allow a list of trusted parameters through. def cart_params params.fetch(:cart, {}) end def invalid_cart logger.error "無効なカート(#{params[:id]})にアクセスしようとしました。" redirect_to markets_index_url, notice: '無効なカートです。' end end
次にカートビューを編集します。
「SampleCart/app/views/carts/show.html.erb」ファイルを以下のように編集します。
記述編集 【SampleCart/app/views/carts/show.html.erb】
<div class="container mt-4"> <div class="card"> <div class="card-body"> <div class="card-title h5 mb-4"><strong>現在のカート</strong></div> <% @cart.line_items.each do |item| %> <div class="card mb-2"> <div class="card-body"> <%= item.good.title %> <span class="badge bg-warning"><%= number_to_currency(item.good.price) %></span> × <span class="badge bg-primary"><%= item.quantity %>個</span> = <span class="badge bg-danger"><%= number_to_currency(item.total_price) %></span> </div> </div> <% end %> <div class="container mt-4"> <span class="badge bg-secondary">合計金額</span> <span class="badge bg-success fs-5"><%= number_to_currency(@cart.total_price) %></span> </div> <div class="mt-4"> <%= button_to 'カートを空にする', @cart, method: :delete, class: 'btn btn-outline-danger', data: { turbo: false }, form: { onSubmit: "return check()" } %> </div> </div> </div> </div> <script> function check(){ if(window.confirm('カートを空にしますか?')){ return true; } else{ window.alert('キャンセルされました'); return false; } } </script>
ブラウザの表示を確認します。
http://localhost:3000/carts/8
これで「カートを空にする」ボタンを押すとカートの内容が破棄されてトップページに戻り、「カートが空になりました。」というフラッシュメッセージが表示されます。
【16 | エラー処理】 << 【ホーム】 >> 【18 | Ajax】
↓↓クリックして頂けると励みになります。