目前我们已经完成了微博应用的用户模型最基本的开发,但是使用这个用户模型是通过控制台很不方便,这节课就来为微博应用添加用户登录和注册的可视化功能,讲解rails中会话的概念和使用。
用户是需要密码的,我们先给用户模型添加上密码字段,只要两个步骤:
第一个步骤就是给用户模型再添加一个字段叫password
第一步比较麻烦,要退出rails控制台,如下操作
完成后会自动创建如下文件
添加代码后如下:
代码的意思就是为users模型添加一个password字段。
还没完,别忘了数据库迁移的工作rake db:migrate即可:
?
?
第二个步骤就是在User模型里添加安全密码has_secure_password这么一个方法
第三步骤就是为password字段加上基本验证。
?
上节课我们添加新用户是通过控制台,实际上应该有页面来注册用户,注册的用户来使用网站的服务。根据前面所学,我们创建新用户的路由需要使用Users控制器的new这个action。我们可以首先创建Users控制器,因为我们只创建一个模型而已。
IDE中打开控制器文件:
先在浏览器访问new这个action试试(要是不显示网页就是没运行服务器rails server,因为错误会出现错误的红白页面才对)
我们能访问到new这个action,因为生成控制器同时生成了它的视图,但是我们还没为它添加任何功能。
打开路由我们把下面自动生成的路由删除
改成资源路由如下第二行:
既然是注册页面,那么很明了:一个填写表单信息的页面,该页面有一个提交按钮。
我们打开new这个视图:
会报错,因为写完视图代码,还需要去new动作添加一段代码,代码就是为了给前端的表单提供变量支持:
该视图代码我们只要知道点击注册会将用户名、邮箱和密码这三组信息发送到我们的user控制器对应的create这么一个action动作就可以了。
还有前面添加的字段出错了正确如下,要加上_digest:
?
下面开始就用git来操作,不用win+R的cmd窗口了,如下直接打开工程目录报错,也许目录没问题,我们一级一级进入工程目录就可以:
我们输入一组信息试试点击注册试试:
结果如下:
报错是因为表单提交时提交给user控制器的create这个action进行内容的创建,但是我们的user控制器现在还没有create动作,
所以下面我们加入健壮参数,我们只要知道健壮参数可以限制只提交特定几个字段而其他字段不允许提交就行,还有前面有错,user前面有@,正确代码如下:
这时候回到new视图
那么可以看到是password字段出问题,这个字段是后来添加上的,可能的原因是我们添加没成功,所以我们删除如下截图的第三个文件
然后命令行输入rails g migration AddPasswordDigestToUsers:
重新生成上面的删除文件,添加完代码如下:
然后再执行
这时候重进new页面点击提交就可以了,如下:
还有我们前面的new视图代码少了一行<%=f.password_field :password %>,补充后如下:
这时在重新注册提交,结果如下,密码标签下面就有了密码输入框:
如上,我们提交完的结果是又回到了注册页的页面上,这个就是下面代码的作用
字段标红,是因为我们添加了验证,验证不通过就标红。
但是这样给用户的体验是非常差的,因为没有给出哪里错误的提示,用户还会继续输入错误,那么我们就来添加错误提示信息:
之前我们就在控制台用过,当save失败,错误信息会保存到errors.full_messages这个字段中
在new视图添加错误提示的代码3到14行
刷新new页面后,用户名不填,后面随便填写些数字,密码和密码确认没填写一致,结果如下
用户名不能为空,email格式不合法,密码和密码确认不一致,密码太短
注册失败的代码写完之后,我们下面完成注册成功的代码的编写,这里我们假设用户注册成功之后就会进入显示用户的个人资料页面(这个显示其实就是这种路由页面,users/id):
所以我们就在控制器的save成功里面添加跳转的代码,第10行
这样还不行,因为我们还没有添加用户个人资料页,添加也很简单
首先在user控制器中添加show这个action,里面代码也很简单就是根据路由传来的id(它保存到params里面),我们根据id查找并保存到变量@user里面。第16到第18行。
然后去新建users文件夹下的show页面并添加代码:
这时候我们刷新new页面并依次输入sundi,[email protected],1234567,1234567
结果好像输入的没有在页面正常显示,原来是页面代码写错了,<%后面没写=,修改后如下(跟br没关系,br是换行):
这时候就表明我们的注册功能能够正常地运行了,有了注册功能下面我们还需要一个登陆功能,实现登陆功能就涉及到本节课的一个重点"会话":
我们在登陆一个网站以后,不退出网站的情况下默认都是登陆这个账号的,所以后面可以访问任何页面而不用再次登陆。其实这样就是会话保持的这么一种技术,那么什么是会话呢?我们可以理解为是用户浏览器和rails服务之间的关系的一种保持,保持的就是一些用户的登陆状态和用户的浏览信息等等。
那么rails是怎么实现会话功能的呢?
Rails常用的方法就是使用session来实现会话,rails本身提供了一套session的方法让用户可以直接去调用。
?
Session:在计算机中,尤其是在网络应用中,称为"会话控制"。Session 对象存储特定用户会话所需的信息。这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web 页时,如果该用户还没有会话,则 Web 服务器将自动创建一个 Session 对象。当会话过期或被放弃后,服务器将终止该会话。Session 对象最常见的一个用法就是存储用户的首选项。例如,如果用户指明不喜欢查看图形,就可以将该信息存储在 Session 对象中。有关使用 Session 对象的详细信息,请参阅"ASP 应用程序"部分的"管理会话"。注意
会话状态仅在支持 cookie 的浏览器中保留。
?
那么我们现在知道了session这个概念,我们就去实现一个会话功能,先添加一个会话控制器并在里面添加一个动作叫做new:
之后我们再去添加路由信息:
先把第二行代码的路由删除
添加三个路由,分别是new、create和destroy动作,代码第5第6第7行:
new动作向用户显示登陆的页面(就跟注册里面的new动作一样),create用来创建一个新的会话(它相当于注册里面注册用户的那个create),destroy就是用来销毁或者删除用户登录的会话也就是我们平常所说的退出会话。
完成这部分之后,我们还要一个登陆页面,如下是自动生成的new视图:
更改为,代码意思就是给用户提供一个登陆表单,当用户点击登陆按钮以后就可以将登陆信息提交到create这个动作中(这个我们前面就在注册页面见过了,很方便),我们只要知道这是用来显示登陆框填入信息点击提交就会将输入信息提交到后端:
接下来我们打开sessions这个控制器:
在里面添加一个动作叫create,首先我们要登陆最基本就是先查找存不存在这一个用户,如果存在还要去验证这个密码正不正确,查找用户我们使用find_by对email这个字段进行查找,并且我们在查找之前将用户输入的那些字段强制转换为小写。
(email:params[:session][:email].downcase),前面是数据库中的email,后面是用户的输入对应params里保存的session参数的该参数里面的[:email]字段
然后就是判断用户存在不存在并且判断密码正确不正确
session[:user_id]=@user.id
#这句话其实就是将当前用的的@user.id保存到session变量的:user_id字段中,只要我们不去销毁或者置空这个值,那么这个值就会在整个rails的生命周期中一直存在。这个就可以作为会话状态的凭证,我们验证是不是有这个值存在就知道当前有没有会话登陆状态在保持,进而通过user_id就可以判断当前用户是不是登陆。
当我们有了用户登录这个方法,我们其实可以在用户注册完成以后直接让用户登录。怎么做呢?其实很简单,在用户控制器的注册方法后面也添加这么一行代码就行,如下图的第10行代码。就是就是将当前用的的@user.id保存到session变量的:user_id字段中就可以记住用户的登陆状态了。
最后我们要做的就是完成退出的功能,退出其实很简单就是将session置空就行了,到session的控制器添加一个destroy方法如下:
delete和[]没空格隔开则
我们还需要在页面上添加退出按钮,比如我们添加到个人资料页,如下
我们直接进入login页面并输入如下:
点击登陆:
还有注意find_by和后面的(不能有空格,否则如下:
其实这些问题很简单,视频里错误,正确如下:
find_by前面要加User.
还有验证的英语是authenticate,视频里写错了
前面的错误可以通过查看文档来发现,文档地址http://doc.rubyfans.com/
进入网址后点击Rails的v4.1.0,左上角输入方法名,右边就是使用案例,可以知道我们需要在我们的代码find_by前面加上User
这样第一个错误就解决了,但是还是报错
?
然后我们文档查找发现没有找到这个方法(rails的方法,ruby而非rails的方法自可能找不到,但这里我们已经知道要找的方法就是rails的方法,但还是没找到就知道是我们方法名拼写错误),而验证的英语是authenticate,所以我们拼写错误,我们文档找该方法试试,就能查找到该方法因为是登陆验证所以我们就点击这第一个的on GitHub(没有像前面一样简短的使用案例,因为验证需要上下文,所以我们可以点击进入GitHub里面查看该方法的定义使用形式)
正确代码如下:
我们输入前面注册的用户信息点击登陆就能正确显示如下页面
到此说明我们登陆成功了。这时候我们点击上面的Log out链接进行退出,就回到如下页面重新登陆:
还有个注意事项,前面的如下应该是session.delete(:user_id)括号不是[],不然会报错如下(但是我们delete与后面的[有个空格隔开就能不报错,这个是自己发现的,先记住吧):
?
到此点击Log out能跳回登陆的页面,说明我们成功退出,销毁了登陆的会话。
但这里问题其实还非常多,比如哈希验证没有涉及,代码还可以写得更简洁等等。