By Harvey Ico, server-side engineer from Unifa
So, you want a user session feature in your application?
Maybe you're already exploring gems like devise
, sorcery
, or others.
Hold on! With the recent release of Rails 8, you can now achieve this without needing to install external gems.
Installation
To get started, the magic command is:
rails generate authentication
This command generates most of the necessary files for you.
Heads up! Before running this command, make sure you’ve created your database. If you don’t, Rails will skip creating migration files—something I learned on the way.
Here's an example of what gets generated:
➜ $ rails generate authentication invoke erb create app/views/passwords/new.html.erb create app/views/passwords/edit.html.erb create app/views/sessions/new.html.erb create app/models/session.rb create app/models/user.rb create app/models/current.rb create app/controllers/sessions_controller.rb create app/controllers/concerns/authentication.rb create app/controllers/passwords_controller.rb create app/channels/application_cable/connection.rb create app/mailers/passwords_mailer.rb create app/views/passwords_mailer/reset.html.erb create app/views/passwords_mailer/reset.text.erb create test/mailers/previews/passwords_mailer_preview.rb insert app/controllers/application_controller.rb route resources :passwords, param: :token route resource :session gsub Gemfile bundle install --quiet /Users/harvey.ico/.rbenv/versions/3.3.6/bin/ruby: No such file or directory -- bin/bundle (LoadError) generate migration CreateUsers email_address:string!:uniq password_digest:string! --force rails generate migration CreateUsers email_address:string!:uniq password_digest:string! --force invoke active_record create db/migrate/20241127013611_create_users.rb generate migration CreateSessions user:references ip_address:string user_agent:string --force rails generate migration CreateSessions user:references ip_address:string user_agent:string --force invoke active_record create db/migrate/20241127013612_create_sessions.rb Could not find gem 'bcrypt (~> 3.1.7)' in locally installed gems. Run `bundle install --gemfile /Users/harvey.ico/projects/dummies/test_1/Gemfile` to install missing gems.
If you don’t already have the bcrypt
gem installed, the generator will add it for you. In that case, you’ll need to run bundle install
before proceeding.
Once that's done, run:
rails db:migrate
Example output:
➜ $ rails db:migrate == 20241127013611 CreateUsers: migrating ====================================== -- create_table(:users) -> 0.0021s -- add_index(:users, :email_address, {:unique=>true}) -> 0.0004s == 20241127013611 CreateUsers: migrated (0.0026s) ============================= == 20241127013612 CreateSessions: migrating =================================== -- create_table(:sessions) -> 0.0071s == 20241127013612 CreateSessions: migrated (0.0071s) ==========================
How to use
What’s next? How do we actually use this?
First, take a look at the files generated by the scaffold. You'll notice a file named:
app/controllers/concerns/authentication.rb
This concern should be included in any controller where authentication is required.
Typically, developers add it to the ApplicationController
or a shared base controller. Conveniently, the generator automatically inserts the concern into ApplicationController
for you. Depending on your use case, you may want to remove it from there.
class ApplicationController < ActionController::Base include Authentication end
So, what’s in the Authentication concern? It includes several useful methods. Here are the key ones:
- allow_unauthenticated_access: A class method to bypass authentication in certain scenarios.
- authenticated?: Returns a Session object. However, I’d recommend renaming it to something more intuitive, like current_session, as its name might suggest it returns a boolean. You can access the associated User object from this method as well.
- require_authentication: Use this in a before_action to enforce authentication.
- after_authentication_url: Customize this method to define where users are redirected after logging in.
- terminate_session: Use this method to log out a user.
- start_new_session_for: Accepts a User object to start a new session. I suggest terminating the existing session first before using this.
Rails also sets up some basic session pages and routes for you.
For instance, the default login path is /sessions/new
, which maps to the Rails helper new_session_path
. The view is a basic skeleton so be sure to design it to your liking!
app/views/sessions/new.html.erb
You can view all authentication routes by running:
rails routes
Final thoughts
Until now, my go-to gem for authentication was devise. However, devise has become quite large and packed with features I rarely use. Removing unnecessary features and customizing it can be a hassle.
With the built-in Rails 8 authentication, I now have a lightweight, easy-to-setup alternative.
That said, note that this feature only provides the following:
- User login page
- Password reset page
What’s missing?
- User sign up page
But don’t worry—that’s straightforward to implement. Creating a sign-up page usually involves inserting a User
record with an email_address
and password
.
Unifa is actively recruiting, please check our website for details: