# 7.2 注冊表單
用戶資料頁面已經可以訪問了,但內容還不完整。下面我們要為網站創建一個注冊表單。如[圖 5.9](chapter5.html#fig-new-signup-page) 和[圖 7.10](#fig-blank-signup-page-recap) 所示,“注冊”頁面還沒有什么內容,無法注冊新用戶。本節會實現如[圖 7.11](#fig-signup-mockup) 所示的注冊表單,添加注冊功能。
圖 7.9:添加側邊欄和 CSS 后的用戶資料頁面圖 7.10:注冊頁面現在的樣子
因為我們要實現通過網頁創建用戶的功能,那么就把 [6.3.4 節](chapter6.html#creating-and-authenticating-a-user)在控制臺中創建的用戶刪除吧。最簡單的方法是使用 `db:migrate:reset` 命令:
```
$ bundle exec rake db:migrate:reset
```
在某些系統中可能還要重啟 Web 服務器才能生效。
圖 7.11:用戶注冊頁面的構思圖
## 7.2.1 使用 `form_for`
注冊頁面的核心是一個表單,用于提交注冊相關的信息(名字,電子郵件地址,密碼和密碼確認)。在 Rails 中,創建表單可以使用 `form_for` 輔助方法,傳入 Active Record 對象后,使用該對象的屬性構建一個表單。
注冊頁面的地址是 /signup,由用戶控制器的 `new` 動作處理([代碼清單 5.33](chapter5.html#listing-signup-route))。首先,我們要創建傳給 `form_for` 的用戶對象,然后賦值給 `@user` 變量,如[代碼清單 7.12](#listing-new-action-with-user) 所示。
##### 代碼清單 7.12:在 `new` 動作中添加 `@user` 變量
app/controllers/users_controller.rb
```
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
end
def new
@user = User.new end
end
```
表單的代碼參見[代碼清單 7.13](#listing-signup-form)。[7.2.2 節](#signup-form-html)會詳細分析這個表單,現在我們先添加一些 SCSS,如[代碼清單 7.14](#listing-form-css) 所示。(注意,這里重用了[代碼清單 7.2](#listing-mixin-and-debug) 中的混入。)添加樣式后的注冊頁面如[圖 7.12](#fig-signup-form) 所示。
##### 代碼清單 7.13:用戶注冊表單
app/views/users/new.html.erb
```
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(@user) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.email_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Create my account", class: "btn btn-primary" %>
<% end %>
</div>
</div>
```
##### 代碼清單 7.14:注冊表單的樣式
app/assets/stylesheets/custom.css.scss
```
.
.
.
/* forms */
input, textarea, select, .uneditable-input {
border: 1px solid #bbb;
width: 100%;
margin-bottom: 15px;
@include box_sizing;
}
input {
height: auto !important;
}
```
圖 7.12:用戶注冊頁面
## 7.2.2 注冊表單的 HTML
為了能更好地理解[代碼清單 7.13](#listing-signup-form) 中定義的表單,可以分成幾段來看。我們先看外層結構——開頭在 ERb 中調用 `form_for` 方法,結尾是 `end`:
```
<%= form_for(@user) do |f| %>
.
.
.
<% end %>
```
這段代碼中有關鍵字 `do`,說明 `form_for` 方法可以接受一個塊,而且有一個塊變量 `f`(代表表單)。
我們一般無需了解 Rails 輔助方法的內部實現,但是對于 `form_for` 來說,我們要知道 `f` 對象的作用是什么:在這個對象上調用[表單字段](http://www.w3schools.com/html/html_forms.asp)(例如,文本字段、單選按鈕和密碼字段)對應的方法,生成的字段元素可以用來設定 `@user` 對象的屬性。也就是說:
```
<%= f.label :name %>
<%= f.text_field :name %>
```
生成的 HTML 是一個有標注(label)的文本字段,用來設定用戶模型的 `name` 屬性。
在瀏覽器中按右鍵,然后選擇“審查元素”,會看到頁面的源碼,如[代碼清單 7.15](#listing-signup-form-html) 所示。下面花點兒時間介紹一下表單的結構。
##### 代碼清單 7.15:[圖 7.12](#fig-signup-form) 中表單的源碼
```
<form accept-charset="UTF-8" action="/users" class="new_user"
id="new_user" method="post">
<input name="utf8" type="hidden" value="✓" />
<input name="authenticity_token" type="hidden"
value="NNb6+J/j46LcrgYUC60wQ2titMuJQ5lLqyAbnbAUkdo=" />
<label for="user_name">Name</label>
<input id="user_name" name="user[name]" type="text" />
<label for="user_email">Email</label>
<input id="user_email" name="user[email]" type="email" />
<label for="user_password">Password</label>
<input id="user_password" name="user[password]"
type="password" />
<label for="user_password_confirmation">Confirmation</label>
<input id="user_password_confirmation"
name="user[password_confirmation]" type="password" />
<input class="btn btn-primary" name="commit" type="submit"
value="Create my account" />
</form>
```
先看表單里的結構。比較一下[代碼清單 7.13](#listing-signup-form) 和[代碼清單 7.15](#listing-signup-form-html),我們發現,下面的 ERb 代碼
```
<%= f.label :name %>
<%= f.text_field :name %>
```
生成的 HTML 是
```
<label for="user_name">Name</label>
<input id="user_name" name="user[name]" type="text" />
```
下面的 ERb 代碼
```
<%= f.label :password %>
<%= f.password_field :password %>
```
生成的 HTML 是
```
<label for="user_password">Password</label>
<input id="user_password" name="user[password]" type="password" />
```
如[圖 7.13](#fig-filled-in-form) 所示,文本字段(`type="text"`)會直接顯示填寫的內容,而密碼字段(`type="password"`)基于安全考慮會遮蓋輸入的內容。
圖 7.13:在表單的文本字段和密碼字段中填寫內容
[7.4 節](#successful-signups)會介紹,之所以能創建用戶,全靠 `input` 元素的 `name` 屬性:
```
<input id="user_name" name="user[name]" - - - />
.
.
.
<input id="user_password" name="user[password]" - - - />
```
[7.3 節](#unsuccessful-signups)會介紹,Rails 會以這些 `name` 屬性的值為鍵,用戶輸入的內容為值,構成一個名為 `params` 的哈希,用來創建用戶。
另外一個重要的標簽是 `form`。Rails 使用 `@user` 對象創建這個 `form` 元素,因為每個 Ruby 對象都知道它所屬的類([4.4.1 節](chapter4.html#constructors)),所以 Rails 知道 `@user` 所屬的類是 `User`,而且,`@user` 是一個新用戶,Rails 知道要使用 `post` 方法——這正是創建新對象所需的 HTTP 請求(參見[旁注 3.2](chapter3.html#aside-get-etc)):
```
<form action="/users" class="new_user" id="new_user" method="post">
```
這里的 `class` 和 `id` 屬性并不重要,重要的是 `action="/users"` 和 `method="post"`。設定這兩個屬性后,Rails 會向 /users 發送 `POST` 請求。接下來的兩節會介紹這個請求的效果。
你可能還會注意到,`form` 標簽中有下面這段代碼:
```
<div style="display:none">
<input name="utf8" type="hidden" value="✓" />
<input name="authenticity_token" type="hidden"
value="NNb6+J/j46LcrgYUC60wQ2titMuJQ5lLqyAbnbAUkdo=" />
</div>
```
這段代碼不會在瀏覽器中顯示,只在 Rails 內部有用,所以你并不需要知道它的作用。簡單來說,這段代碼首先使用 Unicode 字符 `✓`(對號 ?)強制瀏覽器使用正確的字符編碼提交數據,然后是一個“真偽令牌”(authenticity token),Rails 用它抵御“跨站請求偽造”(Cross-Site Request Forgery,簡稱 CSRF)攻擊。[[8](#fn-8)]
- 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 練習