Ruby on Rails ショッピングカート part3 カート作成

Ruby on Rails において ショッピングカート とは以下を示します。

  1. セッション情報を取得する、無ければ新たに作成するメソッド実装
    1. /app/controllers/store_controller.rb
       private
       def find_cart
         session[:cart] ||= Cart.new
       end
      
  2. カートモデルのテーブル作成
     商品の価格が変更されても、既に受注している商品には
     変更前の価格を維持するので、ここでも価格を保持している。
    
     カート自体を考えると、カートを表すテーブルは必要ない気
     が・・・・・。まぁ必要ではないけど、カートが通常のクラスと
     前提して考えて進めていきたいと思う。ただし、実際にデー
     タを挿入するタイミングはチェックアウト時ですよ!!
    
    1. create.sql
       create table line_items (
         id              int           not null auto_increment,
         product_id      int           not null,
         order_id        int           not null,
         quantity        int           not null default 0,
         unit_price      decimal(10,2) not null,
         constraint fk_items_product   foreign key (product_id) references products(id),
         primary key (id)
       );
      
  3. カートモデルを作成
     %cd depot/
     %ruby script/generate model LineItem
           exists  app/models/
           exists  test/unit/
           exists  test/fixtures/
           create  app/models/line_item.rb
           create  test/unit/line_item_test.rb
           create  test/fixtures/line_items.yml
           create  db/migrate
           create  db/migrate/001_create_line_items.rb
    
  4. 参照制約をRailsに定義
     DBの参照制約までは自動的にしてくれない。
    
    1. /app/models/line_item.rb
       class LineItem < ActiveRecord::Base
         belongs_to :product
       end
      
  5. アクションメソッドの追加
     現在のセッション情報を取得して、そのショッピングカートを見つける。
     ここでは、Cartクラスもdisplay_cart()メソッドも実装していない。
    
    1. /app/controllers/store_controller.rb
       def add_to_cart
         product = Product.find(params[:id])
         @cart = find_cart
         @cart.add_product(product)
         redirect_to(:action => 'display_cart')
       end
      
  6. Cartクラス作成
     アプリケーションデータが格納される。(論理的にはモデルの一部)
     でも、データベーステーブルに関連付けしないので、
     "class Product < ActiveRecord::Base"は記述しない。
    
    1. /app/models/cart.rb
       class Cart
      
         attr_reader :items
         attr_reader :total_price
      
         def initialize
           @items = []
           @total_price = 0.0
         end
      
         def add_product(product)
           @items << LineItem.for_product(product)
           @total_price += product.price
         end
      
       end
      
  7. Cartクラスのfor_product()クラスメソッドを実装
     クラスレベルのヘルパーメソッドを作成する。
    
    1. /app/models/line_item.rb
       class LineItem < ActiveRecord::Base
         belongs_to :product
         def self.for_product(product)
           item = self.new
           item.quantity   = 1
           item.product    = product
           item.unit_price = product.price
           item
         end
       end
      
  8. display_cart()メソッド実装、ビュー作成
    1. /app/controllers/store_controller.rb
       def display_cart
         @cart = find_cart
         @items = @cart.items
       end
      
    2. /app/views/store/display_cart.rhtml
       <h1>カートの表示</h1>
      
       <p>
         カートには <%= @items.size %> 個の商品が入っています。
       </p>
      
  9. アプリケーションにクラス宣言
     もし、「Not Found」エラーが発生したら
     (Rails 0.13.1以前では発生しないが・・・・・)
     このファイルは、アプリケーション全体のコンテキストを
     確立するために使われる。そこに、新しく作成したモデルの
     ファイルを宣言する必要がある。
    
    1. /app/controllers/application.rb
       class ApplicationController < ActionController::Base
         model :cart
         model :line_item
       end
      
  10. カートの表示
     「カートに入れる」をクリック。
    
    • http://www.bishounen.sakura.ne.jp/rails/images/knowledge/146_01_cart_display.jpg
  11. ビューを編集
     商品の情報を表示できるように編集。
    
     ここで、終了タグにマイナスが付いていることに注意!!
     これは、ERbは直後の改行を抑止する目的。
    
    1. /app/views/store/display_cart.rhtml
       <h1>カートの表示</h1>
       <table>
       <%
       for item in @items
         product = item.product
       -%>
         <tr>
           <td><%= item.quantity %></td>
           <td><%= h(product.title) %></td>
           <td align="right"><%= item.unit_price %></td>
           <td align="right"><%= item.unit_price * item.quantity %></td>
         </tr>
       <% end -%>
       </table>
      
  12. 新たなカートの表示
     3回「カートに入れる」を繰り返す。
    
    • http://www.bishounen.sakura.ne.jp/rails/images/knowledge/146_02_cart_new_display.jpg
  13. 重複はGroupにして表示
     上記では重複して表示していたので、それをGroupに表示したい。
    
    1. /app/models/cart.rb
       class Cart
      
         attr_reader :items
         attr_reader :total_price
      
         def initialize
           @items = []
           @total_price = 0.0
         end
      
         def add_product(product)
           item = @items.find {|i| i.product_id == product.id}
           if item
             item.quantity += 1
           else
             item = LineItem.for_product(product)
             @items << item
           end
           @total_price += product.price
         end
      
       end
      
    • http://www.bishounen.sakura.ne.jp/rails/images/knowledge/146_03_cart_distinct.jpg
  14. ビューを編集
    1. /app/views/store/display_cart.rhtml
       <div id="cartmenu">
         <ul>
           <li><%= link_to 'ショッピングを続ける', :action => "index" %></li>
           <li><%= link_to 'カートを空にする', :action => "empty_cart" %></li>
           <li><%= link_to 'チェックアウトする', :action => "checkout" %></li>
         </ul>
       </div>
      
       <table cellpadding="10" cellspacing="0">
         <tr class="carttitle">
           <td rowspan="2">数量</td>
           <td rowspan="2">説明</td>
           <td colspan="2">価格</td>
         </tr>
         <tr class="carttitle">
           <td>単価</td>
           <td>合計</td>
         </tr>
      
       <%
       for item in @items
         product = item.product
       -%>
         <tr>
           <td><%= item.quantity %></td>
           <td><%= h(product.title) %></td>
           <td align="right"><%= item.unit_price %></td>
           <td align="right"><%= item.unit_price * item.quantity %></td>
         </tr>
       <% end %>
         <tr>
           <td colspan="3" align="right"><strong>総計:</strong></td>
           <td id="totalcell"><%= @cart.total_price %></td>
         </tr>
       </table>
      
    • http://www.bishounen.sakura.ne.jp/rails/images/knowledge/146_04_cart_distinct_new.jpg
  15. スタイルを追加
     以下のスタイルを追加する。
    
    1. /public/stylesheets/depot
       /* Shoppng cart screen */
      
       .carttitle {
         background: #282;
         color: #dfd;
         font: bold smaller sans-serif;
         text-align: center;
       }
      
       .carttitle TD {
         padding-top: 0px;
         padding-bottom: 0px;
       }
      
       #cartmenu {
         float: right;
         border-left: 1px dotted #282;
       }
      
       #totalcell {
         font-weight: bold;
         border-top: 1px solid #282;
         border-bottom: 2px solid #282;
         text-align: right;
       }
      
    • http://www.bishounen.sakura.ne.jp/rails/images/knowledge/146_05_add_style.jpg

ご訪問頂き有難う御座います。 当サイトを効率良く使うためにまずは FrontPage を見て下さい。 検索方法、一覧表示などの各情報を纏めています。
当サイトの説明 → Frontpage