Simple Rails Authentication without the Devise gem
There's a decent amount of Rails tutorials on Medium and this will be another 🤷🏻♀️, but it has Letterkenny gifs.
To start this you need Ruby and Rails installed. I used homebrew on a Mac, and that was fantastic. To start, let's create a new application:
rails new MyApp
cd into the project, pitter-patter, and lets that get at it!
Let's start with understanding a crucial part of Rails. It's a MVC, model view controller, framework. Which means any app built in Rails has that frame.
So, that means we will need models, controllers, and views for this tutorial. To generate those things all you need to remember is:
Take generating a model for our User:
rails g model User
Awesome right? moving right on.
So the gist of a sign-in system is this: the User(me) wants to log in. This means that the User(me) needs their information in the database so that the application can check against it to make sure they can let the (then authenticated) User through. Most of the time that means a password to validate that you are who you say you are.
There's a hitch, you CAN NOT leave the passwords in the database in plain text. Security-wise, it’s similar to leaving your home’s door open and unlocked with the price of everything written on your valuables. HARD NO, right?
So we need to translate those passwords into something unreadable and not easily translatable.
Say hello to BCRYPT!
bcrypt is a password hashing function created by Niel Provos and David Mazieres and we are going to use it to hash the password in our app’s DB.
if you go to your Gemfile and bcrypt comment out like so:
# gem 'bcrypt', '~> 3.1.7'
that's fine, we are just going to keep it that way for a quick sec.
We need to create our user object, which means creating a model! So in your console go ahead and generate a model:
rails g model User email first_name last_name user_name password_digest
Nice! That command not only creates a model but a table called users! It adds the columns email, first_name, last_name, and user_name along with the password digest for bcrypt.
Now we need to connect the info we want from the User to the Users table, so we need to do several things.
1.Uncomment the bcrypt gem from the Gemfile, and run the command:
2. Add this into the User model file User.rb
3. Create and rake our database with:
We started our database work! Yeah! But there's more after the break! But grab a puppers and take 5.
Ok, we are back! and what do we want? a User!
To do that we need a controller. Let's use the handy command again:
rails g controller User create new index
The create and new in the command are for methods in the new controller and two views associated with them. To understand that take a look at the Rails Asset Pipeline documentation.
In the user_controller.rb put:
and in a private method:
And that's all we need there!
If you find yourself asking “But what is that code doing???”, I'll tell you!
In the create method we create a new user object which is equal to a new instance of our User model that has been populated with the user_params, protected information that we want to require when making our User. We ask if the user variable has been saved, (research the difference between the create and new with a save), then the page should flash signup is successful. Else we flash a failure and redirect back to the page we are on. (We haven't set up our routes just yet!)
but how to create the user and enter them into the DB? Well, I'm so glad you asked!
in app/views/user/new.html.erb we need a form to do exactly that:
This form takes the information we need in our table for a new user and fills all the columns.
Now for some routing. Routing is how we POST or GET, something we can designate. Also, its where you can rename a page so that it shows up as “localhost:3000/signup” in the browser. So in MyApp/config/routes.rb, which should have some code, take it out and put in:
Well it won't be pretty but let's run Rail’s built-in server
and check out what's going on, if you navigate to localhost:3000/signup you should see a simple form with inputs! Now go ahead and try it out!
Now if it worked you should see:
But, if you want to do a check which is always a great idea you can do it in the rails console. Run
rails c in the terminal and request
That should show you all the info that you just entered in the form.
Now we want to log in!
For most of the internet, there are ways of tracking when a user logs in or arrives at a current point. Cookies and sessions are worth an in-depth look at.
For now, we are going to work with creating a session when logging in and destroying one on logging out. Run this:
rails g controller Sessions new create destroy
Here is where we implement login logic magic:
In create, we find set the user object to a User entry where the user_name is the entered one. If it is, and the password can be matched and authenticated the user gets redirected to the home page. As well, we set the session to the user id of the user object’s id. Now we have a couple more routes to add to MyApp/config/routes.rb:
In MyApp/app/views/sessions/new.html.erb add:
In this code you may want to change the
text_field_tag :name to something else like using the user’s email for logging in, just remember to change it in your sessions controller’s create method as well so that the form communicates through its POST routing correctly.
And add a helpful function into MyApp/app/controllers/application_controller:
This helper method allows us to check if the user that's on our page is a session having current_user or just an unaccounted pleb.
Add some html and ruby to the home page:
Ok now test away! And rejoice you built a simple authentication system!
All of this is super simple, but I've gone on to introduce larger concepts into this code like email registration, an is_online boolean and some other cool stuff I am doing for school.
PS, much of the code has flashes, to introduce them into your HTML just put:
<% if flash[:notice] %><%= flash[:notice] %><% end %>