Ruby on Rails カート内の項目の数量を減らす

Rails によるアジャイルWebアプリケーション開発 第3版 の『第9章 タスク D : Ajax の追加』の自由課題『カート内の項目の数量を減らす方法』について。

まず、Ajax を使わずにカートの商品を減らすボタンを実装する。
これは、以下の4つの手順で行なっていく。

  1. ビューのカートの商品部分に削除ボタンを追加する
  2. コントローラに delete_from_cart メソッドを追加する
  3. カートモデルに delete_product メソッドを追加する
  4. アイテムモデルに decrement_quantity メソッドを追加する

削除ボタンの追加

app/views/store/_cart_item.html.erb に button_to で削除ボタンを追加する。
このボタンでコントローラに delete_from_cart メソッドを実行させる。
また、引数としてアイテムの id を渡す。
ボタンのラベルは『-』にしておく。

<% item_tr_if(cart_item == @current_item, cart_item.quantity) do %>
  <td><%= cart_item.quantity %> &times; </td>
  <td><%=h cart_item.title %></td>
  <td class="item-price"><%= number_to_currency(cart_item.price) %></td>
  <td><%= button_to "-", :action => "delete_from_cart", :id => cart_item.product %></td>
<% end %>

コントローラに削除メソッドを追加

app/controllers/store_controller.rb に削除メソッド delete_from_cart を追加する。
引数として渡された id から商品を特定し、カートモデルに商品の削除をさせる。
実行後はリダイレクトしてページの更新をする。

def delete_from_cart
  product = Product.find(params[:id])
  @cart = find_cart
  @cart.delete_product(product)
  redirect_to_index
end

カートモデルから商品を削除

app/models/cart.rb に商品削除の delete_product メソッドを追加する。
コントローラから呼び出された delete_product メソッドは、引数として渡された product から一致するカートアイテムを探し出し、その個数を 1 減少させる。
減少させた後の個数が 0 ならばカートからアイテムを削除しておく。

def delete_product(product)
  current_item = @items.find {|item| item.product == product }
  if current_item.decrement_quantity == 0
    @items.delete(current_item)
  end
  current_item
end

カートの商品情報の個数を減少させる

カートの商品情報モデル CartItem@quantity1 減少させるメソッド decrement_quantity を追加する。

def decrement_quantity
  @quantity -= 1
end

以上で、Ajax を使わない通常の HTML の商品削除処理が追加できた。

続いて、このコードに Ajax を使った処理を追加していく。
Ajax 処理の追加で行うことは以下の3つ。

  1. 削除ボタンを Ajax 対応に変更
  2. delete_from_cart メソッドを Ajax リクエストを受け取るように変更
  3. レスポンスとして返す JavaScript を作る

削除ボタンの Ajax 対応化

app/views/store/_cart_item.html.erb の削除フォームボタンを Ajax 対応化させる。

<% item_tr_if(cart_item == @current_item, cart_item.quantity) do %>
  <td><%= cart_item.quantity %> &times; </td>
  <td><%=h cart_item.title %></td>
  <td class="item-price"><%= number_to_currency(cart_item.price) %></td>
  <td>
    <% form_remote_tag :url => { :action => "delete_from_cart", :id => cart_item.product } do %>
      <%= submit_tag "-" %>
    <% end %>
  </td>
<% end %>

コントローラのメソッドを Ajax 対応化

app/controllers/store_controller.rb の delete_from_cart メソッドを Ajax リクエストを受け取り Ajax レスポンスを返すように修正する。

def delete_from_cart
  product = Product.find(params[:id])
  @cart = find_cart
  @cart.delete_product(product)
  respond_to do |format|
    format.js if request.xhr?
    format.html { redirect_to_index }
  end
end

Ajax レスポンスの作成

コントローラが Ajax リクエストを受け取った時にレスポンスとして返すことになる JavaScript を作る RJS テンプレートを作成する。
app/views/store/delete_from_cart.js.rjs にカート項目の削除後にレンダリングすることになる HTML を作らせる。
さらに、カートの中身が空になった際にカートを blind_up 効果で非表示にさせる処理も加える。

各アイテムの個数が 0 個になった場合に視覚効果を使って画面上から消そうと思ったが、簡単にできそうにないので断念した。

page.replace_html("cart", :partial => "cart", :object => @cart)

page[:cart].visual_effect :blind_up if @cart.total_items == 0

以上で Ajax を使ったカート項目の削除処理が完成した。

RailsによるアジャイルWebアプリケーション開発
Sam Ruby David Heinemeier Hansson Dave Thomas
オーム社
売り上げランキング: 29946
«
»