Rails开发:购物车(1)

本文介绍了一个名为Depot的应用程序搭建过程,包括页面流设计、数据模型建立及编码实践等内容,特别关注于Rails框架下的Web开发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参与者:buyer seller

 

第一阶段需求描述:

买主使用Depot 浏览待售的商品,选择自己要购买的货物,然后提供必要的信息以创建订单。

卖主使用Depot 维护待售的货品列表,确认等待发货的订单,然后将订单标记为“已发货”的状态。

 

Step1: 页面流Page Flow

对应用程序中的主要页面有个整体概念,并且清楚地知道它们之间的导航关系。在开发过程的初期,页面流可能不完整,但仍然能够帮助我们弄清需要做什么、如何将所有东西串起来。

 

买主的流程

买主浏览一个分类列表页,在其中选择货品,每次选择一种。选中的货品被添加进购物车,每次选择执行完毕之后显示购物车的状况。买主可以回到分类列表页继续购物,也可以选择立即付账,购买购物车中的货品。用户买完单以后,我们取出客户的联系信息和本次交易的明细,显示一个收据页面。我们还不知道要如何处理支付问题,所以这部分细节在这幅流程图中是相当含糊的。

 

 

卖主的流程

登录之后,卖主会看到一个菜单,可以让她创建或者查看一个货品,还可以针对现有的订单发货。在查看货品的同时,卖主可以选择编辑货品信息或者把该货品整个删掉。

 

 

 

Step2: Data数据

 

                                                                                最初的猜想

随之而来的下一个问题就是:订单里应该有哪些信息。我们再次决定把这个问题留待以后解决——当把一些成果展示给用户看到之后,他们会帮助我们弄清这些细节。

在“订单条目” (LineItem) 这项数据里复制了货品的价格,这略微破坏了“保持简单”的规则。但我们是从经验出发作出这一决定的:如果货品的价格发生变化,那么已经下好的订单不应该受到影响,因此每个订单条目都应该反映下单时的货品价格。

 

Step3: Let's Code编码

我们可以根据这三幅图来进行开发,不过也可能很快把它们抛弃掉——当我们获得反馈之后,它们就会过时了。这也正是我们不花很多时间画它们的原因——如果你没有花很多时间去做,抛弃的时候就会比较轻松一些。

 

我们的第一个开发任务是要创建一个web 界面,用于维护货品信息:新建货品、编辑现有货品、删除不需要的货品,凡此种种。我们将以小步迭代的方式开发这个应用——“小步”的意思是“每过几分钟考核一次”。现在,我们开始吧……

 

 创建用于保存货品信息的数据库表
 配置应用程序,使之指向我们的数据库
 然后让Rails 帮我们生成“货品维护”应用的最初版本

 

rails depot -d mysql

cd depot

rake db:create

 

Rails 提供了一个中间层。使用Rails ,我们可以定义数据库迁移任务(database migration) 。每个迁移任务代表针对数据库进行的一次修改,采用独立于数据库的源程序形式来描述。修改的内容既可能是针对数据库结构的,也可能是针对表中的数据的。我们可以用这些迁移任务来升级数据库,也可以撤销它们的作用。

 

如何创建这些迁移任务?一般而言,我们希望在创建Rails 模型的同时创建与之对应的数据库表,所以Rails 提供了这么一条精巧的捷径:当你用生成器新建模型类时, Rails 会自动创建一个迁移任务,你可以用它来创建与模型类对应的表。

 

ruby script/generate scaffold product

rake db:migrate

 

Rake 怎么知道哪些迁移任务实施过、哪些没有呢?运行迁移任务之后去看看数据库结构,你就会发现schema_migrations 这么一张表,它的作用就是跟踪数据库的版本。

 

ruby script/server

http://localhost:3000/products

 

添加遗失的字段

需要创建一个迁移任务。在前面创建Product模型类时,我们已经使用过自动生成的迁移任务;这次需要自己动手创建一个,并且需要给它起个一目了然的名字,这样哪怕在一年后再来看这个应用程序,也能记得每个迁移任务是干什么的。一般的习惯是用“ create”来给“创建表”的迁移任务命名,用“ add” 来给“往现有表中添加字段”的迁移任务命名。

 

ruby script/generate migration add_price_to_product price:decimal

 

打开迁移任务的源文件,编辑其中的up() 方法,在其中插入“向products 表添加price字段及其相关参数 :precision , :scale 和 :default”33 的代码( 如下所示) 。
down() 方法则用remove_column()方法删除这个字段。

class AddPriceToProduct < ActiveRecord::Migration
  def self.up
    add_column :products, :price, :decimal,
                        :precision => 8, :scale => 2, :default => 0
  end
  def self.down
    remove_column :products, :price
  end
end

 

 

rake db:migrate

 

我们仅仅处理了模型,控制的流程并没有改变,也就是说控制器不需要改变。需要改变的是视图

 

添加数据有效性检查

模型层是代码世界与数据库之间的把门人。除非通过模型,
否则应用程序无法从数据库获得任何东西,当然也无法把任何东西写回数据库。所以,这就是一个实施
验证的理想场所:不管数据来自表单输入还是来自程序处理,模型都可以对其进行检查,从而保护数据
库不受“坏数据”的污染。

 

class Product < ActiveRecord::Base

    validates_presence_of :title, :description, :image_url
end

 

    validates_numericality_of :price

 

我们需要检查价格字段的值大于0, 这就需要在模型类中编写一个名为price_must_be_at_least_a_cent() 的方法。我们将方法的名字传递给ActiveRecord::Base.validate()方法,这样Rails 就知道在保存Product实例之前调用这个方法。

    validate :price_must_be_at_least_a_cent
protected
def price_must_be_at_least_a_cent
    errors.add(:price, 'should be at least 0.01' ) if price.nil ? || price < 0.01 # 相当于this.price
end

 

请注意,在将价格与0.0l 比较之前,我们先要检查它是不是nil 。这个步骤是很重要的:如果用户将价格字段留空,浏览器就不会向应用程序传递任何价格数据, price 变量也不会被设值。如果试图将这个ni1 值与0 进行比较,就会引发一个异常。

 

还有两样东西要验证。首先,我们希望确保每样货品都有一个独一无二的名称(title)。

validates_uniqueness_of :title

 

 

还需要验证输入的图片地址URL 合法。

validates_format_of :image_url,
      :with => %r{/.(gif|jpg|png)$}i,
      :message => 'must be a URL for GIF, JPG or PNG image.'

 

更美观的列表页

在继续前进之前,最好有一组可靠的测试数据供我们使用。当然,我们可以用脚手架生成的界面从测览器输入数据。但如果我们这样做,以后别的开发者要修改这段代码就得做同样的事情。而且,如果我们在一支开发团队中工作,那么团队的每个成员都得自己输入一份数据。所以,最好还是用一种更可控的方式来填充数据。当然我们有办法,那就是迁移任务! 

 

我们来创建一个纯数据的迁移任务,在up() 方法中先清空products 表,然后添加三条有代表性的数据; down() 方法则会清空这张表。

ruby script/generate migration add_test_data

rake db:migrate

现在,来美化一下货品列表页面吧。这项工作分为两部分,最终我们会得到一个HTML 页面,其中使用CSS 来定义显示风格。不过,首先我们需要告诉浏览器到哪里去找样式表文件。

所有用脚手架生成的应用程序都会默认使用public/stylesheets 目录下的scaffold.css 样式表。我们不打算修改这个文件,而是为这个
应用程序新建了一份样式表depot.css,并将其放在同一个目录下。

 

http://media.pragprog.com/titles/rails3/code/depot_c/db/migrate/20080601000003_add_test_data.rb
http://media.pragprog.com/titles/rails3/code/depot_c/public/images
http://media.pragprog.com/titles/rails3/code/depot_c/public/stylesheets/depot.css

 

最后,我们需要把这些样式表链入HTML 页面。看看.html.erb文件,你不会发现任何对样式表的引用,甚至连通常放这些引用的<head> 标记都找不到。Rails 把这些信息保存在一个单独的文件中,它为所有的products 页提供一个标准的页面环境。这个叫做products.html.erb的文件是一个布局模板,就放在layouts目录下。

<%= stylesheet_link_tag 'scaffold', 'depot' %>

 

现在样式表已经到位了。我们要编辑app/views/products 目录下的index.html.erb 文件,只需要用一个简单的表格状模板替换掉脚手架生成的视图。

<div id="product-list">
    <h1>Listing products</h1>
   
    <table>
      <% for product in @products %>
        <tr class="<%= cycle('list-line-odd', 'list-line-even') %>">
        <td>
            <%= image_tag product.image_url, :class => 'list-image' %>
        </td>
        <td class="list-description">
            <dl>
                <dt><%=h product.title %></dt>
                <dd><%= truncate(product.description.gsub(/<.*? >/,''),:length => 80)%></dd>
            </dl>
        </td>
        <td class="list-actions">
            <%= link_to 'Show', product %><br/>
            <%= link_to 'Edit', edit_product_path(product) %><br/>
            <%= link_to 'Destroy', product, :confirm => 'Are you sure? ', :method => :delete %>
        </td>
        </tr>
    <% end %>
    </table>
</div>

 

即便是这么简单的一个模板,也用到了Rails 内建的好几项特性:
 列表中的每一行交替使用不同的背景颜色。为了实现这一效果,我们需要交替地将每一行的CSS 类型设置为list-line-even 和list-line-odd。cycle()这个辅助方法专门用于这一功能:将列表中的各行交替地设置为两种不同的样式。
 truncate() 辅助方法让描述信息只显示出前80 个字符,在使用truncate() 方法前我们先用gsub() 方法去除描述信息中的HTML 标记41 。
 我们还用h() 方法来保证货品名称和描述中的HTML 标记被当作普通文本。
 看看link_to 'Destroy'这行代码,后面有:confirm=>"Are you sure? " 这么一个参数。如果点击这个链接, Rails 就会让你的浏览器弹出一个对话框,问你是否确定要删除货品。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值