Ruby Rails学习中:登陆
登陆
一. Sessions 控制器
登录和退出功能由 Sessions 控制器中相应的 REST 动作处理 : 登录表单在 new 动作中处理, 登录的过程是向 create 动作发送 POST 请求, 退出则是向 destroy 动作发送 DELETE 请求。
1.首先生成 Sessions 控制器, 以及其中的 new 动作:
$ rails generate controller Sessions new
Users 资源使用特殊的 resources 方法自动获得 REST 式路由, 而 Sessions 资源则只能使用具名路由, 处理发给 /login 地址的 GET 和 POST 请求, 以及发给 /logout 地址的 DELETE 请求, 如下图所示(删除了 rails generate controller 生成的无用路由)。
(1).添加一个资源, 获得会话的标准 REST 式动作 RED
打开文件:config/routes.rb
添加上图中的路由规则之后, 还要创建Session时生成的测试, 使用新的登录路由, 如下图所示:
(2).更新 Sessions 控制器的测试, 使用新的登录路由 GREEN
打开文件:test/controllers/sessions_controller_test.rb
Sessions 资源的路由规则会把 URL 和动作对应起来, 如下图所示:
至此, 我们添加了好几个自定义的具名路由, 现在最好看一下完整的路由列表。我们可以执行 rails routes 命令生成路由列表:
注:你没必要完全理解输出的这些路由。像这样查看路由能对应用支持的动作有个整体认识。
二. 登录表单
登录表单和注册表单之间的主要区别是, 会话不是模型, 因此不能创建类似 @user 的变量。所以, 构建登录表单时, 我们要为 form_for 稍微多提供一些信息。form_for(@user)的作用是让表单向 /users 发起 POST 请求。对会话来说, 我们需要指明资源的名称以及相应的 URL:form_for(:session, url: login_path)知道怎么调用 form_for 之后, 参照注册表单编写登陆表单, 如图所示:
1.登录表单的代码
打开文件:app/views/sessions/new.html.erb
注:为了操作方便, 我们还加入了指向“注册”页面的链接。(导航栏中的“Login”还没填写地址,所以你要在地址栏中输入 /login。稍后会修正这个问题。)
2.页面
三. 查找并验证用户的身份
首先,我们要为 Sessions 控制器编写一个最简单的 create 动作, 以及空的 new 动作和 destroy 动作, 如下图所示:
1.Sessions 控制器中 create 动作的初始版本
打开文件:app/controllers/sessions_controller.rb
create 动作现在只渲染 new 视图, 不过这为后续工作做好了准备。提交 /login 页面中的表单后, 显示的页面如下图所示:
2.查找并验证用户的身份
打开文件:app/controllers/sessions_controller.rb
上图中红框内的第一行使用提交的电子邮件地址从数据库中取出相应的用户。(我们前面说过, 电子邮件地址都是以小写字母形式保存的, 所以这里调用了 downcase 方法, 确保提交有效的地址后能查到相应的记录。)高亮显示的第二行看起来很怪, 但在 Rails 中经常使用:
user && user.authenticate(params[:session][:password])
我们使用 && (逻辑与)检测获取的用户是否有效。因为除了 nil 和 false 之外的所有对象都被视作真值, 所以上面这个语句可能出现的结果如下表所示。从表中可以看出, 当且仅当数据库中存在提交的电子邮件地址, 而且对应的密码和提交的密码匹配时, 这个语句才会返回 true 。
3.渲染闪现消息
布局中已经加入了显示闪现消息的局部视图, 所以无需其他修改, flash[:danger] 消息就能显示出来; 而且因为使用了 Bootstrap 提供的 CSS, 消息的样式也很美观,如图所示::
注:就跟代码中标注的一样, 现在的闪现消息有问题问题在于, 闪现消息在一个请求的生命周期内是持续存在的, 而重新渲染页面(使用 render 方法)与重定向不同, 不算是一次新请求, 所以你会发现这个闪现消息存在的时间比预期的要长很多。
例如:提交无效的登录信息, 然后访问首页, 还会显示这个闪现消息:
4.测试闪现消息
首先, 为应用的登录功能生成一个集成测试文件:
$ rails generate integration_test users_login
(1).捕获继续显示闪现消息的测试 RED
打开文件:test/integration/users_login_test.rb
让上图中的测试通过的方法是, 把 flash 换成特殊的 flash.now 。 flash.now 专门用于在重新渲染的页面中显示闪现消息。与 flash 不同的是, flash.now 中的内容会在下次请求时消失——这正是上图中的测试所需的行为。替换之后, 正确的应用代码如下图所示:
(2).处理登录失败正确的代码 GREEN
四. 登录
Rails 生成器很人性化, 生成 Sessions 控制器时自动生成了一个 Ses-sions 辅助模块。而且, 其中的辅助方法会自动引入 Rails 视图。如果在控制器的基类( ApplicationCon-troller )中引入辅助方法模块, 还可以在控制器中使用,如下图所示:
1.在 Application 控制器中引入 Sessions 辅助模块
打开文件:app/controllers/application_controller.rb
注:做好这些准备工作后,现在可以开始编写代码登入用户了。
2.login 方法
有 Rails 提供的 session 方法协助,登入用户很简单。( session 方法与前面生成的 Sessions 控制器没有关系。)我们可以把 session 视作一个散列, 按照下面的方式赋值:
session[:user_id] = user.id
这么做会在用户的浏览器中创建一个临时 cookie, 内容是加密后的用户 ID。在后续的请求中, 可以使用 ses-sion[:user_id] 取回这个 ID。到后面我们会使用的 cookies 方法创建的是持久 cookie, 而 session 方法创建的是临时会话, 浏览器关闭后立即失效。
我们想在多个不同的地方使用这个登录方式, 所以在 Sessions 辅助模块中定义一个名为 log_in 的方法, 如下图所示:
(1).login 方法
打开文件:app/helpers/sessions_helper.rb
session 方法创建的临时 cookie 会自动加密, 所以上图中的代码是安全的, 攻击者无法使用会话中的信息以该用户的身份登录。不过, 只有 session 方法创建的临时 cookie 是这样, cookies 方法创建的持久cookie 则有可能会受到会话劫持(session hijacking)攻击。所以在以后我们会小心处理存入用户浏览器中的信息。
定义好 log_in 方法后, 我们可以完成 Sessions 控制器中的 create 动作, 登入用户, 然后重定向到用户的资料页面, 如下图所示:
(2).登入用户
打开文件:app/controllers/sessions_controller.rb
注:简洁的重定向代码redirect_to user我们在前面节见过。Rails 会自动转换成用户资料页的地址: user_url(user)。
3.当前用户
把用户 ID 安全地存储在临时会话中之后,在后续的请求中可以将其读取出来。我们要定义一个名为 cur-rent_user 的方法,从数据库中取出用户 ID 对应的用户。 current_user 方法可用于编写类似下面的代码:
<%= current_user.name %>
或是:
redirect_to current_user
查找用户的方法之一是使用 find 方法,在用户资料页面就是这么做的:
User.find(session[:user_id])
前面说过,如果用户 ID 不存在, find 方法会抛出异常。在用户的资料页面可以使用这种行为,因为必须有相应的用户才能显示他的信息。但 session[:user_id] 的值经常是 nil (表示用户未登录),所以我们要使用 create 动作中通过电子邮件地址查找用户的 find_by 方法,通过 id 查找用户:
User.find_by(id: session[:user_id])
如果 ID 无效, find_by 方法返回 nil ,而不会抛出异常。因此,我们可以按照下面的方式定义 current_user 方法:
def current_user
User.find_by(id: session[:user_id])
end
这样定义应该可以,不过如果在一个页面中多次调用 current_user 方法,会多次查询数据库。所以,我们要使用一种 Ruby 习惯写法,把 User.find_by 的结果存储在实例变量中,只在第一次调用时查询数据库,后续再调用直接返回实例变量中存储的值:
if @current_user.nil?
@current_user = User.find_by(id: session[:user_id])
else
@current_user
end
使用前面节中介绍的“或”运算符 || ,可以把这段代码改写成:
@current_user = @current_user || User.find_by(id: session[:user_id])
User 对象是真值,所以仅当 @current_user 没有赋值时才会执行 find_by 方法。
述代码虽然可以使用,但并不符合 Ruby 的习惯。 @current_user 赋值语句的正确写法是这样:
@current_user ||= User.find_by(id: session[:user_id])
这种写法用到了容易让人困惑的 ||= (或等)运算符, 参见下图的说明:
(1).在会话中查找当前用户
打开文件:app/helpers/sessions_helper.rb
注:定义好 current_user 方法之后,可以根据用户的登录状态修改应用的布局了。
4.修改布局中的链接
修改网站布局中的链接时要在 ERb 中使用 if-else 语句,用户登录时显示一组链接,未登录时显示另一组链接:
<% if logged_in? %>
# 登录用户看到的链接
<% else %>
# 未登录用户看到的链接
<% end %>
为了编写这种代码,我们要定义 logged_in? 方法,返回布尔值。
用户登录后,当前用户存储在会话中,即 current_user 不是 nil 。检测会话中有没有当前用户要使用“非”运算符。“非”运算符写做 ! ,经常读作“bang”。logged_in? 方法的定义如下图所示:
(1).logged_in? 辅助方法
打开文件:app/helpers/sessions_helper.rb
(2).修改布局中的链接
打开文件:app/views/layouts/_header.html.erb
Ruby Rails学习中:登陆的更多相关文章
- Ruby Rails学习中:注册表单,注册失败,注册成功
接上篇 一. 注册表单 用户资料页面已经可以访问了, 但内容还不完整.下面我们要为网站创建一个注册表单. 1.使用 form_for 注册页面的核心是一个表单, 用于提交注册相关的信息(名字.电子邮件 ...
- Ruby Rails学习中:调试信息和 Rails 的三种环境,Users 资源,调试器,Gravatar 头像和侧边栏
注册 一.调试信息和 Rails 环境 现在咱们要实现的用户资料页面是我们这个应用中第一个真正意义上的动态页面.虽然视图的代码不会动态改变, 不过每个用户资料页面显示的内容却是从数据库中读取的.添加动 ...
- Ruby Rails学习中:添加安全密码
接上篇 一. 添加安全密码 我们已经为 name 和 email 字段添加了验证规则, 现在要加入用户所需的最后一个常规属性: 安全密码.每个用户都要设置一个密码(还要二次确认), 数据库中则存储经过 ...
- Ruby Rails学习中:User 模型,验证用户数据
用户建模 一. User 模型 实现用户注册功能的第一步是,创建一个数据结构,用于存取用户的信息. 在 Rails 中,数据模型的默认数据结构叫模型(model,MVC 中的 M).Rails 为解决 ...
- Ruby Rails学习中:Ruby内置的辅助方法,基础内容回顾补充
一. Ruby内置的辅助方法 1.打开文件:app/views/layouts/application.html.erb(演示应用的网站布局) 来咱把注意力放在圈起来的那一行: 这行代码使用 Rail ...
- Ruby Rails学习中:Sass 和 Asset Pipeline,布局中的链接(Rails路由,具名路由),用户注册: 第一步
接上篇: 一.Sass 和 Asset Pipeline Rails 中最有用的功能之一是 Asset Pipeline, 它极大地简化了静态资源文件(CSS.JavaScript 和图像)的生成和管 ...
- Ruby Rails学习中:网站导航,Bootstrap和自定义的CSS,局部视图
添加一些结构 一.网站导航 1.添加一些结构后的网站布局文件 打开文件:app/views/layouts/application.html.erb 简单介绍一下,添加的代码: 我们从上往下看一下这段 ...
- Ruby Rails学习中:有点内容的静态页面
续上篇: 一. 有点内容的静态页面 rails new 命令创建了一个布局文件, 不过现在最好不用.我们重命名这个文件: $ mv app/views/layouts/application.html ...
- Ruby Rails学习中:关于测试的补充,MiniTest报告程序,Guard自动测试
一. 关于测试的补充 1.MiniTest报告程序 为了让 Rails 应用的测试适时显示红色和绿色,我建议你在测试辅助文件中加入以下内容: (1).打开文件:test/test_helper.rb ...
随机推荐
- golang精选100题带答案
能力模型 级别 模型 初级 primary 熟悉基本语法,能够看懂代码的意图: 在他人指导下能够完成用户故事的开发,编写的代码符合CleanCode规范: 中级 intermediate 能够独立完成 ...
- 内部排序总结之----插入类排序(插入和Shell)
一.直接插入排序 直接插入排序(straight insertion sort)的做法是: 每次从无序表中取出第一个元素,把它插入到有序表的合适位置,使有序表仍然有序. 第一趟比较前两个数,然后把第二 ...
- 理解Cookie和Session
HTTP 无状态协议 HTTP 本身是一个无状态的连接协议,无状态的意思是:每条请求/响应都是独立进行的,服务端每处理完一个客户端的请求之后就会断开连接,并且每条请求/响应与其之前(或之后)的请求/响 ...
- docker部署TX-LCN5.0.2
主要是在配置tx-lcn.manager.host时需要特别注意下,应该安装如下配置进行 tx-lcn: manager: host: 0.0.0.0 port: 8070 heart-time: 1 ...
- mybatis 操作其他数据库的数据表
配置文件里面配置的数据库只是默认数据库,并不是只能操作默认数据库.(被自己蠢死了,唉) 1. 注解方式 使用BaseMapper方式操作数据表时,在表对应的实体类上的 @table 注解描述表名时加上 ...
- 【零基础】为什么Facebook发币就不一样
参考: https://baijiahao.baidu.com/s?id=1637182596912694597&wfr=spider&for=pc https://blog.csdn ...
- windows下安装MongoDB服务
1,参考:https://www.cnblogs.com/lecaf/p/mongodb.html 2,要设置环境变量 3,设置用户 use admin 注:MongoDB安装好以后由默认的admi ...
- linux的dos开关机命令
常用:halt.reboot CentOS关机命令: 重启命令 reboot shutdown -r now 立刻重启 shutdown -r 10 过10分钟自动重启 shutdown -r 20: ...
- 小D课堂 - 新版本微服务springcloud+Docker教程_5-04 feign结合hystrix断路器开发实战下
笔记 4.Feign结合Hystrix断路器开发实战<下> 简介:讲解SpringCloud整合断路器的使用,用户服务异常情况 1.feign结合Hystrix ...
- linux简单命令8---软件包安装
1:使用yum安装,它不能包查询和包校验.它安装的是RPM格式文件.没有yum文件 ---------------------------------------------------------- ...