読者です 読者をやめる 読者になる 読者になる

気軽に楽しくプログラムと遊ぶ

自分が興味があってためになるかもって思う情報を提供しています。

書籍「Railsによるアジャイル Webアプリケーション開発」9章

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章完了しました。
引き続き、既存データの修正、エラー処理、フラッシュ、ログについての
学習を進めます。