# 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) 類似。
圖 2.12:發布微博的頁面圖 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)會詳細介紹錯誤信息。)
圖 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)能把微博和各個用戶關聯起來。
圖 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
```
圖 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
```
圖 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 數據庫。
圖 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 練習