7.4 注册成功
处理完提交无效数据的情况,本节我们要完成注册表单的功能,如果提交的数据有效,就把用户存入数据库。我们先尝试保存用户,如果保存成功,用户的数据会自动存入数据库,然后在浏览器中重定向,转向新注册用户的资料页面,页面中还会显示一个欢迎消息,构思图如图 7.19 所示。如果保存用户失败了,就交由上一节实现的功能处理。
图 7.19:注册成功后显示的页面构思图
7.4.1 完整的注册表单
要完成注册表单的功能,我们要把代码清单 7.17 中的注释换成适当的代码。现在,提交有效数据时也不能正确处理,如图 7.20 所示,因为 Rails 动作的默认行为是渲染对应的视图,而 create
动作不对应视图。
图 7.20:提交有效注册信息后显示的错误页面
成功注册后,我们不需要渲染页面,而要重定向到另一个页面。按照习惯,我们要重定向到新注册用户的资料页面,不过转到根地址也行。为此,在应用代码中要使用 redirect_to
方法,如代码清单 7.23 所示。
代码清单 7.23:create
动作的代码,处理保存和重定向操作
app/controllers/users_controller.rb
class UsersController < ApplicationController
.
.
.
def create
@user = User.new(user_params)
if @user.save
redirect_to @user else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
end
注意,我们写的是:
redirect_to @user
不过,也可以写成:
redirect_to user_url(@user)
Rails 看到 redirect_to @user
后,知道我们想重定向到 user_url(@user)
。
7.4.2 闪现消息
有了代码清单 7.23 中的代码后,注册表单已经可以使用了。不过在提交有效数据注册之前,我们要添加一个 Web 应用中经常使用的增强功能:访问随后的页面时显示一个消息(这里,我们要显示一个欢迎新用户的消息),如果再访问其他页面,或者刷新页面,这个消息要消失。
在 Rails 中,短暂显示一个消息使用“闪现消息”(flash message)实现。按照 Rails 的约定,操作成功时使用 :success
键表示,如代码清单 7.24 所示。
代码清单 7.24:用户注册成功后显示一个闪现消息
app/controllers/users_controller.rb
class UsersController < ApplicationController
.
.
.
def create
@user = User.new(user_params)
if @user.save
flash[:success] = "Welcome to the Sample App!" redirect_to @user
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
end
把一个消息赋值给 flash
之后,我们就可以在重定向后的第一个页面中将其显示出来了。我们要遍历 flash
,在网站布局中显示所有相关的消息。你可能还记得 4.3.3 节在控制台中遍历哈希那个例子,当时我故意把变量命名为 flash
:
$ rails console
>> flash = { success: "It worked!", danger: "It failed." }
=> {:success=>"It worked!", danger: "It failed."}
>> flash.each do |key, value|
?> puts "#{key}"
?> puts "#{value}"
>> end
success
It worked!
danger
It failed.
按照上述方式,我们可以使用如下的代码在网站的全部页面中显示闪现消息的内容:
<% flash.each do |message_type, message| %>
<div class="alert alert-<%= message_type %>"><%= message %></div>
<% end %>
(这段代码很乱,混用了 HTML 和 ERb,7.7 节中有一题会要求你把它变得好看一些。)
其中
alert-<%= message_type %>
为各种类型的消息指定一个 CSS 类,因此,:success
消息的类是 alert-success
。(:success
是个符号,ERb 会自动把它转换成字符串 "success"
,然后再插入模板。)
为不同类型的消息指定不同的 CSS 类,可以为不同类型的消息指定不同的样式。例如,8.1.4 节会使用 flash[:danger]
显示登录失败消息。[11](其实,在代码清单 7.19 中为错误消息区域指定样式时,已经用过 alert-danger
。)Bootstrap 提供的 CSS 支持四种闪现消息样式,分别为 success
,info
,warning
和 danger
,在开发这个演示应用的过程中,我们会找机会全部使用一遍。
消息也会在模板中显示,如下代码:
flash[:success] = "Welcome to the Sample App!"
得到的完整 HTML 是:
<div class="alert alert-success">Welcome to the Sample App!</div>
把前面的 ERb 代码放入网站的布局中,得到的布局如代码清单 7.25 所示。
代码清单 7.25:在网站的布局中添加闪现消息
app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
.
.
.
<body>
<%= render 'layouts/header' %>
<div class="container">
<% flash.each do |message_type, message| %>
<div class="alert alert-<%= message_type %>"><%= message %></div>
<% end %>
<%= yield %>
<%= render 'layouts/footer' %>
<%= debug(params) if Rails.env.development? %>
</div>
.
.
.
</body>
</html>
7.4.3 首次注册
现在我们可以注册一个用户,看看到目前为止所实现的功能。用户的名字使用“Rails Tutorial”,电子邮件地址使用“[email protected]”,如图 7.21 所示。注册成功后,页面中显示了一个友好的欢迎消息,如图 7.22 所示。消息的样式是由 5.1.2 节集成的 Bootstrap 框架提供的 .success
类实现。(如果无法注册,提示电子邮件地址已经使用,确保按照 7.2 节的说明,执行了 db:migrate:reset
Rake 任务,而且重启了开发服务器。)刷新用户资料页面后,闪现消息会消失,如图 7.23 所示。
图 7.21:首次注册时填写的信息图 7.22:注册成功后显示有闪现消息的页面图 7.23:刷新页面后资料页面中的闪现消息不见了
我们还可以检查一下数据库,确保真得创建了新用户:
$ rails console
>> User.find_by(email: "[email protected]")
=> #<User id: 1, name: "Rails Tutorial", email: "[email protected]",
created_at: "2014-08-29 19:53:17", updated_at: "2014-08-29 19:53:17",
password_digest: "$2a$10$zthScEx9x6EkuLa4NolGye6O0Zgrkp1B6LQ12pTHlNB...">
7.4.4 注册成功的测试
在继续之前,我们要编写测试,确认提交有效信息后应用的表现正常,并捕获可能出现的回归。和 7.3.4 节中注册失败的测试一样,我们主要是检查数据库中的内容。这一次,我们要提交有效的数据,确认创建了一个用户。类似代码清单 7.21 中使用的
assert_no_difference 'User.count' do
post users_path, ...
end
这里我们要使用对应的 assert_difference
方法:
assert_difference 'User.count', 1 do
post_via_redirect users_path, ...
end
和 assert_no_difference
一样,assert_difference
的第一个参数是字符串 'User.count'
,目的是比较块中的代码执行前后 User.count
的变化。第二个参数可选,指定变化的数量(这里是 1)。
把 assert_difference
加入代码清单 7.21 后,得到的测试如代码清单 7.26 所示。注意,请求用户的资料页面时,使用的是 post_via_redirect
方法,目的是提交数据后继续跟踪重定向,渲染 users/show
模板。(针对闪现消息的测试留作练习。)
代码清单 7.26:注册成功的测试 GREEN
test/integration/users_signup_test.rb
require 'test_helper'
class UsersSignupTest < ActionDispatch::IntegrationTest
.
.
.
test "valid signup information" do
get signup_path
name = "Example User"
email = "[email protected]"
password = "password"
assert_difference 'User.count', 1 do
post_via_redirect users_path, user: { name: name,
email: email,
password: password,
password_confirmation: password }
end
assert_template 'users/show'
end
end
注意,这个测试还确认了成功注册后会渲染 show
视图。如果想让测试通过,用户资源的路由(代码清单 7.3),用户控制器中的 show
动作(代码清单 7.5),以及 show.html.erb
视图(代码清单 7.8)都得能正常使用才行。所以,
assert_template 'users/show'
这一行代码就能测试用户资料页面几乎所有的相关功能。这种对应用中重要功能的端到端覆盖展示了集成测试的重大作用。