Back to home

Devise Part 1: Setting Up Devise With Rails 7 And React main image

Devise Part 1: Setting Up Devise With Rails 7 And React

This post will cover the first of six parts of the series on Devise and Ruby on Rails.

The series will cover the following:

  1. Setting up a basic sign up and login flow with Devise.
  2. Using Redis sessions instead of cookies.
  3. Adding Tailwind to our project to beautify the sign-up flow.
  4. Authorizing separate frontends to use our Rails API.
  5. Setting up Devise with Omniauth to our project to sign in with GitHub OAuth.
  6. Adding in Recaptcha to our project to protect against spam.

Source code can be found here

Prerequisites

  1. Basic familiarity with setting up a new Rails project.

Getting started

We will use Rails to initialize the project demo-rails-7-with-devise-series:

# Create a new rails project $ rails new demo-rails-with-react-frontend $ cd demo-rails-with-react-frontend # Add required gem $ bundler add devise # Scaffold the app $ bin/rails generate devise:install $ bin/rails generate devise User # Generate a home controller for us to test against $ bin/rails generate controller home index

Updating our developer environment settings

Next, we need to update the default action mailer config at config/environments/development.rb:

config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

Requiring authentication for our controller

We are going to update the application controller at app/controllers/application_controller.rb to always require a user to be logged in for all actions:

class ApplicationController < ActionController::Base before_action :authenticate_user! end

That last part is up to you. If you want to restrict the controllers that will be requiring auth, you can always add before_action :authenticate_user! to that file.

Setup routing

At this stage, we want to update our routes to set our Home controller index to the root route:

Rails.application.routes.draw do devise_for :users # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html # Defines the root path route ("/") root 'home#index' end

Setup the Devise initializer

In my current version of Rails 7, I also needed to update the config/initializers/devise.rb file to uncomment the config.navigational_formats and add the :turbo_stream for the default Devise handler after signing up:

config.navigational_formats = ['*/*', :html, :turbo_stream]

Updating our view

Let's set the values of app/views/home/index.html.erb to the following:

<h1>Home#index</h1> <p>Find me in app/views/home/index.html.erb</p> <%= link_to "Log out", destroy_user_session_path, data: { "turbo-method": :delete } %>

We are only adding in that last line here.

Starting the server

Finally, we can migrate and start the server:

# Create and migrate the db $ bin/rails db:create db:migrate # Start the server (including the React app) $ bin/rails s

At this stage, going to localhost:3000 will redirect us to our sign in route http://localhost:3000/users/sign_in.

Redirected to sign in

Redirected to sign in

Select Sign up to redirect to our sign up route http://localhost:3000/users/sign_up.

Sign up

Sign up

Signing up and viewing our page

Sign up with whatever credentials you wish.

I am going to use hello@example.com as the email and password as the password.

After signing up, you will be redirected to the root path and authenticated for the application. Hooray!

Authenticated

Authenticated

Things to note from the magic happening

A lot of magic happened when we ran the generate and install commands for Devise.

If you check under db/migrate/<timestamp>_devise_create_users.rb for the Devise migration, you will see that Devise setup a migration for us with some sensible defaults and commented out extras:

# frozen_string_literal: true class DeviseCreateUsers < ActiveRecord::Migration[7.0] def change create_table :users do |t| ## Database authenticatable t.string :email, null: false, default: "" t.string :encrypted_password, null: false, default: "" ## Recoverable t.string :reset_password_token t.datetime :reset_password_sent_at ## Rememberable t.datetime :remember_created_at ## Trackable # t.integer :sign_in_count, default: 0, null: false # t.datetime :current_sign_in_at # t.datetime :last_sign_in_at # t.string :current_sign_in_ip # t.string :last_sign_in_ip ## Confirmable # t.string :confirmation_token # t.datetime :confirmed_at # t.datetime :confirmation_sent_at # t.string :unconfirmed_email # Only if using reconfirmable ## Lockable # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts # t.string :unlock_token # Only if unlock strategy is :email or :both # t.datetime :locked_at t.timestamps null: false end add_index :users, :email, unique: true add_index :users, :reset_password_token, unique: true # add_index :users, :confirmation_token, unique: true # add_index :users, :unlock_token, unique: true end end

You will also note that we also had some options to uncomment some strings to help us set up the Trackable, Confirmable and Lockable options. You can read up more on those options here.

We won't follow up too much on this here, but some of those options could have been added under the app/models/user.rb file. We will touch back on OmniAuth later in part five.

Also, when you do not generate the views, Devise handles the default views that we saw for both sign up and sign in. We will be generating and altering those views in part three.

Summary

Today's post kicked off the Devise series with a basic overview of getting Devise up and running with Rails 7.

In the next part, we will tackle using Redis for our session store instead of the default cookie store.

Resources and further reading

Photo credit: halacious

Personal image

Dennis O'Keeffe

@dennisokeeffe92
  • Melbourne, Australia

Hi, I am a professional Software Engineer. Formerly of Culture Amp, UsabilityHub, Present Company and NightGuru.
I am currently working on workingoutloud.dev, Den Dribbles and LandPad .

1,200+ PEOPLE ALREADY JOINED ❤️️

Get fresh posts + news direct to your inbox.

No spam. We only send you relevant content.