# 1.3 第一個應用
按照計算機編程領域[長期沿用的傳統](http://www.catb.org/jargon/html/H/hello-world.html),第一個應用的目的是編寫一個“hello, world”程序。具體說來,我們要創建一個簡單的應用,在網頁中顯示字符串“hello, world!”,在開發環境([1.3.4 節](#hello-world))和線上網站中([1.5 節](#deploying))都是如此。
Rails 應用一般都從 `rails new` 命令開始,這個命令會在你指定的文件夾中創建一個 Rails 應用骨架。如果沒使用[1.2.1 節](#development-environment)推薦的 Cloud9 IDE,首先你要新建一個文件夾,命名為 `workspace`,然后進入這個文件夾,如[代碼清單 1.2](#listing-mkdir-rails-projects) 所示。([代碼清單 1.2](#listing-mkdir-rails-projects) 中使用了 Unix 命令 `cd` 和 `mkdir`,如果你不熟悉這些命令,可以閱讀[旁注 1.3](#aside-unix-commands)。)
##### 代碼清單 1.2:為 Rails 項目新建一個文件夾,命名為 `workspace`(在云端環境中不用這一步)
```
$ cd # 進入家目錄
$ mkdir workspace # 新建 workspace 文件夾
$ cd workspace/ # 進入 workspace 文件夾
```
##### 旁注 1.3:Unix 命令行速成課
使用 Windows 和 Mac OS X(數量較少,但增長勢頭迅猛)的用戶可能對 Unix 命令行不熟悉。如果使用推薦的云端環境,很幸運,這個環境提供了 Unix(Linux)命令行——在標準的 [shell 命令行界面](http://en.wikipedia.org/wiki/Shell_(computing))中運行的 [Bash](http://en.wikipedia.org/wiki/Bash_(Unix_shell))。
命令行的基本思想很簡單:使用簡短的命令執行很多操作,例如創建文件夾(`mkdir`),移動和復制文件(`mv` 和 `cp`),以及變換目錄瀏覽文件系統(`cd`)。主要使用圖形化界面(Graphical User Interface,簡稱 GUI)的用戶可能覺得命令行落后,其實是被表象蒙蔽了:命令行是開發者最強大的工具之一。其實,你經常會看到經驗豐富的開發者開著多個終端窗口,運行命令行 shell。
這是一門很深的學問,但在本書中只會用到一些最常用的 Unix 命令行命令,如[表 1.1](#table-unix-commands)所示。若想更深入地學習 Unix 命令行,請閱讀 Mark Bates 寫的《[Conquering the Command Line](http://conqueringthecommandline.com/)》(可以[免費在線閱讀](http://conqueringthecommandline.com/book),也可以[購買電子書和視頻](http://conqueringthecommandline.com/#pricing))。
表 1.1:一些常用的 Unix 命令
| 作用 | 命令 | 示例 |
| --- | --- | --- |
| 列出內容 | `ls` | `$ ls -l` |
| 新建文件夾 | `mkdir <dirname>` | `$ mkdir workspace` |
| 變換目錄 | `cd <dirname>` | `$ cd workspace/` |
| 進入上層目錄 | `$ cd ..` |
| 進入家目錄 | `$cd ~` 或 `$ cd` |
| 進入家目錄中的文件夾 | `$ cd ~/workspace/` |
| 移動文件(重命名) | `mv <source> <target>` | `$ mv README.rdoc README.md` |
| 復制文件 | `cp <source> <target>` | `$ cp README.rdoc README.md` |
| 刪除文件 | `rm <file>` | `$ rm README.rdoc` |
| 刪除空文件夾 | `rmdir <directory>` | `$ rmdir workspace/` |
| 刪除非空文件夾 | `rm -rf <directory>` | `$ rm -rf tmp/` |
| 連結并顯示文件的內容 | `cat <file>` | `$ cat ~/.ssh/id_rsa.pub` |
不管在本地環境,還是在云端 IDE 中,下一步都是使用[代碼清單 1.3](#listing-rails-command)中的命令創建第一個應用。注意,在這個代碼清單中,我們明確指定了 Rails 版本(`4.2.2`)。這么做的目的是,確保使用[代碼清單 1.1](#listing-installing-rails)中安裝的 Rails 版本來創建這個應用的文件夾結構。(執行[代碼清單 1.3](#listing-rails-command) 中的命令時,如果返回“Could not find ’railties”這樣的錯誤,說明你沒安裝正確的 Rails 版本,再次確認你安裝 Rails 時執行的命令和[代碼清單 1.1](#listing-installing-rails) 一模一樣。)
##### 代碼清單 1.3:執行 `rails new` 命令(明確指定版本號)
```
$ cd ~/workspace $ rails _4.2.2_ new hello_app
create
create README.rdoc
create Rakefile
create config.ru
create .gitignore
create Gemfile
create app
create app/assets/javascripts/application.js
create app/assets/stylesheets/application.css
create app/controllers/application_controller.rb
.
.
.
create test/test_helper.rb
create tmp/cache
create tmp/cache/assets
create vendor/assets/javascripts
create vendor/assets/javascripts/.keep
create vendor/assets/stylesheets
create vendor/assets/stylesheets/.keep
run bundle install
Fetching gem metadata from https://rubygems.org/..........
Fetching additional metadata from https://rubygems.org/..
Resolving dependencies...
Using rake 10.3.2
Using i18n 0.6.11
.
.
.
Your bundle is complete!
Use `bundle show [gemname]` to see where a bundled gem is installed.
run bundle exec spring binstub --all
* bin/rake: spring inserted
* bin/rails: spring inserted
```
如代碼清單 1.3 所示,執行 `rails new` 命令生成所有文件之后,會自動執行 `bundle install` 命令。我們會在 [1.3.1 節](#bundler)說明這個命令的作用。
留意一下 `rails new` 命令創建的文件和文件夾。這個標準的文件夾結構(如[圖 1.4](#fig-directory-structure-rails))是 Rails 的眾多優勢之一——讓你從零開始快速的創建一個可運行的簡單應用。而且,所有 Rails 應用都使用這種文件夾結構,所以閱讀他人的代碼時很快就能理清頭緒。這些文件的作用如[表 1.2](#table-rails-directory-structure) 所示,在本書的后續內容中將介紹其中大多數文件和文件夾。從 [5.2.1 節](chapter5.html#the-asset-pipeline)開始,我們將介紹 `app/assets` 文件夾,它是 Asset Pipeline 的一部分。Asset Pipeline 把組織、部署 CSS 和 JavaScript 等資源文件變得異常簡單。
圖 1.4:新建 Rails 應用的文件夾結構
表 1.2:Rails 文件夾結構簡介
| 文件/文件夾 | 作用 |
| --- | --- |
| `app/` | 應用的核心文件,包含模型、視圖、控制器和輔助方法 |
| `app/assets` | 應用的資源文件,例如層疊樣式表(CSS)、JavaScript 和圖片 |
| `bin/` | 可執行二進制文件 |
| `config/` | 應用的配置 |
| `db/` | 數據庫相關的文件 |
| `doc/` | 應用的文檔 |
| `lib/` | 代碼庫模塊文件 |
| `lib/assets` | 代碼庫的資源文件,例如 CSS、JavaScript 和圖片 |
| `log/` | 應用的日志文件 |
| `public/` | 公共(例如瀏覽器)可訪問的文件,例如錯誤頁面 |
| `bin/rails` | 生成代碼、打開終端會話或啟動本地服務器的程序 |
| `test/` | 應用的測試 |
| `tmp/` | 臨時文件 |
| `vendor/` | 第三方代碼,例如插件和 gem |
| `vendor/assets` | 第三方資源文件,例如 CSS、JavaScript 和圖片 |
| `README.rdoc` | 應用簡介 |
| `Rakefile` | 使用 `rake` 命令執行的實用任務 |
| `Gemfile` | 應用所需的 gem |
| `Gemfile.lock` | gem 列表,確保這個應用的副本使用相同版本的 gem |
| `config.ru` | [Rack 中間件](http://rack.github.io/)的配置文件 |
| `.gitignore` | Git 忽略的文件 |
## 1.3.1 Bundler
創建完一個新的 Rails 應用后,下一步是使用 Bundler 安裝和包含該應用所需的 gem。在 [1.3 節](#the-first-application)簡單提到過,執行 `rails new` 命令時會自動運行 Bundler(通過 `bundle install` 命令)。不過這一節,我們要修改應用默認使用的 gem,然后再次運行 Bundler。首先,在文本編輯器中打開文件 `Gemfile`,雖然具體的版本號和內容或許有所不同,但大概與[代碼清單 1.4](#listing-default-gemfile) 和[圖 1.5](#fig-cloud9-gemfile) 差不多。(這個文件中的內容是 Ruby 代碼,現在先不關心句法,[第 4 章](chapter4.html#rails-flavored-ruby)會詳細介紹 Ruby。)如果你沒看到如圖 1.5 所示的文件和文件夾,點擊文件瀏覽器中的齒輪圖標,然后選擇“Refresh File Tree”(刷新文件樹)。(如果沒出現某個文件或文件夾,就可以刷新文件樹。)
##### 代碼清單 1.4:`hello_app` 中默認生成的 `Gemfile`
```
source 'https://rubygems.org'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.2.2'
# Use sqlite3 as the database for Active Record
gem 'sqlite3'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 5.0'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# Use CoffeeScript for .js.coffee assets and views
gem 'coffee-rails', '~> 4.1.0'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
# gem 'therubyracer', platforms: :ruby
# Use jquery as the JavaScript library
gem 'jquery-rails'
# Turbolinks makes following links in your web application faster. Read more:
# https://github.com/rails/turbolinks
gem 'turbolinks'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.0'
# bundle exec rake doc:rails generates the API under doc/api.
gem 'sdoc', '~> 0.4.0', group: :doc
# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'
# Use Unicorn as the app server
# gem 'unicorn'
# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development
group :development, :test do
# Call 'debugger' anywhere in the code to stop execution and get a
# debugger console
gem 'byebug'
# Access an IRB console on exceptions page and /console in development
gem 'web-console', '~> 2.0'
# Spring speeds up development by keeping your application running in the
# background. Read more: https://github.com/rails/spring
gem 'spring'
end
```
圖 1.5:在文本編輯器中打開默認生成的 `Gemfile`
其中很多行代碼都用 `#` 符號注釋掉了,這些代碼放在這是為了告訴你一些常用的 gem,也是為了展示 Bundler 的句法。現在,除了這些默認的 gem 之外,我們還不需要其他的 gem。
如果沒在 `gem` 指令中指定版本號,Bundler 會自動最新版。下面就是一例:
```
gem 'sqlite3'
```
還有兩種常用的方法,用來指定 gem 版本的范圍,一定程度上控制 Rails 使用的版本。首先看下面這行代碼:
```
gem 'uglifier', '>= 1.3.0'
```
這行代碼的意思是,安裝版本號大于或等于 `1.3.0` 的最新版 `uglifier`(作用是壓縮 Asset Pipeline 中的文件),就算是 `7.2` 版也會安裝。第二種方法如下所示:
```
gem 'coffee-rails', '~> 4.0.0'
```
這行代碼的意思是,安裝版本號大于 `4.0.0`,但小于 `4.1` 的 `coffee-rails`。也就是說,`>=` 符號的意思是始終安裝最新版;`~> 4.0.0` 的意思是只安裝補丁版本號變化的版本(例如從 `4.0.0` 到 `4.0.1`),而不安裝次版本或主版本的更新(例如從 `4.0` 到 `4.1`)。不過,經驗告訴我們,即使是補丁版本的升級也可能導致錯誤,所以在本教程中我們基本上會為所有的 gem 都指定精確的版本號。你可以使用任何 gem 的最新版本,還可以在 `Gemfile` 中使用 `~>`(一般推薦有經驗的用戶使用),但事先提醒你,這可能會導致本教程開發的應用表現異常。
修改[代碼清單 1.4](#listing-default-gemfile) 中的 `Gemfile`,換用精確的版本號,得到的結果如[代碼清單 1.5](#listing-gemfile-sqlite-version) 所示。注意,借此機會我們還變動了 `sqlite3` 的位置,只在開發環境和測試環境([7.1.1 節](chapter7.html#debug-and-rails-environments))中安裝,避免和 Heroku 所用的數據庫沖突([1.5 節](#deploying))。
##### 代碼清單 1.5:每個 Ruby gem 都使用精確版本號的 `Gemfile`
```
source 'https://rubygems.org'
gem 'rails', '4.2.2'
gem 'sass-rails', '5.0.2'
gem 'uglifier', '2.5.3'
gem 'coffee-rails', '4.1.0'
gem 'jquery-rails', '4.0.3'
gem 'turbolinks', '2.3.0'
gem 'jbuilder', '2.2.3'
gem 'sdoc', '0.4.0', group: :doc
group :development, :test do
gem 'sqlite3', '1.3.9'
gem 'byebug', '3.4.0'
gem 'web-console', '2.0.0.beta3'
gem 'spring', '1.1.3'
end
```
把代碼清單 1.5 中的內容寫入應用的 `Gemfile` 文件之后,執行 `bundle install` 命令[[7](#fn-7)]安裝這些 gem:
```
$ cd hello_app/ $ bundle install Fetching source index for https://rubygems.org/
.
.
.
```
`bundle install` 命令可能要執行一會兒,不過結束后我們的應用就可以運行了。
## 1.3.2 `rails server`
運行完 [1.3 節](#the-first-application)中的 `rails new` 命令和 [1.3.1 節](#bundler) 中的 `bundle install` 命令之后,我們的應用就可以運行了,但是怎么運行呢?Rails 自帶了一個命令行程序(或叫腳本),可以運行一個本地服務器,協助我們的開發工作。這個命令具體怎么執行,取決于你使用的環境:在本地系統中,直接執行 `rails server` 命令就行([代碼清單 1.6](#listing-local-server));而在 Cloud9 中,還要指定綁定的 IP 地址和[端口號](http://en.wikipedia.org/wiki/TCP_and_UDP_port),告訴 Rails 服務器外界可以通過哪個地址訪問應用([代碼清單 1.7](#listing-cloud-server))。[[8](#fn-8)](Cloud9 使用特殊的環境變量 `$IP` 和 `$PORT` 動態指定 IP 地址和端口號。如果想查看這兩個環境變量的值,可以在命令行中輸入 `echo $IP` 和 `echo $PORT`。)如果系統提示缺少 JavaScript 運行時,訪問 [execjs 在 GitHub 中的項目主頁](https://github.com/sstephenson/execjs),查看解決方法。我非常推薦安裝 [Node.js](http://nodejs.org/)。
##### 代碼清單 1.6:在本地設備中運行 Rails 服務器
```
$ cd ~/workspace/hello_app/ $ rails server => Booting WEBrick
=> Rails application starting on http://localhost:3000
=> Run `rails server -h` for more startup options
=> Ctrl-C to shutdown server
```
##### 代碼清單 1.7:在云端 IDE 中運行 Rails 服務器
```
$ cd ~/workspace/hello_app/ $ rails server -b $IP -p $PORT => Booting WEBrick
=> Rails application starting on http://0.0.0.0:8080
=> Run `rails server -h` for more startup options
=> Ctrl-C to shutdown server
```
不管使用哪種環境,我都建議你在另一個終端選項卡中執行 `rails server` 命令,這樣你就可以繼續在第一個選項卡中執行其他命令了,如[圖 1.6](#fig-new-terminal-tab) 和[圖 1.7](#fig-rails-server-new-tab) 所示。(如果你已經在第一個選項卡中啟動了服務器,可以按 Ctrl-C 鍵關閉服務器。)在本地環境中,在瀏覽器中打開 [http://localhost:3000/](http://localhost:3000/);在云端 IDE 中,打開“Share”(分享)面板,點擊“Application”后的地址即可打開應用(如[圖 1.8](#fig-share-workspace))。在這兩種環境中,顯示的頁面應該都和[圖 1.9](#fig-riding-rails) 類似。
點擊“About your application’s environment”可以查看應用的信息。你看到的版本號可能和我的不一樣,但和[圖 1.10](#fig-riding-rails-environment) 差不多。當然了,從長遠來看,我們不需要這個 Rails 默認頁面,不過現在看到這個頁面說明 Rails 可以正常運行了。我們會在[1.3.4 節](#hello-world)刪除這個頁面,替換成我們自己寫的首頁。
圖 1.6:再打開一個終端選項卡圖 1.7:在另一個選項卡中運行 Rails 服務器圖 1.8:分享運行在云端工作空間中的本地服務器圖 1.9:執行 `rails server` 命令后看到的 Rails 默認頁面圖 1.10:默認頁面中顯示應用的環境信息
## 1.3.3 模型-視圖-控制器
在初期階段,概覽一下 Rails 應用的工作方式([圖 1.11](#fig-mvc))多少會有些幫助。你可能已經注意到了,在 Rails 應用的標準文件夾結構中有一個文件夾叫 `app/`([圖 1.4](#fig-directory-structure-rails)),其中有三個子文件夾:`models`、`views` 和 `controllers`。這暗示 Rails 采用了“模型-視圖-控制器”(簡稱 MVC)架構模式,這種模式把“域邏輯”(domain logic,也叫“業務邏輯”(business logic))與圖形用戶界面相關的輸入和表現邏輯強制分開。在 Web 應用中,“域邏輯”一般是“用戶”、“文章”和“商品”等數據模型,GUI 則是瀏覽器中的網頁。
圖 1.11:MVC 架構圖解
和 Rails 應用交互時,瀏覽器發出一個請求(request),Web 服務器收到這個請求之后將其傳給 Rails 應用的控制器,由控制器決定下一步該做什么。某些情況下,控制器會立即渲染視圖(view),生成 HTML,然后發送給瀏覽器。對于動態網站來說,更常見的是控制器和模型(model)交互。模型是一個 Ruby 對象,表示網站中的一個元素(例如一個用戶),并且負責和數據庫通信。和模型交互后,控制器再渲染視圖,并把生成的 HTML 返回給瀏覽器。
如果你覺得這些內容有點抽象,不用擔心,后面會經常講到 MVC。在[1.3.4 節](#hello-world)中,首次使用 MVC 架構編寫應用;在 [2.2.2 節](chapter2.html#mvc-in-action)中,會以一個應用為例較為深入地討論 MVC;在最后那個演示應用中會使用完整的 MVC 架構。從 [3.2 節](chapter3.html#static-pages)開始,介紹控制器和視圖;從 [6.1 節](chapter6.html#user-model)開始,介紹模型;[7.1.2 節](chapter7.html#a-users-resource)則把這三部分放在一起使用。
## 1.3.4 Hello, world!
接下來我們要對這個使用 MVC 框架開發的第一個應用做些小改動——添加一個控制器動作,渲染字符串“hello, world!”。(從 [2.2.2 節](chapter2.html#mvc-in-action)開始會更深入的介紹控制器動作。)這一節的目的是,使用顯示“hello, world!”的頁面替換 Rails 默認的首頁([圖 1.9](#fig-riding-rails))。
從“控制器動作”這個名字可以看出,動作在控制器中定義。我們要在 `ApplicationController` 中定義這個動作,并將其命名為 `hello`。其實,現在我們的應用只有 `ApplicationController` 這一個控制器。執行下面的命令可以驗證這一點(從 [第 2 章](chapter2.html#a-toy-app)開始,我們會創建自己的控制器。):
```
$ ls app/controllers/*_controller.rb
```
`hello` 動作的定義體如[代碼清單 1.8](#listing-hello-action) 所示,調用 `render` 函數返回文本“hello, world!”。(現在先不管 Ruby 的句法,[第 4 章](chapter4.html#rails-flavored-ruby)會詳細介紹。)
##### 代碼清單 1.8:在 `ApplicationController` 中添加 `hello` 動作
app/controllers/application_controller.rb
```
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
def hello
render text: "hello, world!" end
end
```
定義好返回所需字符串的動作之后,我們要告訴 Rails 使用這個動作,不再顯示默認的首頁([圖 1.10](#fig-riding-rails-environment))。為此,我們要修改 Rails 路由。路由在控制器之前([圖 1.11](#fig-mvc)),決定瀏覽器發給應用的請求由哪個動作處理。(簡單起見,[圖 1.11](#fig-mvc) 中省略了路由,從 [2.2.2 節](chapter2.html#mvc-in-action)開始會詳細介紹路由。)具體而言,我們要修改默認的首頁,也就是根路由。這個路由決定根 URL 顯示哪個頁面。根 URL 是 http://www.example.com/ 這種形式,所以一般簡化使用 /(斜線)表示。
如[代碼清單 1.9](#listing-default-root-route) 所示,Rails 應用的路由文件(`config/routes.rb`)中有一行注釋,說明如何編寫根路由。其中,“welcome”是控制器名,“index”是這個控制器中的動作名。去掉這行前面的 `#` 號,解除注釋,這樣根路由就可以定義了,然后再把內容替換成[代碼清單 1.10](#listing-hello-root-route) 中的代碼,告訴 Rails 把根路由交給 `ApplicationController` 中的 `hello` 動作處理。(在 [1.1.2 節](#conventions-in-this-book)說過,豎排的點號表示省略的代碼,不要直接復制。)
##### 代碼清單 1.9:生成的默認根路由(在注釋中)
config/routes.rb
```
Rails.application.routes.draw do
.
.
.
# You can have the root of your site routed with "root"
# root 'welcome#index' .
.
.
end
```
##### 代碼清單 1.10:設定根路由
config/routes.rb
```
Rails.application.routes.draw do
.
.
.
# You can have the root of your site routed with "root"
root 'application#hello' .
.
.
end
```
有了[代碼清單 1.8](#listing-hello-action) 和[代碼清單 1.10](#listing-hello-root-route) 中的代碼,根路由就會按照我們的要求顯示“hello, world!”了,如[圖 1.12](#fig-hello-world-hello-app) 所示。
圖 1.12:在瀏覽器中查看顯示“hello, world!”的頁面
- 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 練習