Bummer! This is just a preview. You need to be signed in with a Pro account to view the entire video.
Creating User Sessions in Rails14:51 with Jim Hoskins
[Master Class] [Designer and Developer Workflow] [Creating the User Session] 0:00 So now, we've updated our form view where we can have our password 0:05 and password confirmation and our properly crypted password 0:09 will be stored in the database. 0:12 So, we can pretty much register and edit all the users. 0:14 So, the next step is to actually log in. 0:18 In order to log in, we'll be using a session, and a session is 0:21 a model that sort of handles a particular session. 0:25 So, when we log in, we'll be creating a new session for a user, 0:28 and when we log out, we'll be deleting a session. 0:32 So, it works just like our other models where we'll be creating and deleting things. 0:34 So, let's go ahead and generate our session. 0:39 So, we saw before that there is a generator that's installed with authlogic 0:42 called "authlogic session," and basically, we can use this to generate our user session 0:47 which is a session that authenticates a user. 0:53 So, we'll do "rails generate authlogic:session" 0:57 and we'll call this a "UserSession." 1:07 So, now it's gone ahead and created a file called "app/models/user_session.rb," 1:13 so let's go check that out, and here we are in app/models/user_session.rb. 1:18 Now, you'll notice this is a little bit different than our typical model. 1:25 It doesn't inherit from ActiveRecord base. 1:28 In fact, there is no database table for the user session. 1:32 The model itself is represented in the database, 1:35 so it can abstract away the actual logging in and logging out. 1:38 So instead, it inherits from Authlogic Session Base, 1:42 and that class provides us with a lot of functionality, 1:47 which will ultimately allow us to log in. 1:50 Now, since it's called a user session, it's assuming that 1:53 what it's going to be authenticating against is a user class, 1:56 which will act as authentic, which we've already gone ahead and set up. 2:00 So, those assumptions should be true. 2:05 So now, the steps are we're going to create a new controller for handling our authentication, 2:08 or handling our actual user sessions, and when we want to log in 2:13 we'll call the create method, and we'll generate a new user session 2:18 based on the authentication credentials that have been passed. 2:22 And if that's successful, then we'll have a new session where somebody is logged in, 2:26 and if it's not successful, it will redirect them back to the new user session screen 2:31 or the log in screen. 2:35 So, let's go ahead and generate a new controller for our user sessions. 2:37 So, we'll do "rails generate controller" and we'll call this "UserSessions," 2:41 and what I'm going to do is define a method called "new" which will be our log in, 2:52 and this will just generate a view for the new field, which is really the only 2:58 user visible action that the user sessions will implement. 3:02 So, if we run that, it's created a new controller called "user sessions controller," 3:06 and it's created a new view file under views/user_sessions/new.html.haml, 3:10 and that new .html file will be our log in page. 3:17 We'll go ahead and adjust our routes later so the route will look like /login. 3:21 So, let's go to our new user sessions controller because 3:27 it's just generated an empty controller. 3:30 What we have to do is now add the logic that we want to add to it. 3:32 So, let's go ahead, open up controllers, user session controller. 3:37 So, here it's generated a new method stub, and this is what's going to be called 3:42 when we go to usersessions/new, and what we need to do is 3:47 instantiate a new user session, and this will be useful because in our form 3:52 our user session instance is actually what we're going to be basing our form off of. 3:58 So, since we have a real object of the user session, 4:03 it allows us to treat it just like any other model in our application. 4:06 So, we'll just go ahead and say "@user_session = UserSession.new." 4:10 Then our new .html view will render and display an empty form for user session. 4:20 So, when that form submits or they hit log in and it submits, 4:28 that's going to go to create. 4:32 And this is the method where we're actually going to do our authentication. 4:35 So, in this create method is actually where we're going to do our authentication. 4:39 So, the first step is to get a user session instance. 4:43 This will be a lot like our new method. 4:46 We'll do "UserSession.new." 4:48 However, this time we've been passed in parameters, so we want to instantiate 4:52 our user session with the, let's say, email and password that were submitted. 4:56 So, to do that we'll just pass in (params[user_session]). 5:01 Now, this just looks like any other create method where we instantiate a new object 5:09 based on the parameters, and that's what's really great about authlogic 5:13 is it really has the same sort of pattern as any other model. 5:16 So, the next step is where the real magic happens. 5:21 We're going to try to save this user session. 5:24 So, we'll say "if @user_session.save," 5:26 and then there's going to be an else and end here. 5:33 So, when we try to save a user session, what authlogic does is it takes the information 5:37 that it was passed, basically our email and password, and it tried to find a user 5:42 who matches those credentials. 5:47 If it finds one and we save it, it will go ahead and say that we are authenticated 5:50 and return true, and it will set the cookie saying this person is logged in 5:55 so we can handle our true session here, so at this point they are logged in. 6:00 So, why don't we go ahead and just leave a flash here, 6:05 and this is just a notice at the top of the page, 6:09 so we'll say "flash(notice) = "Welcome to EasyJobs" 6:11 or something along those lines. 6:19 We can go ahead and change this easily later. 6:21 So, if we're logged in, we want to go ahead and redirect them somewhere. 6:23 So, we'll just say "redirect_to jobs_url." 6:25 Now, in this else clause here, we were not able to save our user session, 6:33 which means that based on the information that was passed in via params, 6:36 which I just realized I misspelled. 6:41 It is not "parms." 6:43 There we go. 6:45 Based on that information, we are not able to log in, so what we want to do is actually 6:47 go ahead and just render our new form again. 6:51 So, we'll say "render action of new" and what this does is 6:54 since we have our @user_session set with the information that was submitted 7:01 when we render this new action here, it will actually prepopulate the email field 7:06 with what they pass through. 7:12 The actual password field should be blank because we don't want to pass 7:14 the password back to them, but it's a nice little tip that we will be able to give 7:17 to the user that you don't have to enter your email again, or you can review it. 7:21 So, this handles our logging in. 7:25 Basically, with the user session we just pass it some information like email and password. 7:27 If it saves, they're logged in. 7:31 If not, they need to try again, and destroying is pretty much the same thing. 7:34 When we log out, we want to go ahead and destroy this user session. 7:40 So, we'll define destroy. 7:47 So, how do we find our current user session? 7:50 Well, this is code that we're going to need throughout the entire application. 7:54 We're going to need to be able to search for the current user session 7:57 and the current user in order to, for instance, display who's logged in, 8:00 to perform authorization checks to see if they're allowed to perform certain actions. 8:06 So, what we're going to do is write different methods, and we'll save them 8:10 in our application controller so they're available to us at any place in our application. 8:13 So, we're going to take a break from writing our user sessions controller 8:17 to go to our application controller, and our application controller 8:21 is in app, controllers, application controller. 8:25 So here, we're going to define two private methods. 8:30 So, we'll define private and down here is where we'll define our method. 8:33 The first method we want to do is current user session, "current_user_session." 8:38 And we'll define another method which will be current user, 8:46 and where current session will actually retrieve the current user session 8:52 more often we actually want the user that's associated with the session, 8:56 so this convenience method "current_user" will provide that. 9:00 Now, the way we can get the current user session is by using the user session 9:04 class method called "find," and authlogic will use its ways to find out 9:08 if there is a current user session and return that instance to you if it exists, otherwise no. 9:13 Now, while this will technically work, we may be calling current user session 9:18 multiple times in our request. 9:23 So, what we want to do is make sure we're not calling user.find all the time. 9:26 Instead, we want to cache or memoize the result into an instance variable 9:29 so we're not calling user.find over and over again. 9:34 So, the first thing we'll do is we'll say "@current_user_session = UserSession.find." 9:37 So, after the first time we've called it, @current_user_session is defined. 9:47 So, if we call it a second time, what we want to do is check if @current_user_session 9:51 has been defined and if so, we want to return that since we already did the find call on it. 9:55 We can just return the cached result, otherwise we'll actually want to do 10:01 the User.Session find here. 10:06 So, what we'll do is we'll say "return @current_user_session" 10:09 if we have current user session defined, so we'll do "defined?(@current_user_session). 10:16 Another reason we can't just say "return @current_user_session 10:26 if @current_user_session" is because if they are logged out, 10:29 current_user_session will be nil and it will try to reevaluate User.Session.find every time 10:33 if somebody's logged out. 10:40 So, this is just a way of us caching so don't have to call User.Session.find 10:42 over and over again if we call current user session over and over again. 10:45 Now, let's say we want to get the current user. 10:49 Well, to do that we will need to get the current user session, 10:51 so we can just type in "current_user_session" and call that method, 10:54 and we can call ".user" on it. 10:59 Now remember, if somebody's logged out, current user session will be null 11:02 and if we try to call user on that, well, we're going to get an error. 11:05 So, what we need to do is check if current user session is true 11:09 or a truthy value or just not nil. 11:14 So, by using this here, we'll say "current_user_session," make sure it's true. 11:17 If it is, then we'll call "current_user_session.user." 11:21 Now, if current user session is false or they're logged out, 11:24 when this evaluates to nil, or false rather, it will not evaluate this side 11:27 so we won't get an error. 11:32 Now you can see that we've called current user session twice in quick succession, 11:35 which is why this caching is important. 11:38 Again, we don't want to continue doing this over and over again, 11:41 so let's implement the same sort of caching, so let's implement 11:43 the same sort of value caching here that we did here. 11:46 So, instead of just returning, we'll return it while setting it to current user, 11:49 and then before we try to do that, we'll say 11:57 "return @current_user if defined?(@current_user)." 11:59 So now, from anywhere in our controller we could type in "current user," 12:08 and if somebody's logged in, we'll get a user instance of the person who's logged in, 12:11 and if they're not logged in, then we'll get nil. 12:15 We could do the same thing for current user session if we actually wanted 12:18 to get the session which we actually do in our log out method. 12:21 Now, before I switch away from this, there is one last thing I want to do. 12:25 So, we'll call helper method and pass it the symbol "current_user_session" 12:33 and "current_user." 12:39 What this does is it makes the methods current user session and current user 12:43 available in our views as helper methods because quite often in our views 12:46 we're going to want to access current user. 12:51 So now, we can go ahead and save that out. 12:53 So, let's just hop back to our user sessions controller 12:56 to see if we can't implement destroy now. 12:59 Well, now, this is as simple as doing "current_user_session.destroy." 13:01 Now, you'll realize that if somebody's logged out already then current user session 13:11 will return null and trying to call destroy on it will cause an error. 13:15 Now, there's a couple of different ways we could solve this. 13:20 The most correct, in my opinion, way to do this would be to restrict the destroy method 13:22 so it's only visible to people who are logged in, and that will happen 13:28 when we start doing our authorization. 13:32 Right now what I want to do is just to make sure we don't get this error, 13:35 I'm going to call "current_user_session && current_user_session.destroy." 13:38 That way, if there is no current user session, the destroy method will not be called. 13:46 No harm, no foul. 13:51 It will be a little bit weird to log out while you're logged out, but right now it avoids the error. 13:53 So, then I'm just going to go ahead and just type in "flash[:notice]" 13:59 and just say "You are now logged out." 14:04 And let's go ahead and just redirect to the jobs url again, the home page. 14:11 So, now we've got the controllers and models for our session set up. 14:18 We have a user session which handles all of the logic of logging in 14:21 and authenticating the user. 14:25 We have the user sessions controller which will ultimately 14:27 be our log in and log out controller. 14:30 We still need to create the views for it, and in our application controller 14:32 we've created a couple of methods that will allow us to get the current session 14:36 and the current user. 14:39 So, up next we're going to go ahead and jump towards the front end 14:41 and create our log in form and some information that will be displayed 14:44 when you're logged in or when you're logged out. 14:48
You need to sign up for Treehouse in order to download course files.Sign up