The last few weeks I have been chronicling my experience creating an application using Rails and React with the react-rails
gem. One of the more general parts of an application that is applicable to a wide variety of projects is a user login. While building out the skeleton of a user login system for the trivia app I am currently working on, I thought it might be an opportunity to share my approach for others that might be looking to build out a similar system.
Small note about this post: there are so many different ways one could approach building a login system for their applications. If you would like to follow along and build your own, feel free to play around with things and make them your own. To keep things as simple as possible, the system I will be building out here will be pretty bare bones. For this post, I am also working with Rails 6 and not utilizing the React functionality of the application.
Let's Get Started!
The first thing we are going to need is a Rails project to work in. I already have one built, but if you are looking to just play around or create your own new project for whatever reason, you can do so by using the rails new <app-name>
command.
For our login system, the goal is to have a Sign Up page where users can create an account and a Login page that will allow them to log into their account. To be able to test this, we will also have a "profile" page that will be visible after a user is logged in. Let's look at a breakdown of the things we will need to make this happen:
- User Model & Database Migration
- Sessions
- Helpers
- Routes
- Controllers
- Views
User Model
The first thing we will need to do is create a Model for our User data. For security, we will be using the bcrypt
gem to salt and hash our user's passwords. To add it, simply go to your gemfile and add gem 'bcrypt'
. Rails may have automatically added this gem when creating a new project, in that case you just have to remove the comment. After making sure it is included in your gemfile, simply run bundle install
to install the gem in your project.
We are ready now to create our actual model. You could just create a new file in the models
folder, but we are going to use a generator for this. The benefit of using the generator is that not only will rails automatically create the model file for us, but it will also create a migration for us so that we can easily create a Users table in our database.
For our user model we will be keeping things simple and requiring just a username
and a password
field.
rails g model User username:string password_digest:string
With this command Rails will generate a User model for us as well as a migration for that model. The migration will create a User table with a username and password column as well as standard id and timestamp columns. The reason we are using password_digest here is because of bcrypt. When we connect our model to the gem a little later, this column will give us access to a password and password_confirmation field and allow us to authenticate our user's password.
To use bcrypt with our model is very simple. Let's just go to the model.rb
file and add the helper has_secure_password
inside the class definition. It should look like this:
Now that we have everything connected, the last step is to load our migration. If you haven't already, create your database by using the rails db:create
command. After the database is created we can simply run our migration with the rails db:migrate
command. We should now have a working User model and database table.
Sessions
We will be taking advantage of the sessions hash that Rails provides for us to keep track of the logged in user. I don't want to go into too much detail here, but essentially this provides us a way to persist the current user through our application so that they don't have to continually log in. Just know that when you see us using session[:user_id]
this is what we are accessing. If you'd like to get a more detailed understanding, feel free to read more about it here.
Helpers
This next part is optional, but I find it useful when developing my own applications. We are going to set up some helper functions that will allow us to DRY up our code a little bit. Specifically we will be creating a logged_in?
helper that will return true or false based on whether or not there is an active session[:user_id]
and a current_user
helper that will return to us the database model for the currently logged in user. We will place the code for these two in app/helpers/application_helper.rb
Routes
The last bit we need to set up before getting into the nitty gritty of Controllers and Views is setting up our routes. We are going to have two Controllers we need to create routes for: session
and users
. We will be using the sessions to handle the session actions of logging in and out. The users will be in charge of the actual user data for things like creating and editing new users.
For users we can use the resources
helper and specify the routes we want Rails to make available for us. For the sessions routes, I prefer creating them myself so that I can customize the paths.
Controllers
The controllers will allow us to perform some logic as well as pass information on to our views. When the user requests a specific endpoint, the controller will execute the corresponding code and make certain variables available to our view for whatever we may need. I prefer to create my controller and view files individually, but you can also use a rails generator to do both automatically. If you are creating your own Controller like I am, just create a new file in the app/controllers
folder using the plural like this: sessions_controller.rb
. The naming convention is important here so that Rails can link your models, views, and controllers together.
For the Sessions controller we will only need a create action. Since our login
route will just render our login view, Rails will automatically handle that for us. In our create action we will search our database for the user entry that matches the username provided in the login form, authenticate using bcrypt and the provided password, and then setting the session[:user_id]
and redirecting the user.
The Users Controller is a little more involved. We will need a new action that will give our view access to a new User instance.
Our create action will be very similar to our login action, with the exception that we will be creating and saving a new user database entry. Lastly we will have a show action that will give us access to the data for the currently logged in user.
We will also be enforcing strong params which you can learn more about here.
Views
The last step is to create some views that we can actually interact with. This is the bit that is most customizable, as you can create whatever variety of UI you would like for this. As mine are also rather basic just to get things working, I will just give an overview of what is needed here.
We will need to first create a users
and sessions
folder within the app/views
folder. There we can create our view files for each of our controllers. Using the naming convention of <action_name>.html.erb
Rails will automatically render the corresponding views to our controller actions. For example, our login view should be app/views/sessions/login.html.erb
.
For our sessions, we will need a login
view, and for our users we will need a new
and show
view.
For the login and new pages, we will need at minimum a form for the user to input a username and password and submit that data to our controller for handling. Below you can see my bare bones implementation of these pages.
The final show page can really display any information you would like. Here we have access to the data for the logged in user so something like a profile page that displays the user's information, with buttons to edit or delete data might be a good idea.
Conclusion
And that's how I get started with pretty much every Rails project I create to have a bare-bones functional login system. I hope this was helpful in some way if you're still here. Happy Coding!
Top comments (5)
use devise easier, a lot of things misleading.
Even the devise documentation suggests rolling your own to begin with !
I tried this and got stuck on "The action 'home' could not be found for SessionsController" it seems like sessions need a home definition but there is not such in the present article.
I'm still confused as to how to view several of the pages when using localhost. When i run this on my machine I'm able to get to the login page but not anywhere else.
Great! Thank for share your knowledge with us.