天天看點

Agile Web Development with Rails第九章筆記——任務D:建立購物車

本章内容:

  • 會話和會話管理
  • 添加模型間的關系
  • 建立一個按鈕,可添加産品到購物車中

疊代D1:尋找購物車 将購物車放在資料庫中,并在會話中存儲該購物車的唯一辨別符,cart.id。每當請求出現時,可以從會話中找到該購物車的辨別,并用該辨別在資料庫中查找購物車。 1、建立購物車 rails generate scaffold cart

Agile Web Development with Rails第九章筆記——任務D:建立購物車

2、應用遷移 rake db:migrate

Agile Web Development with Rails第九章筆記——任務D:建立購物車

3、修改控制器app/controllers/application_controller.rb Rails的會話像是一個散列,将購物車對應的資料庫id(cart.id)指派給辨別符為cart_id的session中。

class ApplicationController < ActionController::Base
  protect_from_forgery

  private
    def current_cart
      Cart.find(session[:cart_id])
    rescue ActiveRecord::RecordNotFound
     cart=Cart.create
     session[:cart_id]=cart.id
    cart
 end
end
           

先從session對象中得到:cart_id,試圖尋找與該id對應的購物車。如果沒有找到,建立新的cart,并将新購物車的id儲存在會話中。 疊代D2:将産品放到購物車中 1、建立線上商品表存放線上商品、購物車和産品之間的關系。 如圖所示,線上商品line_items描述了購物車carts和商品products之間的關系。

Agile Web Development with Rails第九章筆記——任務D:建立購物車
Agile Web Development with Rails第九章筆記——任務D:建立購物車
Agile Web Development with Rails第九章筆記——任務D:建立購物車

建立Rails模型: rails generate scaffold line_item product_id:integer cart_id:integer 應用遷移來建立相應的資料庫表:

rake db:migrate

2、修改模型檔案 在模型檔案中添加一些聲明來說明線上商品、購物車和産品之間的關系。(牽扯到cart、product和line_item的模型檔案) 打開app/models下的檔案cart.rb,添加一個對has_many的調用:

Agile Web Development with Rails第九章筆記——任務D:建立購物車

has_many :line_items一個購物車有許多相關聯的線上商品。 :dependent => :destroy線上商品的存在依賴于購物車是否存在。 從相反的方向定義關系(從線上商品到carts和products表),修改app/models/line_item.rb

Agile Web Development with Rails第九章筆記——任務D:建立購物車

注:如果一個資料庫表有外鍵,那麼在相應模型中每個外鍵都要有個belongs_to聲明。 belongs_to告訴Rails資料庫,表line_items中的資料是依賴于表carts和表products的。

因為每個産品都可以有多個線上商品引用它,故需要在模型product中添加一個has_many指令。

class Product < ActiveRecord::Base
  attr_accessible :description, :image_url, :price, :title
  validates :title, :description, :image_url, :presence => true
  validates :price, :numericality => {:greater_than_or_equal_to => 0.01}
  validates:title, :uniqueness => true
  validates :image_url, :format => {
  :with => %r{\.(gif|jpg|png)$}i,
  :message => 'must be a URL for GIF,JPG or PNG image.'
}
  default_scope :order => 'title'
  has_many :line_items
  before_destroy :ensure_not_referenced_by_any_line_itme

 private
  def ensure_not_referenced_by_any_line_itme
   if line_items.empty?
    return true
   else
    errors.add(:base,'Line Items present')
    return false
  end
 end
end
           

上面的代碼聲明了一個産品有多個線上商品,并定義了一個hook(鈎子)方法叫

ensure_not_referenced_by_any_line_itme。

hook方法就是在對象的生命周期中某個給定的地方Rails會自動調用的方法。

疊代D3:添加一個按鈕 現在模型間的關系處理完畢,該給每個産品添加一個Add to Cart按鈕了。

1、修改視圖頁面,使用line_items_path指定處理動作的控制器為線上産品控制器,向控制器傳入欲加入購物車産品的id

<% if notice %>
<p id="notice"><%= notice %></p>
<% end %>

<h1>Your Pragmatic Catalog</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>
      <%= button_to 'Add to Cart', line_items_path(:product_id => product) %>
    </div>
  </div>
<% end %>
           

修改效果:

Agile Web Development with Rails第九章筆記——任務D:建立購物車

2、修改線上商品控制器的create方法。

将産品id傳遞給create方法,以便唯一的辨別要添加的産品。

修改後的create方法如下:

# POST /line_items
  # POST /line_items.xml
  def create
    @cart = current_cart
    product = Product.find(params[:product_id])
    @line_item = @cart.line_items.build(:product => product)

    respond_to do |format|
      if @line_item.save
        format.html { redirect_to(@line_item.cart,
          :notice => 'Line item was successfully created.') }
        format.xml  { render :xml => @line_item,
          :status => :created, :location => @line_item }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @line_item.errors,
          :status => :unprocessable_entity }
      end
    end
  end
           

如以上代碼所示,這部分的操作可以總結為:

Agile Web Development with Rails第九章筆記——任務D:建立購物車

跳轉界面模闆:

<h2>Your Pragmatic Cart</h2>
<ul>    
  <% @cart.line_items.each do |item| %>
    <li><%= item.product.title %></li>
  <% end %>
</ul>
           

3、結果測試

完成上述步驟之後點選Add to Cart按鈕,但是報錯如下

Agile Web Development with Rails第九章筆記——任務D:建立購物車
Agile Web Development with Rails第九章筆記——任務D:建立購物車

百度發現大家都遇到了這個bug,應該是版本差别所緻。

由于寫了“@cart.line_items.build(:product => product)”這句,這裡要求必須把product屬性放入attr_accessible中

原因在此

http://guides.rubyonrails.org/security.html#mass-assignment

為了安全考慮,如果允許mass-assignment的話,可以通過連結往資料庫裡插入資料

是以預設不可以直接用build來new這個新對象,除非加上

attr_accessible :product,:cart 允許mass-assignment。

修改模型層檔案

Agile Web Development with Rails第九章筆記——任務D:建立購物車

重新測試,運作正常:

Agile Web Development with Rails第九章筆記——任務D:建立購物車