本章内容:
- 會話和會話管理
- 添加模型間的關系
- 建立一個按鈕,可添加産品到購物車中
疊代D1:尋找購物車 将購物車放在資料庫中,并在會話中存儲該購物車的唯一辨別符,cart.id。每當請求出現時,可以從會話中找到該購物車的辨別,并用該辨別在資料庫中查找購物車。 1、建立購物車 rails generate scaffold cart
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISN1kDOxUTN5AzMyUDMzEDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
2、應用遷移 rake db:migrate
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之間的關系。
建立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的調用:
has_many :line_items一個購物車有許多相關聯的線上商品。 :dependent => :destroy線上商品的存在依賴于購物車是否存在。 從相反的方向定義關系(從線上商品到carts和products表),修改app/models/line_item.rb
注:如果一個資料庫表有外鍵,那麼在相應模型中每個外鍵都要有個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 %>
修改效果:
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按鈕,但是報錯如下
百度發現大家都遇到了這個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。
修改模型層檔案
重新測試,運作正常: