第二章 Rails 中的资源

课程概要:

本课程讲解 Rails 中的资源,通过 scaffold 命令创建资源,并对资源文件的类型、REST 风格设计及路由文件进行讲解,理解 Rails 如何在 REST 架构下如何进行资源的管理。

知识点:

  1. scaffold 命令
  2. REST
  3. routes

课程背景

Rails 是 REST 风格的 web 开发框架,通过本课程的学习,可以理解 Rails 是如何通过对资源的管理,实现 REST 架构的。

2.1 应用 scaffold 命令创建资源

概要:

本课时详细介绍 Rails 中的命令,以及使用 scaffold 命令创建的资源文件,如 erb 文件,测试文件,sass 文件等。

知识点:

  1. scaffold
  2. sass/scss
  3. coffeescript
  4. erb
  5. rspec

正文

2.1.1 rails 命令

上一节,我们用 new 创建了一个 Rails 项目,并且使用了下面的命令,创建了商品(Product)这个资源:

  1. % rails g scaffold product name price:decimal description:text

g 是 generate 的缩写,Rails 还为我们提供了几个类似的命令:

  1. % rails -h
  2. generate 生成资源文件 (简写 "g")
  3. console 运行调试控制台 (简写 "c")
  4. server 运行 Rails 服务 (简写 "s")
  5. dbconsole 运行数据库调试控制台 (简写 "db")
  6. new 创建新的 Rails 项目。 你也可以 "rails new ." 它会在当前目录下创建
  7. destroy 删除 "generate" 创建的文件 (简写 "d")
  8. plugin new 创建一个 plugin
  9. runner Rails 环境下,执行一段 Ruby 代码

我们用 generate 可以创建资源,同样也可以用 destroy 删除这个资源,比如:

  1. % rails destroy scaffold product

我们已经使用 server 命令运行了项目,但是,有时候我们不一定要在 web 页面上做操作,为了方便调试,我们可以已进入到互动终端,也就是 console 中:

  1. % rails console
  2. > Product.first
  3. Product Load (0.2ms) SELECT "products".* FROM "products" ORDER BY "products"."id" ASC LIMIT 1
  4. => nil
  5. > exit

在 console 里,我们可以方便的操作数据库,下一章我们会重点讲解数据库部分。

和 console 类似,dbconsole 可以进入到数据库的互动终端里,具体的命令取决去使用的哪个数据库,rails 只是为我们提供了一个方便的连接数据库方式。

plugin 命令可以为一个独立的功能创建专属的代码,并且存在与该 Rails 项目中,在 Rails 3 之后,越来越多的功能使用 gem 来实现,plugin 较少使用了。

和 console 的交互式操作不同,runner 可以执行一段代码,相同的是,它们都拥有当前项目完整的 Rails 环境。我们可以使用执行一个文件,比如:

  1. % rails runner lib/somefile.rb

在这个 file 里,可以实现一些功能,这和 rake 的实现方式较接近。

2.1.2 scaffold 命令

回到我们经常使用的 generate 命令,先查看帮助文档:

  1. % rails generate -h

我们看到,generate 可以创建很多类型的文件,比如 model,controller,assets 文件等,这些都是一个 Rails 资源所需要。我们可以分别执行 generate 命令,也可以把它们一次都执行,这就是 scaffold。

scaffold 的中文称呼是 “脚手架”,个人觉得它不是很形象,如果称它为“一大堆 generator(生成器) 的集合”,似乎形象很多。Rails 为我们提供了一些 generator,我们也可以编写自己的 generator。

再来看看 scaffold 的语法结构:

  1. % rails g scaffold [资源名] [属性列表] [选项]

为了使我们的网店更接近实际应用,我们再增加一个资源:商品类型(Variant)

  1. % rails g scaffold variants product_id:integer price:decimal{'8,2'} size

variants 是资源的名称,它可以是单数,我们创建商品时用的就是单数形式。属性列表里,属性名称和属性的类型,使用 : 来分开,默认的类型是 string,所以 color 的后面没有声明它是什么类型,那么它就是 string 类型。

当我们创建价格类型的时候,decimal 可以增加两个具体参数:precision 和 scale,每个数据库的默认值是不同的,我们可以查看这里:

RMDB 的decimal 默认值

我们打开 config/routes.rb,可以看到这样两行代码已经添加了:

生成文件的时候,我们注意到这一行:

  1. ...
  2. resources :products
  3. resources :variants
  4. ...

这就是我们定义的资源。其实,我们说 URL 中的 R 就是这个资源 Resource 的意思。我们可以这样理解 Rails:

Rails 是从管理资源开始的。

我们还可以配置 scaffold,让它跳过一些不必要的文件,配置写在 config/application.rb 中:

  1. class Application < Rails::Application
  2. ...
  3. config.generators do |cfg|
  4. cfg.stylesheets false
  5. cfg.javascripts false
  6. cfg.helpers false
  7. end

这样,scaffold 命令就不再创建 helper,css,js 文件了。但在我们学习初期阶段,先不这么做。

2.1.3 sass/scss

创建的文件中,我们看到了 .scss 的文件,其实,它是 sass 文件,一种 css 的预处理文件,它的后缀有两种:.scss.sassscss 语法更接近 css 本身,你可以直接粘贴 css 来使用。sass 语法更加简洁,它去掉了 ;{} 这些符号,并且使用空格,作为语法缩进。

使用 sass,可以使用预定义变量,使用语法嵌套,代码混入等多种编程风格的代码,编写 css,并且在编译成 css 文件的过程中,还可以进行语法检查。

sass 和 scss 写法上的不同,可以在 http://sass-lang.com/guide (中文文档)看到。

如果你想在两种文件间转换,可以使用这个命令:

  1. # Convert Sass to SCSS
  2. % sass-convert style.sass style.scss
  3. # Convert SCSS to Sass
  4. % sass-convert style.scss style.sass

SASS用法指南 一文里有更详细的介绍。

Rails 默认使用的是 sass,这里是它 github 的地址,

在我们的 css 文件中,经常会使用图片文件,比如 background-image 属性,但是我们的图片是放在 assets 文件夹中的,我们可以有三种方式来使用图片。

第一种,直接粘贴图片地址,比如:

  1. background-image: url("/assets/logo.png");

这是很不好的,它不能使用 digest 方式来使用图片资源,也不够灵活。

第二种,将图片文件放到 public 下,比如:

  1. background-image: url("/images/logo.png");

这需要我们在 public 下建立一个 images 文件夹来管理图片文件,也不能使用 digest。

第三种,直接使用 sass-rails 提供的辅助方法

  1. background-image: asset-url('logo.png');

当然,我也见到过第四种方法,使用 erb 来重构 sass,文件可能是这样的,style.css.scss.erb,这样就可以在 scss 里插入 erb 的语法:

  1. background-image: url(<%= asset_path 'logo.png' %>);

在 Rails 里是可以这么写的,它会先解析 erb 文件,再解析 sass 文件,生成 css。但是我不建议这么处理问题,在我们使用一个不熟悉的方法解决问题时,应该多耐心看一看它的文档。不知道这里给出的众多链接,大家是否查看了,他们都是对内容很好的补充。

和 sass 一样,Less 也是 css 的预编译工具,如果你留意 bootstrap 的介绍,它的 css 文件就是用 less 编写的。

2.1.4 coffeescript

.coffee 是 js 的预处理文件,它是用 coffeescript 编写的。学习它很简单,只要看看http://coffeescript.org/ 就可以了,中文在 http://coffee-script.org/

scss 和 coffeescript 的目标,是让代码更简洁,易维护。预处理还可以帮你检查语法上的错误。

在我们安装完 bootstrap 后,会给出一个 coffee 文件:

  1. jQuery ->
  2. $("a[rel~=popover], .has-popover").popover()
  3. $("a[rel~=tooltip], .has-tooltip").tooltip()

2.1.5 erb

最后,我们说说 erb。

erb 是 Ruby 的标准库(Standard Library)之一, 它允许是把 Ruby 代码签入到 html 中。

一个简单的例子,我们进入到 irb 中:

  1. % require "erb"
  2. % name = "Ruby"
  3. % ERB.new("My name is #{name}").result
  4. => "My name is Ruby"

好了,文件都介绍完了,我们看一下效果吧,我们使用下面的命令:

  1. % rake db:migrate [1]
  2. % rails s [2]
  • [1] 更新数据库
  • [2] 启动 Rails 服务,s 是 server 的简写

访问 http://localhost:3000/products,试试上面的按钮,体验一下如何增加,修改,删除一个商品(Product)吧。

2.1.6 测试

除了上面介绍的,scaffold 还为我们添加了测试文件 test/models/product_test.rbtest/controllers/products_controller_test.rb

这里,Rails 默认使用的是 minitest,更多介绍可以看这里。我们也可以使用其他的测试框架,比如 Rspec。

我们可以修改 Gemfile

  1. group :development, :test do
  2. gem 'rspec-rails'
  3. end

运行 rspec 的 generator:

  1. % rails generate rspec:install
  2. create .rspec
  3. create spec
  4. create spec/spec_helper.rb
  5. create spec/rails_helper.rb

我们补上 Model 和 Controller 的测试文件:

  1. rails generate rspec:model product
  2. rails generate rspec:controller products

最后,我们在 Rails 项目文件夹中运行这个命令:

  1. % rspec
  2. **
  3. Pending: (Failures listed here are expected and do not affect your suite's status)
  4. 1) ProductsController
  5. # Not yet implemented
  6. # ./spec/controllers/products_controller_spec.rb:4
  7. 2) Product add some examples to (or delete) /Users/liwei/Desktop/Rails_practice_p1_0/code/chapter_2/shop/spec/models/product_spec.rb
  8. # Not yet implemented
  9. # ./spec/models/product_spec.rb:4
  10. Finished in 0.00058 seconds (files took 1.6 seconds to load)

我们看到测试文件已经可以运行了,虽然我们还未给它写一行测试用例(Test Case)。

在后面 MVC 开发的部分,我们会继续添加它的代码。Rspec 的代码和文档在这里:

https://github.com/rspec/rspec

让 Rspec 集成到 Rails 中的方法是安装 rspec-rails

  1. group :development, :test do
  2. gem 'rspec-rails', '~> 3.0'
  3. end

https://github.com/rspec/rspec-rails

下一节,我们将深入 Rails 中,了解它的核心概念:REST。