131216_02:アジャイル開発本
10.3 イテレーション E3:カートの仕上げ
カートを空にする機能を実装する。
カートを空にする機能を実装するには、カートにリンクを追加し、カートコントローラのdestroy( )メソッドを修正してセッションをクリーンアップしなけらばならない。まずテンプレートの作業から始める。ここでもbutton_to( )メソッドを使ってページにボタンを配置する。
app/views/carts/show.html.erbに
<%= button_to 'カートを空にする', @cart, method: :delete,
confirm: '本当に良いですか?' %>
を追加。
コントローラではdestroy( )を修正。ユーザの同意を得てカートを削除し、セッションからカートを削除したうえで、通知メッセージ付きのインデックスページにリダイレクトするようにする。
app/controllers/carts_controller.rbを編集
# DELETE /carts/1
# DELETE /carts/1.json
def destroy
@cart = current_cart
@cart.destroy
session[:cart_id] = nil
respond_to do |format|
format.html { redirect_to store_url,
notice: 'カートは現在空です' }
format.json { head :ok }
end
end
さらに対応するテストも更新する。
test/functional/carts_controller_test.rb
test "should destroy cart" do
assert_difference('Cart.count', -1) do
delete :destroy, {id: @cart.to_param}, {cart_id: @cart.id}
end
assert_redirected_to store_path
end
end
最後にカートの表示を整える。各項目に<li>エレメントを使わず、表を使うようにしましょう。ここもCSSでスタイリングする。
app/views/carts/show.html.erbを編集する。
<% if notice %>
<p id="notice"><%= notice %></p>
<% end %>
<div class="cart_title">カート</div>
<table>
<% @cart.line_items.each do |item| %>
<tr>
<td><%= item.quantity %>×</td>
<td><%= item.product.title %></td>
<td class="item_price"><%= number_to_currency(item.total_price) %></td>
</tr>
<% end %>
<tr class="total_line">
<td colspan="2">合計</td>
<td class="total_cell"><%= number_to_currency(@cart.total_price) %></td>
</tr>
</table>
<%= button_to 'カートを空にする', @cart, method: :delete,
confirm: '本当によいですか?' %>
この作業では、各品目の合計価格を返すメソッドをLineItemモデルに、カート全体の合計価格を返すメソッドをCartモデルに、それぞれ追加する必要がある。まずは品目の合計価格。
app/models/line_item.rbを編集。
class LineItem < ActiveRecord::Base
belongs_to :product
belongs_to :cart
def total_price
product.price * quantity
end
end
次はカート全体の合計価格。Cartに実装するこのメソッドでは、コレクション内の各項目の価格を合計するのに、Railsの便利なメソッドArray#sum( )を使う。
app/models/cart.rbを編集。
class Cart < ActiveRecord::Base
has_many :line_items, dependent: :destroy
def add_product(product_id)
current_item = line_items.find_by_product_id(product_id)
if current_item
current_item.quantity += 1
else
current_item = line_items.build(product_id: product_id)
end
current_item
end
def total_price
line_items.to_a.sum { |item| item.total_price }
end
end
app/assets/stylesheets/carts.css.scss
この章のまとめ