《Agile Web Development with Rails》抄书笔记系列
“《Agile Web Development with Rails》抄书笔记系列”目录
在看了产品相关的应用后,我们的客户有一个要求(客户似乎总有提不完的要求。对吧?):商品列表太丑了。提议我们进行美化,看能否将商品图片一起展示出来?
这让我们有点进退维谷。作为开发人员,我们职业性地深吸一口气,带着不置可否的摇头,低声问道”你想要什么?”同时,我们也想想炫耀一下,Rails可以轻松应付这些变化。我们打开我们信赖的编辑器。
在我们进行更深入的开发之前,最好使用一组测试来确保应用的可行性。我们可以使用自动生成的套件,在浏览器表单中输入数据等。如果我们这样做,未来工作在同一个代码库上的程序猿也必须这样做。如果我们作为一个项目组的一个成员,同时参与一个项目,那么每位成员都不得不输入自己的数据。如果我们可以以一种可控的方式将数据加载到数据库中,这将是非常完美的。事实证明,我们可以这么干。Rails提供了导入种子数据(seed data)的能力。
首先,我需要简单修改一下在db目录下的种子数据文件,seeds.rb。
下面让让我们添加一些代码,来完成向产品表中添加数据的工作。这就需要使用Product的create()方法了。下面就是想要的文件。不需要手动输入,你可以直接拷贝走或者下载我托管到Github上的源代码。
相关图片,你需要拷贝到你应用的%depot%/app/assets/image/目录下。注意:这个seeds.rb脚本文件会删除products表中已有的数据。也许,你不想让其删除你自己耗费数小时,辛辛苦苦一点点输入的数据。
D呱呱
D瓜哥将这个应用的源代码都托管到了Github上。下载链接如下:完整项目的代码,https://github.com/diguage/depot;另外,针对本节的代码:开始之前,https://github.com/diguage/depot/tree/v-06.1;本节完成后,https://github.com/diguage/depot/tree/v-06.2。
刚刚检查一下D瓜哥项目中的种子文件内容,由于D瓜哥的失误,这个种子文件没有添加进去相应的内容,请大家到本书作者提供的网站上下载,网站:http://media.pragprog.com/titles/rails4/code/rails32/depot_a/db/seeds.rb
03 | Product.create(title: 'CoffeeScript' , |
06 | CoffeeScript is JavaScript done right. It provides all of JavaScript's |
07 | functionality wrapped in a cleaner, more succinct syntax. In the first |
08 | book on this exciting new language, CoffeeScript guru Trevor Burnham |
09 | shows you how to hold onto all the power and flexibility of JavaScript |
10 | while writing clearer, cleaner, and safer code. |
15 | Product.create(title: 'Programming Ruby 1.9' , |
18 | Ruby is the fastest growing and most exciting dynamic language |
19 | out there. If you need to get working programs delivered fast, |
20 | you should add Ruby to your toolbox. |
22 | image_url: 'ruby.jpg' , |
26 | Product.create(title: 'Rails Test Prescriptions' , |
29 | <em>Rails Test Prescriptions</em> is a comprehensive guide to testing |
30 | Rails applications, covering Test-Driven Development from both a |
31 | theoretical perspective (why to test) and from a practical perspective |
32 | (how to test effectively). It covers the core Rails testing tools and |
33 | procedures for Rails 2 and Rails 3 , and introduces popular add-ons, |
34 | including Cucumber, Shoulda, Machinist, Mocha, and Rcov. |
(你可以已经注意到,这里使用了%{…}。这是定义字符串的又一种语法,和双引号功能相同,在遇到长语句或者需要换号的时候使用很方便。另外还需要注意,因为使用了Rails的create()方法,如果因为验证失败而导致不能插入数据时,该方法会”悄无声息”地失败掉。)
执行如下命令,将测试数据插入到products表中:
现在,让我们来收拾一下商品列表展示。这里有两步要走,以定义一组样式规则,二通过向HTML标签添加class属性,让样式在相应的页面生效。
我们需要一个地方来放置我们的样式定义。正如之前你使用的Rails那样,按照惯例,generate scaffold命令已经在幕后生成相关的文件。我们只需要将样式添加到空样式文件products.css.scss中即可,这个文件在%depot%/app/assets/stylesheets/目录下。
D呱呱
这里定义样式使用的是Sass。Sass是程序化的CSS。使用教程:“Sass使用介绍”;官方教程:“入门教程(英文)”
01 | // Place all the styles related to the Products controller here. |
02 | // They will automatically be included in application.css. |
07 | border-collapse : collapse ; |
仔细看这个样式定义文件,你会发现CSS规则是嵌套的,针对dl定义的规则在.list_description规则的里面,它本身就是定义在产品规则里面的。这可以减少规则重复出现的可能性,更加容易阅读、编写、理解以及维护。
这点,你应该熟悉以.erb结尾的文件,它们会预处理嵌在其中的Ruby表达式和语句。如果你注意到这个文件是以scss结尾的,你也许会猜到这个文件是Sassy CSS,处理后可以生产css文件。
D呱呱
这里,D瓜哥要着重指出,书中并没有提如果处理这个文件。但是,如果你不处理,样式根本无法生效。在以前的版本中,是个CSS文件,虽然使用方式不妥,但是你拷贝到%depot%/public/assets/目录下,也能生效。但是,现在Sass,必须经过处理才能生效。那么该如何处理呢?其实,很简单,只需要一条命令即可:
编译之后,会在%depot%/public/assets/目录下生成相应的CSS文件,同时图片也会自动拷贝到这个目录下。
D瓜哥在“《Agile Web Development with Rails》抄书笔记(02):Rails之初体验”中给出了部分命令。但是,这个命令不够全面。再给大家一个全面的:“Rails命令”
同样,就像ERb文件,SCSS不访问编写正确的CSS。SCSS提供了一种额外的语法,可以让样式文件更加容易编写和维护。你所写的所有的SCSS都可以转化成浏览器可以处理的标准的CSS。
最后,我们还需要定义一下商品的class属性。如果你在刚刚创建的.html.erb文件中查找,那么你找不到任何引用样式文件的地方。你甚至找不到标签。取而代之的是,Rails单独创建了一个用于整个应用的标准页面,这个文件被命名为application.html.erb,可以控制网页的整体布局,文件在%depot%/app/views/layouts/目录下。修改文件的代码如下:
05 | <%= stylesheet_link_tag "application", :media => "all" %> |
06 | <%= javascript_include_tag "application" %> |
09 | < body class="<%= controller.controller_name %>"> |
因为Rails会加载所有的样式文件,所以我们需要建立一个约定,想限制一个样式文件只针对相应的Controller页面生效。使用Controller名称作为class属性的名称是一个简单实现方法。上面的代码修改正是完成这个工作。
现在,我们拥有了所需的样式文件,我们还修改模板,来自定义展示效果。编辑在%depot%/app/views/products/目录下的index.html.erb文件,删除默认生成的视图代码,将其修改成如下代码:
01 | < h1 >Listing products</ h1 > |
04 | <% @products.each do |product| %> |
05 | < tr class="<%= cycle('list_line_odd', 'list_line_even') %>"> |
07 | <%= image_tag(product.image_url, class: 'list_image') %> |
10 | < td class = "list_desctiption" > |
12 | < dt ><%= product.title %></ dt > |
13 | < dd ><%= truncate(strip_tags(product.description), length: 80) %></ dd > |
16 | < td class = "list_action" > |
17 | <%= link_to 'Show', product %>< br /> |
18 | <%= link_to 'Edit', edit_product_path(product) %>< br /> |
19 | <%= link_to 'Destroy', product, method: :delete, data: { confirm: 'Are you sure?' } %> |
27 | <%= link_to 'New Product', new_product_path %> |
虽然这个模板很简单,但是它还是使用了一些Rails内建的特性:
- 列表中的行背景色交替显示。Rails的辅助方法cycle()来设置每列的CSS class属性,list_line_even或者list_line_odd,而且会在相邻两行之间交替出现。
- truncate()辅助方法用于展示商品描述的前八十个字符。在调用truncate()方法之前,调用strip_tags()可以将描述中的HTML标签删除掉。
- 注意看”link_to ‘Destroy’”那行,看看为啥有参数”confirm:’Areyou sure?’”。如果你点击这个链接,Rails会让你浏览器弹出来一个对话框,来询问你是否确认删除商品。(下面我们会专门说明一下弹出框)
method: :delete是何须玩意?
你也许注意到了生成了的Destroy链接包含一个参数method::delete。这个决定调用ProductsController 中的哪个方法,同时影响HTTP的方法。
浏览器使用HTTP和服务器进行交流。HTTP协议定义了一组可以让浏览器采用的动词(一般说成HTTP方法),同时协议规定了使用时机。举例说明一下,一个常规的超链接,使用HTTP的Get请求。Get请求被定义用来获取数据,它不应该产生其他的影响。显式声明使用这个参数,是说明这个链接使用HTTP的DELETE方法。Rails使用这个信息来决定应该将这个请求路由给Controller中的那个action方法。
注意,当在浏览器中使用时,Rails会使用POST HTTP方法代替PUT和DELETE方法,并添加一个额外的参数,这样Router就能确定最初是使用哪个方法了。无论使用哪个方式,这个请求都不会被Web爬虫缓存或爬取。
我们向数据库中添加了一些测试数据,我还重写了展示商品列表的index.html.erb文件,我们还填充了products.css.scss文件中的样式,同时样式也会通过布局文件application.html.erb加载到我们的页面。现在,启动服务器,打开浏览器,输入http://localhost:3000/products,商品列表美好后的结果是否如下显示的这样呢?

我们将我们的成果展示给客户,她很满意。
上一节内容和本节内容是本书的第五章,一个迭代。这两节,我们完成了网店的后台开发。具体如下:
- 我们创建了开发库;
- 我们使用迁移脚本创建并修改了数据库;
- 我们创建了products表,同时使用生成器创建了一个应用来维护表中的数据;
- 我们更新了一个应用级别的布局,将页面展示对应到相应Controller视图,方便展示商品列表;
下一步,我们该创建网店的前台页面了。
按照步骤做了,可是样式表还是不生效啊!
我给你发邮件了,有我的联系方式,直接加我好友,给我留言吧。哈哈
楼主是个大好人!好人一生平安!
样式表没生效。