# 2.3 微博资源
我们已经生成并浏览了用户资源,现在要生成微博资源。阅读本节时,我推荐你和 [2.2 节](#the-users-resource)对比一下。你会发现两个资源在很多方面都是一致的。通过这样重复生成资源,我们可以更好地理解 Rails 中的 REST 架构。在这样的早期阶段看一下用户资源和微博资源的相同之处,也是本章的主要目的之一。
## 2.3.1 概览微博资源
和用户资源一样,我们使用 `rails generate scaffold` 命令生成微博资源的代码,不过这一次要实现[图 2.3](#fig-demo-micropost-model) 中的数据模型:[[8](#fn-8)]
```
$ rails generate scaffold Micropost content:text user_id:integer
invoke active_record
create db/migrate/20140821012832_create_microposts.rb
create app/models/micropost.rb
invoke test_unit
create test/models/micropost_test.rb
create test/fixtures/microposts.yml
invoke resource_route
route resources :microposts
invoke scaffold_controller
create app/controllers/microposts_controller.rb
invoke erb
create app/views/microposts
create app/views/microposts/index.html.erb
create app/views/microposts/edit.html.erb
create app/views/microposts/show.html.erb
create app/views/microposts/new.html.erb
create app/views/microposts/_form.html.erb
invoke test_unit
create test/controllers/microposts_controller_test.rb
invoke helper
create app/helpers/microposts_helper.rb
invoke test_unit
create test/helpers/microposts_helper_test.rb
invoke jbuilder
create app/views/microposts/index.json.jbuilder
create app/views/microposts/show.json.jbuilder
invoke assets
invoke coffee
create app/assets/javascripts/microposts.js.coffee
invoke scss
create app/assets/stylesheets/microposts.css.scss
invoke scss
identical app/assets/stylesheets/scaffolds.css.scss
```
如果看到 Spring 相关的错误,再次执行这个命令即可。
然后,和 [2.2 节](#the-users-resource)一样,我们要执行迁移,更新数据库,使用新建的数据模型:
```
$ bundle exec rake db:migrate == CreateMicroposts: migrating ===============================================
-- create_table(:microposts)
-> 0.0023s
== CreateMicroposts: migrated (0.0026s) ======================================
```
现在我们就可以使用类似 [2.2.1 节](#a-user-tour)中介绍的方法来创建微博了。你可能猜到了,脚手架还会更新 Rails 的路由文件,为微博资源加入一条规则,如[代码清单 2.8](#listing-demo-microposts-resource) 所示。[[9](#fn-9)]和用户资源类似,`resources :micropsts` 把微博相关的 URL 映射到 `MicropostsController`,如[表 2.3](#table-demo-restful-microposts) 所示。
##### 代码清单 2.8:Rails 的路由,有一条针对微博资源的新规则
config/routes.rb
```
Rails.application.routes.draw do
resources :microposts resources :users
.
.
.
end
```
表 2.3:[代码清单 2.8](#listing-demo-microposts-resource) 中微博资源生成的符合 REST 架构的路由
| HTTP 请求 | URL | 动作 | 作用 |
| --- | --- | --- | --- |
| `GET` | /microposts | `index` | 列出所有微博 |
| `GET` | /microposts/1 | `show` | 显示 ID 为 1 的微博 |
| `GET` | /microposts/new | `new` | 显示创建新微博的页面 |
| `POST` | /microposts | `create` | 创建新微博 |
| `GET` | /microposts/1/edit | `edit` | 显示编辑 ID 为 1 的微博页码 |
| `PATCH` | /microposts/1 | `update` | 更新 ID 为 1 的微博 |
| `DELETE` | /microposts/1 | `destroy` | 删除 ID 为 1 的微博 |
`MicropostsController` 的代码简化后如[代码清单 2.9](#listing-demo-microposts-controller) 所示。注意,除了把 `UsersController` 换成 `MicropostsController` 之外,这段代码和[代码清单 2.4](#listing-demo-users-controller) 没什么区别。这说明了两个资源在 REST 架构中的共同之处。
##### 代码清单 2.9:简化后的 `MicropostsController`
app/controllers/microposts_controller.rb
```
class MicropostsController < ApplicationController
.
.
.
def index
.
.
.
end
def show
.
.
.
end
def new
.
.
.
end
def edit
.
.
.
end
def create
.
.
.
end
def update
.
.
.
end
def destroy
.
.
.
end
end
```
我们在发布微博的页面([/microposts/new](http://localhost:3000/microposts/new))输入一些内容,发布一篇微博,如[图 2.12](#fig-demo-new-micropost) 所示。
既然已经打开这个页面了,那就多发布几篇微博,并且确保至少把一篇微博的 `user_id` 设为 `1`,把微博赋予 [2.2.1 节](#a-user-tour)中创建的第一个用户。结果应该和[图 2.13](#fig-demo-micropost-index) 类似。
![demo new micropost 3rd edition](https://box.kancloud.cn/2016-05-11_5732bcb5624cb.png)图 2.12:发布微博的页面![demo micropost index 3rd edition](https://box.kancloud.cn/2016-05-11_5732bcf16fc97.png)图 2.13:微博索引页([/microposts](http://localhost:3000/microposts))
## 2.3.2 限制微博内容的长度
如果要称得上“微博”这个名字,就要限制内容的长度。在 Rails 中实现这种限制很简单,使用验证(validation)功能即可。要限制微博的长度最大字数为 140 个字符(就像 Twitter 一样),我们可以使用长度验证。在文本编辑器或 IDE 中打开 `app/models/micropost.rb`,写入[代码清单 2.10](#listing-demo-length-validation) 中的代码。
##### 代码清单 2.10:限制微博的长度最多为 140 个字符
app/models/micropost.rb
```
class Micropost < ActiveRecord::Base
validates :content, length: { maximum: 140 } end
```
这段代码看起来可能很神秘,我们会在 [6.2 节](chapter6.html#user-validations)详细介绍验证。如果我们在发布微博的页面输入超过 140 个字符的内容,就能看出这个验证的作用了。如[图 2.14](#fig-micropost-length-error) 所示,Rails 会渲染错误信息,提示微博的内容太长了。([7.3.3 节](chapter7.html#signup-error-messages)会详细介绍错误信息。)
![micropost length error 3rd edition](https://box.kancloud.cn/2016-05-11_5732bcf185ff4.png)图 2.14:发布微博失败时显示的错误消息
## 2.3.3 一个用户拥有多篇微博
Rails 最强大的功能之一是,可以在不同的数据模型之间建立关联(association)。对本例中的用户模型而言,每个用户可以拥有多篇微博。我们可以更新用户模型(参见[代码清单 2.11](#listing-demo-user-has-many-microposts))和微博模型(参见[代码清单 2.12](#listing-demo-micropost-belongs-to-user))的代码实现这种关联。
##### 代码清单 2.11:一个用户拥有多篇微博
app/models/user.rb
```
class User < ActiveRecord::Base
has_many :microposts end
```
##### 代码清单 2.12:一篇微博属于一个用户
app/models/micropost.rb
```
class Micropost < ActiveRecord::Base
belongs_to :user validates :content, length: { maximum: 140 }
end
```
我们可以把这种关联用[图 2.15](#fig-micropost-user-association) 中的图标表示出来。因为 `microposts` 表中有 `user_id` 这一列,所以 Rails(通过 Active Record)能把微博和各个用户关联起来。
![micropost user association](https://box.kancloud.cn/2016-05-11_5732bcf19aab3.png)图 2.15:微博和用户之间的关联
在[第 11 章](chapter11.html#user-microposts)和[第 12 章](chapter12.html#following-users),我们会使用微博和用户之间的关联显示一个用户的所有微博,还会生成一个和 Twitter 类似的微博列表。现在,我们可以在控制台(console)中检查用户与微博之间的关联。控制台是和 Rails 应用交互很有用的工具。在命令行中执行 `rails console` 命令,启动控制台。然后输入 `User.first`,从数据库中读取第一个用户,并把得到的数据赋值给 `first_user` 变量:[[10](#fn-10)]
```
$ rails console >> first_user = User.first
=> #<User id: 1, name: "Michael Hartl", email: "michael@example.org",
created_at: "2014-07-21 02:01:31", updated_at: "2014-07-21 02:01:31">
>> first_user.microposts
=> [#<Micropost id: 1, content: "First micropost!", user_id: 1, created_at:
"2014-07-21 02:37:37", updated_at: "2014-07-21 02:37:37">, #<Micropost id: 2,
content: "Second micropost", user_id: 1, created_at: "2014-07-21 02:38:54",
updated_at: "2014-07-21 02:38:54">]
>> micropost = first_user.microposts.first # Micropost.first would also work.
=> #<Micropost id: 1, content: "First micropost!", user_id: 1, created_at:
"2014-07-21 02:37:37", updated_at: "2014-07-21 02:37:37">
>> micropost.user
=> #<User id: 1, name: "Michael Hartl", email: "michael@example.org",
created_at: "2014-07-21 02:01:31", updated_at: "2014-07-21 02:01:31">
>> exit
```
我在这段代码的最后一行加上了 `exit`,告诉你如何退出终端。在大多数系统中也可以按 Ctrl-D 键。[[11](#fn-11)] 我们使用 `first_user.microposts` 获取这个用户发布的微博。Active Record 会自动返回 `user_id` 和 `first_user` 的 ID(`1`)相同的所有微博。在[第 11 章](chapter11.html#user-microposts)和[第 12 章](chapter12.html#following-users)中,我们会更深入地学习关联的这种用法。
## 2.3.4 继承体系
接下来简要介绍 Rails 中控制器和模型的类继承。 如果你有面向对象编程(Object-oriented Programming,简称 OOP)的经验,能更好地理解这些内容。如果你未接触过 OOP 的话,可以跳过这一节。一般来说,如果你不熟悉类的概念([4.4 节](chapter4.html#ruby-classes)中会介绍),我建议你以后再回过头来读这一节。
我们先介绍模型的继承结构。对比一下[代码清单 2.13](#listing-demo-user-class) 和[代码清单 2.14](#listing-demo-micropost-class) ,可以看出,`User` 和 `Micropost` 都(通过 `<` 符号)继承自 `ActiveRecord::Base`,这是 Active Record 为模型提供的基类。[图 2.16](#fig-demo-model-inheritance) 列出了这种继承关系。通过继承 `ActiveRecord::Base`,模型对象才能与数据库通讯,才能把数据库中的列看做 Ruby 中的属性,等等。
##### 代码清单 2.13:`User` 类中的继承
app/models/user.rb
```
class User < ActiveRecord::Base
.
.
.
end
```
##### 代码清单 2.14:`Mcropost` 类中的继承
app/models/micropost.rb
```
class Micropost < ActiveRecord::Base
.
.
.
end
```
![demo model inheritance](https://box.kancloud.cn/2016-05-11_5732bcf1afbb0.png)图 2.16:用户模型和微博模型中的继承体系
控制器的继承结构稍微复杂一些。对比[代码清单 2.15](#listing-demo-users-controller-class) 和[代码清单 2.16](#listing-demo-microposts-controller-class),可以看出,`UsersController` 和 `Microposts Controller` 都继承自 `ApplicationController`。如[代码清单 2.17](#listing-toy-application-controller-class) 所示,`ApplicationController` 继承自 `ActionController::Base`。`ActionController::Base` 是 Rails 中 Action Pack 库为控制器提供的基类。这些类之间的关系如[图 2.17](#fig-demo-controller-inheritance) 所示。
##### 代码清单 2.15:`UsersController` 类中的继承
app/controllers/users_controller.rb
```
class UsersController < ApplicationController
.
.
.
end
```
##### 代码清单 2.16:`MicropostsController` 类中的继承
app/controllers/microposts_controller.rb
```
class MicropostsController < ApplicationController
.
.
.
end
```
##### 代码清单 2.17:`ApplicationController` 类中的继承
app/controllers/application_controller.rb
```
class ApplicationController < ActionController::Base
.
.
.
end
```
![demo controller inheritance](https://box.kancloud.cn/2016-05-11_5732bcf1c0398.png)图 2.17:`UsersController` 和 `MicropostsController` 中的继承体系
和模型的继承类似,通过继承 `ActionController::Base`,`UsersController` 和 `MicropostsController` 获得了很多功能。例如,处理模型对象的能力,过滤输入的 HTTP 请求,以及把视图渲染成 HTML。Rails 应用中的所有控制器都继承 `ApplicationController`,所以其中定义的规则会自动运用于应用中的的每个动作。例如,[8.4 节](chapter8.html#remember-me)会介绍如何在 `ApplicationController` 中引入辅助方法,为整个应用的所有控制器都加上登录和退出功能。
## 2.3.5 部署这个玩具应用
完成微博资源之后,是时候把代码推送到 Bitbucket 的仓库中了:
```
$ git status
$ git add -A
$ git commit -m "Finish toy app"
$ git push
```
通常情况下,你应该经常做一些很小的提交,不过对于本章来说,最后做一次大提交也无妨。
然后,你也可以按照 [1.5 节](chapter1.html#deploying)介绍的方法,把这个应用部署到 Heroku:
```
$ git push heroku
```
执行这个命令的前提是,你已经按照 [2.1 节](#planning-the-application)中的说明创建了 Heroku 应用。否则,应该先执行 `hreoku create`,然后再执行 `git push heroku master`。
然后还要执行下面的命令迁移生产环境的数据库,这样应用才能使用数据库:
```
$ heroku run rake db:migrate
```
这个命令会按照用户和微博的数据模型更新 Heroku 中的数据库。迁移数据库之后,就可以在生产环境中使用这个应用了,如[图 2.18](#fig-toy-app-production) 所示,而且这个应用使用 PostgreSQL 数据库。
![toy app production](https://box.kancloud.cn/2016-05-11_5732bcf1d899f.png)图 2.18:运行在生产环境中的玩具应用
- Ruby on Rails 教程
- 致中国读者
- 序
- 致谢
- 作者译者简介
- 版权和代码授权协议
- 第 1 章 从零开始,完成一次部署
- 1.1 简介
- 1.2 搭建环境
- 1.3 第一个应用
- 1.4 使用 Git 做版本控制
- 1.5 部署
- 1.6 小结
- 1.7 练习
- 第 2 章 玩具应用
- 2.1 规划应用
- 2.2 用户资源
- 2.3 微博资源
- 2.4 小结
- 2.5 练习
- 第 3 章 基本静态的页面
- 3.1 创建演示应用
- 3.2 静态页面
- 3.3 开始测试
- 3.4 有点动态内容的页面
- 3.5 小结
- 3.6 练习
- 3.7 高级测试技术
- 第 4 章 Rails 背后的 Ruby
- 4.1 导言
- 4.2 字符串和方法
- 4.3 其他数据类型
- 4.4 Ruby 类
- 4.5 小结
- 4.6 练习
- 第 5 章 完善布局
- 5.1 添加一些结构
- 5.2 Sass 和 Asset Pipeline
- 5.3 布局中的链接
- 5.4 用户注册:第一步
- 5.5 小结
- 5.6 练习
- 第 6 章 用户模型
- 6.1 用户模型
- 6.2 用户数据验证
- 6.3 添加安全密码
- 6.4 小结
- 6.5 练习
- 第 7 章 注册
- 7.1 显示用户的信息
- 7.2 注册表单
- 7.3 注册失败
- 7.4 注册成功
- 7.5 专业部署方案
- 7.6 小结
- 7.7 练习
- 第 8 章 登录和退出
- 8.1 会话
- 8.2 登录
- 8.3 退出
- 8.4 记住我
- 8.5 小结
- 8.6 练习
- 第 9 章 更新,显示和删除用户
- 9.1 更新用户
- 9.2 权限系统
- 9.3 列出所有用户
- 9.4 删除用户
- 9.5 小结
- 9.6 练习
- 第 10 章 账户激活和密码重设
- 10.1 账户激活
- 10.2 密码重设
- 10.3 在生产环境中发送邮件
- 10.4 小结
- 10.5 练习
- 10.6 证明超时失效的比较算式
- 第 11 章 用户的微博
- 11.1 微博模型
- 11.2 显示微博
- 11.3 微博相关的操作
- 11.4 微博中的图片
- 11.5 小结
- 11.6 练习
- 第 12 章 关注用户
- 12.1 “关系”模型
- 12.2 关注用户的网页界面
- 12.3 动态流
- 12.4 小结
- 12.5 练习