Rails2.2でサンプルアプリを作ってみる(5)
Rails2.2を利用したサンプルアプリ作成の続きです。
すでにここまで作成が終わっているものとして話を進めていきます。
- Rails2.2でサンプルアプリを作ってみる(1) - 積み重ねた日々
- Rails2.2でサンプルアプリを作ってみる(2) - 積み重ねた日々
- Rails2.2でサンプルアプリを作ってみる(3) - 積み重ねた日々
- Rails2.2でサンプルアプリを作ってみる(4) - 積み重ねた日々
今回の作業内容
今回は、以下の変更を行っていきたいと思います。
- カートを作成する
カートを作成する
商品を追加するためのカートを取得できる必要があるので、StoreController(app/controllers/store_controller.rb)へfind_cartメソッドを追加します。
class StoreController < ApplicationController def index @products = Product.find_products_for_sale end private def find_cart # :cartというsessionハッシュのキーに対応する値を持たない場合、Cartオブジェクトを生成し、sessionにセットする session[:cart] ||= Cart.new end end
find_cartはアクションとして公開したくないので、privateにします。(privateの行の下にメソッドを追加すると、privateメソッドになるので注意が必要)
カートがまだ実装されていないので、Cartクラスを実装します。(app/models/cart.rb)
class Cart attr_reader :items def initialize @items = [] end def add_product(product) # @items.add(product)と同じ @items << product end end
次にカートに商品を追加するアクション(add_to_cart)を追加します。(app/controllers/store_controller.rb)
class StoreController < ApplicationController def index @products = Product.find_products_for_sale end def add_to_cart @cart = find_cart product = Product.find(params[:id]) @cart.add_product(product) end private def find_cart # :cartというsessionハッシュのキーに対応する値を持たない場合、Cartオブジェクトを生成し、sessionにセットする session[:cart] ||= Cart.new end end
最後にテンプレートを作成します。(app/views/store/add_to_cart.html.erb)
<h2>Your Pragmatic Cart</h2> <ul> <% for item in @cart.items %> <li><%=h item.title %></li> <% end %> </ul>
これでカートができました。
しかし、現状のカートでは、同一の商品をカートへ追加すると、同一商品が複数行にわたって表示されてしまいます。
あらたにカート内の商品と数量を持つCartItemクラスを作成します。また商品名と商品の総額を返すメソッドを用意します。(app/models/cart_item.rb)
class CartItem attr_reader :product, :quantity def initialize(product) @product = product @quantity = 1 end def increment_quantity @quantity += 1 end def title @product.title end def price @product.price * @quantity end end
商品をカートに追加する際に、既にカートに登録された商品であったらカートの商品の数量を増やし、存在しない商品であれば、カートに商品を追加するように変更します。(app/models/cart.rb)
class Cart attr_reader :items def initialize @items = [] end def add_product(product) # カート内の商品リストから追加する商品を探す # 存在すれば、current_itemに代入し、存在しなければnilが代入される current_item = @items.find {|item| item.product == product} if current_item current_item.increment_quantity else @items << CartItem.new(product) end end end
テンプレートに数量を表示されるように変更します。(app/views/store/add_to_cart.html.erb)
<h2>Your Pragmatic Cart</h2> <ul> <% for item in @cart.items %> <li><%= item.quantity %> × <%=h item.title %></li> <% end %> </ul>
この状態で、カートに商品を追加すると、以下のエラーが発生します。
これは元のカートの実装時に登録されたセッションデータが古いために、現在のカートの実装では正しく動作しません。
この問題を解消するために、セッションデータを一度クリアします。
$ rake db:sessions:clear (in /Users/kouichi/Development/Ruby/depot)
クリア後に再度アクセスすると今度はエラーが発生しなくなりました。同じ商品をカートを入れた場合に、複数行になることもなくなりました。
上記で書かれた問題は、開発時だけでなく実稼働時に発生するので、実際にはカートの情報はセッションで管理せず、データベースへ格納し管理するべきです。
次回に続きます。
Rails2.2でサンプルアプリを作ってみる(6) - 積み重ねた日々 へ続きます。