首页 > Web开发, 动态语言, 挨踢(IT) > 《Agile Web Development with Rails》抄书笔记(09):商品列表展示

《Agile Web Development with Rails》抄书笔记(09):商品列表展示

2013年5月23日 发表评论 阅读评论 423 人阅读    

《Agile Web Development with Rails》抄书笔记系列

  “《Agile Web Development with Rails》抄书笔记系列”目录

  正如上一节所说,这节我们将美化Product的展示。这节的主要工作是,把产品按照一定的列表进行展示出来。

  上面的章节中,已经创建了Product相关的Controller,这个是方便商品的卖家管理商品使用的。现在,我们创建一个新的Controller,用于向买家展示商品。创建Controller很方便,可以直接rails命令的generate工具来完成。命令如下:

rails generate controller Store index

  请观察输出,这里会显示都创建了哪些文件。创建完成后,启动Rails服务器,访问http://127.0.0.1:3000/store/index即可查看我们工作的结果。

  有木有感觉这个URL有点长?!其实,我们可以简化这个URL,并且将其简化后的URL作为网站的入口链接。请打开%Depot%/config/routes.rb(关于这个文件,以后专门来讲解),添加如下内容:

Depot::Application.routes.draw do
  get"store/index"
  resources :products
  # ...
  # Youcanhave theroot of your site routed with "root"
  # just remember to delete public/index.html.
  # root :to=> 'welcome#index'
  root to:'store#index', as:'store'
  # ...
end

  然后使用如下命令,删除%Depot%/public/index.html文件:

# D瓜哥在Windows上安装了Cygwin
rm public/index.html

  这时,打开http://127.0.0.1:3000/,是不是已经显示成和http://127.0.0.1:3000/store/index一样的内容。

  虽然这个过程很简单,但是从这个过程也可以感受到程序是又几个不同的部分恰当的配合来完成工作的。另外,这个页面的展示还指出了模板文件的位置。

  如果要展示Product信息,我们需要把数据库中Product数据查询出来,并且保证在view代码中可以使用。这时,我们就需要修改%Depot%/app/controllers/store_controller.rb文件中的index()方法,增加如下代码:

class StoreController < ApplicationController
  def index
    @products = Product.order(:title)
  end
end

  这样,就获得了Product信息。下面,我们修改页面上所示的那个模板文件%Depot%/app/views/store/index.html.erb,来展示Product。将原来文件中的内容全部删除,然后添加如下代码:

<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"><%= product.price %></span>
          </div>
     </div>
<% end %>

  请注意sanitize()方法,这个可以使product.description中的HTML标签按照标签展示出来。方便我们利用HTML标签来美化产品的描述。值得注意的是,这样有可能带来一些跨域攻击的安全漏洞。这里还使用了image_tag()方法,这个可以生成HTML的<img>标签,用来展示图片。

  这时,刷新浏览器中的http://127.0.0.1:3000/页面查看效果,是不是感觉样式有问题?这是由于我们没有添加相关的样式。

  Rails使用了Sass来定义样式的。刚才在生成Controller时,已经在/app/assets/stylesheets/目录下自动生成了store.css.scss文件,这个文件就是专门用于定义和StoreController相关的样式的。打开这个文件,在里面添加如下样式:

D呱呱

  目前,针对传统CSS的改进有两种方案:SASS和LESS。Rails中使用的是SASS。D瓜哥查阅了一些这方面的资料,希望对大家有所帮助:

关于SASS的

  1. SASS用法指南
  2. Sass 使用介绍

关于LESS的

  1. LESS中文网

  关于SASS和LESS孰优孰劣,请自己区分。D瓜哥就不赘述了。

.store {
  h1 {
    margin: 0;
    padding-bottom: 0.5em;
    font: 150% sans-serif;
    color: #226;
    border-bottom: 3pxdotted #77d;
  }
 
  /* An entry in thestore catalog */
  .entry {
    overflow: auto;
    margin-top: 1em;
    border-bottom: 1pxdotted #77d;
    min-height: 100px;
   
    img{
       width: 80px;
      margin-right: 5px;
      margin-bottom: 5px;
      position: absolute;
    }
   
    h3 {
      font-size: 120%;
      font-family: sans-serif;
      margin-left: 100px;
      margin-top: 0;
      margin-bottom: 2px;
      color: #227;
    }
   
    p, div.price_line {
      margin-left: 100px;
      margin-top: 0.5em;
      margin-bottom: 0.8em;
    }
   
    .price {
      color: #44a;
      font-weight: bold;
      margin-right: 3em;
    }
  }
}

  然后,刷新浏览器中的http://127.0.0.1:3000/页面查看效果。咦,怎么回事?页面没有按照样式显示,这是怎么回事啊?!

  这里,我们需要额外执行一个指令, 把需要的CSS、JavaScript预先编译出来,把照片也发布都相应的目录下。命令如下:

rake assets:precompile

  这条命令,会把%Depot%/app/assets/下的内容编译,发布到%Depot%/public/assets/目录下。而且还会对CSS、JavaScript进行压缩。真的灰常牛逼啊!哈哈

  执行完上面的命令,再次刷新,咦,页面怎么还是没有正常显示?这里,通过分析生成的CSS选择符,我们发现刚刚添加的CSS都是.store子元素添加的;但是,我们查看网页源代码,没有发现class=”store”的定义。这个该怎么办?下面,我们来说说一下,如入美化这个页面布局?

美化页面布局

  其实,关于如何修改上面的问题,其实很简单,只需要修改一个地方,就可以解决问题:在%Depot%/app/views/layouts/application.html.erb中,只需要在其中的body标签中添加一个class声明即可,代码如下:

<body class="<%= controller.controller_name %>">

一定要注意这里的“=”!因为少了这个符号,让我调试了老长时间才发现问题。

  从这个文件的名字和存放路径上也可以看出,这个文件控制所有Controller和Views的布局,修改这个文件可以影响整个网站的页面显示。所以,我可以通过调整这个页面的内容和布局,来修改整个网站的页面风格。

  这里,我们更新这个文件,来添加页面横幅和侧栏。代码如下:

<!DOCTYPE html>
<html>
<head>
  <title>Depot</title>
  <%= stylesheet_link_tag    "application", :media => "all" %>
  <%= javascript_include_tag "application" %>
  <%= csrf_meta_tags %>
</head>
<body class="<%= controller.controller_name %>">
  <div id="banner">
    <%= image_tag("logo.png") %>
    <%= @page_title || "Pragmatic Bookshelf" %>
  </div>
  <div id="columns">
    <div id="side">
       <ul>
         <li><a href="http://127.0.0.1:3000/">Home</a></li>
         <li><a href="http://127.0.0.1:3000/">Questions</a></li>
         <li><a href="http://127.0.0.1:3000/">News</a></li>
         <li><a href="http://127.0.0.1:3000/">Contact</a></li>
       </ul>
    </div>
     <div id="main">
      <%= yield %>
     </div>
  </div>
</body>
</html>

  针对这段代码做个简要说明:stylesheet_link_tag()方法,可以生成link标签,来引入CSS文件;csrf_meta_tag()方法,用于防止跨域攻击。

  重点关注一下第24行的yield,这个会根据请求的URL,被相应的Views内容替代掉。在本程序中,我们请求http://127.0.0.1:3000/时,会被%Depot%/app/views/store/index.html.erb替换。

  下面,我们来添加CSS。首先,将%Depot%/app/assets/stylesheets/目录下的application.css重命名为application.css.scss,然后在里面添加如下内容:

#banner {
  background: #9c9;
  padding: 10px;
  border-bottom: 2pxsolid;
  font: small-caps 40px/40px "Times NewRoman", serif;
  color: #282;
  text-align: center;
 
  img{
    float: left;
  }
}

#notice {
  color: #000 !important;
  border: 2pxsolid red;
  padding: 1em;
  margin-bottom: 2em;
  background-color: #f0f0f0;
  font: bold smaller sans-serif;
}

#columns {
  background: #141;
 
  #main {
    margin-left: 17em;
    padding: 1em;
    background: white;
  }
 
  #side {
    float: left;
    padding: 1em2em;
    width: 13em;
    background: #141;
   
    ul {
      padding: 0;
     
      li {
        list-style: none;
       
        a {
          color: #bfb;
          font-size: small;
        }
      }
    }
  }
}

  补充一句:你可以通过修改%Depot%/app/views/layouts/application.html.erb中的stylesheet_link_tag()方法的参数,来自定义所需加载的CSS文件。我们修改的是针对整个页面的布局,默认已经所需的CSS文件。所以,我们这里不需要做修改。

格式化价格显示

  在页面中显示的价格是个数字,实在看着不够”见文知意”!所以,有必要格式化一下。Ruby提供了格式化函数:sprintf()。所以,我们可以这样:

<span class="price"><%=sprintf("$%0.02f", product.price) %></span>

  虽然目的达到了。确将货币信息硬编码到了代码中,不利于维护和扩展;比如,不能满足国际化的要求。

  其实,Rails内建了一个专门进行价格格式化的函数:number_to_currency()。所以,我们可以把我们的代码修改成这样:

<span class="price"><%=number_to_currency(product.price) %></span>

针对Controller的功能性测试

  在开始正式的内容讲解之前,我们先运行一下如下命令,来检查一下目前的测试是否都能通过:

rake test

  上一章节,我们专门讲解了一下针对模型的单元测试,测试代码也能简单明了,通俗易懂:执行一条测试语言,返回我们预期的结果。现在,我们来玩点复杂的:我针对服务器的处理、浏览器的展示等这个完整流程进行一个功能性测试(functional tests),测试Model、View、Controller协同工作状况的测试。不用担心,Rails又一次做了很多幕后工作,这个测试很简单。

  首先,来看一下Rails自动生成的测试模板,打开%Depot%/test/functional/store_controller_test.rb,是不是展示如下代码:

require 'test_helper'

class StoreControllerTest < ActionController::TestCase
  test "should get index" do
    get :index
    assert_response :success
  end

end

  这段代码的意思也很简单:请求store/index,测试是否如预期一样成功了。下面开始我们正式的测试。

  我们先来检验一下,我们的页面布局、产品信息以及数字格式。测试代码如下:

require 'test_helper'

class StoreControllerTest < ActionController::TestCase
  test "should get index" do
    get :index
    assert_response :success
     assert_select '#columns #side a', minimun: 4
     assert_select '#main .entry', 3
     assert_select 'h3', 'Programming Ruby 1.9'
     assert_select '.price', /\$[,\d]+\.\d\d/
  end

end

  我们来多新加入的几行代码做个简短的说明。

  assert_select ‘#columns #side a’, minimun: 4这行代码,是检查在CSS选择器”#columns #side a”选出的元素中,是不是最少有四个。

  由此可以看出,Rails内置的测试断言,可以直接解析HTML,然后对其内容进行分析。

  其余三条语句都是针对Product的信息做测试。尤其值得注意的是assert_select ‘.price’, /\$[,\d]+\.\d\d/,可以使用正则表达式来检查数字格式是否匹配货币显示格式。

  通过上一节的内容我们值得,运行每个测试方法之前,Rails都会从”测试固件”中加载数据到测试库中。所以,在运行测试用例之前,请确保%Depot%/test/fixtures/products.yml中的数据,和上节讲述”测试固件”时的内容一致。

  然后,执行如下命令,开始测试:

rake test:functionals

  我们通过对Model添加校验以及测试,保证了数据库中数据的合法有效性;我们又通过对页面进行功能性测试,保证了Model、View以及Controller的协同工作的正确性。现在,我们可以放心地洗洗睡了。梦里,北京的天很蓝,空气很清新……

D呱呱

  添加一些测试数据,打开http://media.pragprog.com/titles/rails4/code/rails32/depot_a/db/seeds.rb

  把里面的内容全部复制下来,粘贴到%Depot%/db/seeds.rb里面;或者保存,把%Depot%/db/seeds.rb给覆盖掉也许。

  然后,执行如下命令:

rake db:seed

  再添加一些图片,打开http://media.pragprog.com/titles/rails4/code/rails32/depot_a/app/assets/images/,把里面展示的几个图片全部保存到%Depot%/assets/images/目录下。



作 者: D瓜哥,https://www.diguage.com/
原文链接:https://wordpress.diguage.com/archives/15.html
版权声明:非特殊声明均为本站原创作品,转载时请注明作者和原文链接。

  1. 本文目前尚无任何评论.
  1. 本文目前尚无任何 trackbacks 和 pingbacks.