您的位置:首页 > 产品设计 > 产品经理

Agile Web Development with Rails第九章笔记——任务D:创建购物车

2013-05-23 10:18 399 查看
本章内容:

会话和会话管理
添加模型间的关系
创建一个按钮,可添加产品到购物车中

迭代D1:寻找购物车
将购物车放在数据库中,并在会话中存储该购物车的唯一标识符,cart.id。每当请求出现时,可以从会话中找到该购物车的标识,并用该标识在数据库中查找购物车。
1、创建购物车
rails generate scaffold cart




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
如以上代码所示,这部分的操作可以总结为:



跳转界面模板:

<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。

修改模型层文件



重新测试,运行正常:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: