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

> In part one of this six part series on Devise and Ruby on Rails, we demonstrate setting up Devise for Rails 7 with a basic sign up and login flow.

- Canonical: https://dennisokeeffe.com/blog/2022-03-07-part-1-setting-up-devise-with-rails-7
- Published: 2022-03-07
- Updated: 2022-03-07
- Tags: ruby, ruby-on-rails, devise

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](https://github.com/okeeffed/demo-rails-7-with-devise-series)

## Prerequisites

1. Basic familiarity with setting up a [new Rails project](https://guides.rubyonrails.org/getting_started.html).

## Getting started

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

```s
# 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`:

```s
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:

```rb
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:

```rb
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:

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

## Updating our view

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

```html
<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:

```s
# 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](https://cdn.dennisokeeffe.com/assets/2022-03-07-part-1-setting-up-devise-with-rails-7/1-sign-in.webp)

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

![Sign up](https://cdn.dennisokeeffe.com/assets/2022-03-07-part-1-setting-up-devise-with-rails-7/2-sign-up.webp)

## 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](https://cdn.dennisokeeffe.com/assets/2022-03-07-part-1-setting-up-devise-with-rails-7/3-authenticated.webp)

## 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:

```rb
# 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](https://github.com/heartcombo/devise).

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

- [Rails getting started](https://guides.rubyonrails.org/getting_started.html)
- [Source code](https://github.com/okeeffed/demo-rails-7-with-devise-series)
- [Devise on GitHub](https://github.com/heartcombo/devise)
- [Series: Devise with Ruby on Rails 7](https://blog.dennisokeeffe.com/blog/series/devise-with-ruby-on-rails-7)

_Photo credit: [`halacious`](https://unsplash.com/@halacious)_
