9.1 イテレーションD1:カートの取得
カートのテーブルとその操作APIを作成
depot> rails generate scaffold cart
現在のカートを取得する処理を共通コントローラであるapplicationControllerに作成
class ApplicationController < ActionController::Base protect_from_forgery with: :exception private def current_cart #セッションから取得したcart_idを元にCartテーブルからCart情報を取得 Cart.find(session[:cart_id]) rescue ActionController::RecordNotFound #存在しない場合、カート情報作成 cart = Cart.create #取得したカート情報よりIDを取得し、セッションに設定 session [:cart_id] = cart.id cart end end
9.2 イテレーションD2: 商品とカートの関連付け
カート内に格納する商品のテーブルを作成する
dpot> rails generate scaffold line_item product_id:integer cart_id:integer dpot> rake db:migrate
データベースには品目、カート、商品のテーブルができた。
次にアプリケーション側で上記に対応するモデルへ関連性を定義する
カートに対するカート内の品目の関係を定義
class Cart < ActiveRecord::Base # Cartがline_itemを複数保持する。Cartが削除されるとline_itemを削除する設定 has_many :line_item, dependent: :destroy end
カート内の品目に対するカート、商品の関係を定義
class LineItem < ActiveRecord::Base belongs_to :product belongs_to :cart end
商品に対するカート内の品目の関係を定義
class Product < ActiveRecord::Base has_many :line_items #商品削除時の設定 before_destroy :ensure_not_referenced_by_any_line_item ・・・ private #この商品を参照している品目が存在しているか def ensure_not_referenced_by_any_line_item if line_items.empty? return true else #errorsオブジェクトに直接アクセスし、Baseオブジェクトにメッセージを紐づける errors.add(:base, '品目が存在しています') return false end end
9.3 イテレーションD3:ボタンの追加
RESTfulなURLやHTTPメソッドがいまいち良くわかっていない気がする。
URLとHTTPメソッドの組み合わせでアクションが決定される仕組みだと思ってますが。。
railsにおけるHTTPメソッドはhtmlで用いるUIコントロールによって決まるらしい。
リンク link_to() HTTP GET
ボタン button_to() HTTP POST
<h1>Programticカタログ</h1> <% @products.each do |product| %> <div class="entry"> <%= image_tag(product.image_url) %> <h3><%= product.title %></h3> <%= sanitize(product.description) %> <div class="price_line"> <span class="price"><%= number_to_currency(product.price) %></span> <!-- カートに入れるボタン コントローラー名+_pathでURL指定。追加商品のIDを指定 --> <%= button_to 'カートに入れる' line_items_path(product_id: product) %> </div> </div> <% end %>
product_idにproductを指定すると、railsが勝手にidを取得してきてくれる。
なんて気が利くやつだ。
カートに商品を入れる処理の実装を行う
depot/app/controllers/line_items_controller.rb
def create #application_controller内のcurrent_cartメソッドでcartを取得 @cart = current_cart #pramsオブジェクトよりproduct_idを取得し、Productを検索、取得。 product = Product.find(params[:product_id]) #取得したProductをcartのline_itemsへ紐づける。Productをインスタンス変数へ格納 @line_item = @cart.line_items.build(product: product) respond_to do |format| #上記、buildだけではDB登録されず、下記saveによりはじめて登録される if @line_item.save #カートへリダイレクトすることで、商品追加されたことを確認できるようにする format.html { redirect_to @line_item.cart, notice: 'Line item was successfully created.' } format.json { render :show, status: :created, location: @line_item } else format.html { render :new } format.json { render json: @line_item.errors, status: :unprocessable_entity } end end end
商品を追加しても商品リストに現状、表示されないので
商品を表示する簡易的な表示を行う実装を行う
<% if notice %> <p id="notice"><%= notice %></p> <% end %> <h2>Pragmaticカート</h2> <ul> <% @cart.line_items.each do |item| %> <li><%= item.product.title %></li> <% end %> </ul>
自由課題
商品一覧リストアクセス回数を表示する
/depot/app/controllers/StoreController
def index ・・・ #セッションがnilの場合、0で初期化 session[:counter] ||= 0 session[:counter] += 1 @counter = session[:counter] end
session[:counter] ||= 0
→session[:counter] || session[:counter] = 0 と同じ意味。
左辺を実行し、falseだったら、右辺を実行する。
rubyの場合、objectがnilの場合、falseを返却する仕様
アクセス数が5回以上になったら、アクセス数を表示する
/depot/views/store/index.html.erb
<h1>Programticカタログ</h1> <% if @counter > 5 %> <p>商品ページへのアクセス数:<%= @counter %></p> <% end %>
/depot/controllers/line_items_controller.rb
def create ・・・ #商品追加時にカウンタを0にリセットする session[:counter] = 0
9章完了しました。
引き続き、既存データの修正、エラー処理、フラッシュ、ログについての
学習を進めます。