# 7.2 注册表单
用户资料页面已经可以访问了,但内容还不完整。下面我们要为网站创建一个注册表单。如[图 5.9](chapter5.html#fig-new-signup-page) 和[图 7.10](#fig-blank-signup-page-recap) 所示,“注册”页面还没有什么内容,无法注册新用户。本节会实现如[图 7.11](#fig-signup-mockup) 所示的注册表单,添加注册功能。
![user show sidebar css 3rd edition](https://box.kancloud.cn/2016-05-11_5732bd11e853d.png)图 7.9:添加侧边栏和 CSS 后的用户资料页面![new signup page 3rd edition](https://box.kancloud.cn/2016-05-11_5732bd05dca6b.png)图 7.10:注册页面现在的样子
因为我们要实现通过网页创建用户的功能,那么就把 [6.3.4 节](chapter6.html#creating-and-authenticating-a-user)在控制台中创建的用户删除吧。最简单的方法是使用 `db:migrate:reset` 命令:
```
$ bundle exec rake db:migrate:reset
```
在某些系统中可能还要重启 Web 服务器才能生效。
![signup mockup bootstrap](https://box.kancloud.cn/2016-05-11_5732bd08d8ea7.png)图 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;
}
```
![signup form 3rd edition](https://box.kancloud.cn/2016-05-11_5732bd12a7786.png)图 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"`)基于安全考虑会遮盖输入的内容。
![filled in form bootstrap 3rd edition](https://box.kancloud.cn/2016-05-11_5732bd12c5540.png)图 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 练习