- Learn about and utilize
session
in Rails - See how
session
&flash
are different than other variables in Rails
session
is a special type of hash-like-object that we utilize to keep track of data throughout a users "session", which normally ends when they close their browser. session
is similar to flash
, except that data stored there will not go away after the next request-response cycle. Instead it will be stored indefinitely. session
is most often used to store information about a user when they log in.
Rails will automatically delete the information from the session
when the user closes the browser. We can also manually remove the data if we not longer want to track it (like when the user logs out).
Let's see it! We are going to create a special form which is going to allow our users to "log in". This is not a secure way to simulate logging in, but we are using this as our first stepping stone to creating "real" authentication, which we'll do later on. We'll allow the user to type a username which will "log in" as that user.
Get the most recent version of the book site code from your instructor, then work through these steps with a partner.
-
Create a new
User
model with one column,username
$ rails generate model User username:string $ rails db:migrate
-
Create a
UsersController
$ rails generate controller Users
-
Add the following routes to your routefile:
get "/login", to: "users#login_form", as: "login" post "/login", to: "users#login" post "/logout", to: "users#logout", as: "logout" get "/users/current", to: "users#current", as: "current_user"
Question: Are these routes RESTful? If not, why not?
-
Create the
users#login_form
action and view. The view for this action should useform_with
to create a form for theUser
model, accepting just theusername
.Question: Do you need to do anything in the controller action to enable this?
Question: Given the routes above, do we need to do anything special with
form_with
?Click here to see our implementation
# app/controllers/users_controller.rb def login_form @user = User.new end
<!-- app/views/users/login_form.html.erb --> <%= form_with model: @user, class: 'login__form', url: login_path do |f| %> <%= f.label :username %> <%= f.text_field :username %> <%= f.submit "Log In" %> <% end %>
-
Create the
users#login
action. This action should read theusername
field sent by the form, and do one of two things:- If the
username
corresponds to aUser
in the database, that user is returning to our site. Save their ID insession[:user_id]
- If the
username
does not correspond to an existing user, this is a new user logging in for the first time. Create aUser
model, and use its ID to populatesession[:user_id]
.
Question: How will the data sent by the form be organized? If you're not sure, how could you find out?
Click here to see our implementation
# app/controllers/users_controller.rb def login username = params[:user][:username] user = User.find_by(username: username) if user session[:user_id] = user.id flash[:success] = "Successfully logged in as returning user #{username}" else user = User.create(username: username) session[:user_id] = user.id flash[:success] = "Successfully logged in as new user #{username}" end redirect_to root_path return end
- If the
-
Create the
users#current
action. This page should display information about the currently logged-in user.Question: What should this page do if no one is currently logged in? There is more than one possible answer to this!
Click here to see our implementation
# app/controllers/users_controller.rb def current @current_user = User.find_by(id: session[:user_id]) unless @current_user flash[:error] = "You must be logged in to see this page" redirect_to root_path return end end
<!-- app/views/users/current.html.erb --> <p>You are logged in as user <%= @current_user.username %></p>
-
Create the
users#logout
action. This should setsession[:user_id]
tonil
and redirect the user back to theroot_path
. -
Now that you have your routes and controller actions, update your view(s) so that a user can perform the actions of logging in and logging out.
-
Think about other things you could add to improve the user experience. What has worked well on other sites you've visited?
-
Think about how you could restrict actions based on who is (or isn't) logged in. You don't need to write code for these, just think about how you might do it.
- Only logged in users may change data on the site (the C, U and D of CRUD)
- Users may mark books as their "favorites", and the current user page includes a list of that user's favorite books
- Only the user that added a book to the site may edit or delete that book
We will discuss these authorization workflows further in the coming weeks.
Rails provides a few special hash-like objects that allow us to go above and beyond local and instance variables in our Rails applications.
We will utilize session
to keep track of logged in user information.
See this updated table that now includes session
.
Name | Data Comes From | Available |
---|---|---|
flash |
This or the last controller action | The rest of this request cycle and the next complete request cycle |
flash.now |
This controller action. Adds to the flash from the last cycle, but will not be carried over to the next one. |
The rest of this request cycle (in flash ) |
session |
Some controller action | Until the user closes the browser |
params |
The request (URL or body) | The corresponding request cycle |
- Sessions, Cookies and Authentication (not including 'Rolling Your Own Auth')
- Rails Guide on Session