Devise Part 1: Setting Up Devise With Rails 7 And React
Published: Mar 7, 2022
Last updated: Mar 7, 2022
This post will cover the first of six parts of the series on Devise and Ruby on Rails.
The series will cover the following:
- Setting up a basic sign up and login flow with Devise.
- Using Redis sessions instead of cookies.
- Adding Tailwind to our project to beautify the sign-up flow.
- Authorizing separate frontends to use our Rails API.
- Setting up Devise with Omniauth to our project to sign in with GitHub OAuth.
- Adding in Recaptcha to our project to protect against spam.
Source code can be found here
Prerequisites
- 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
Select Sign up
to redirect to our sign up route http://localhost:3000/users/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
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
Devise Part 1: Setting Up Devise With Rails 7 And React
Introduction