How to set up devise for rails 7

Steve Condylios
3 min readApr 24, 2022

--

It’s easy to forget a step or two when setting up devise, so here’s a quick ‘how to’ setup devise. It’s not absolutely minimal, but it’s how I set things up for a new project. Here goes:

First, create a user model, resource or scaffold. For example:

rails g resource user first_name last_name admin last_seen_at time_zone

Add devise and letter_opener to Gemfile.rb:

gem "devise", github: "heartcombo/devise", ref: "f8d1ea90bc3"
gem "letter_opener", group: :development

Note: the rationale for cloning devise from GitHub is explained at the bottom of this article, but TL;DR it contains fixes for some rails 7 incompatibilities.

Bundle install:

bundle install

Run the devise install generator:

rails g devise:install

Add these to config/development.rb

# For devise
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
# For letter_opener
config.action_mailer.delivery_method = :letter_opener
config.action_mailer.perform_deliveries = true

In the same file, it can be useful to ensure errors are logged in development, so change that to true:

config.action_mailer.raise_delivery_errors = true

Add devise to the user model

rails g devise user

Go into the newly created migration file and uncomment the confirmable and trackable sections.

Go into app/models/user.rb and add :confirmable and :trackable to devise, like so:

class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable,
:confirmable, :trackable
end

If you prefer users to be ‘remembered’ for longer than 2 weeks, change this setting ( users may expect to stay signed in on devices they’ve signed in on, so setting to something large, e.g. 6.months or 1.year or similar may be desirable).

config.remember_for = 2.years

In the same file, change the default email to one from your application:

config.mailer_sender = 'no-reply@example.com'

Generate devise views (so you can edit them to your taste):

rails g devise:views

Migrate:

rake db:migrate

Add this above <%= yield %> in app/views/layouts/application.html.erb

<% if notice %>
<p class="alert alert-success"><%= notice %></p>
<% end %>
<% if alert %>
<p class="alert alert-danger"><%= alert %></p>
<% end %>

Note: since the notice is added to application.html.erb, it can be removed from individual show views, by removing <%= notice %> (if you keep that, the notice will appear twice, which is undesirable).

Try it out

Head to http://localhost:3000/users/sign_up and make a new user, you should receive an email which opens in the browser (via letter_opener). Great, it’s working!

Denying access!

Let’s test authorisation by creating two pages: a landing page which is accessible to anyone, and a dashboard which is accessible only after an account is created and the user has logged in:

rails g controller static_pages landing_page dashboard

Start the server and note that both pages are accessible:

http://localhost:3000/static_pages/landing_page

http://localhost:3000/static_pages/dashboard

In the application controller, add this

before_action :authenticate_user!

Now the two pages will redirect to a login screen. To make the landing_page accessible without login, go into the static_pages controller and add this:

skip_before_action :authenticate_user!, only: [:landing_page]

Set a root url in routes.rb by replacing the landing_page route with this:

root 'static_pages#landing_page'

Lastly, add sign in and sign out links just after <body> in app/views/application.html.erb like so:

<% if user_signed_in? %>
Logged in as <strong><%= current_user.email %></strong>.
<%= link_to 'Edit profile', edit_user_registration_path %> |
<%= link_to "Logout", destroy_user_session_path, data: { turbo_method: :delete } %>
<% else %>
<%= link_to "Sign up", new_user_registration_path %> |
<%= link_to "Login", new_user_session_path %>
<% end %>

Create a new user, login, log out, have a play around.

Under normal circumstances, this would be all that needs doing. However, rails 7 doesn’t play nice with devise, so there are a few extra steps.

Devise with Rails 7 and Turbo

At the time of writing, rails 7 and devise don’t play nice, on account of turbo. So we can turn turbo off in the devise views, explained excellently here (you can see the exact changes in this commit here).

Devise 4.8.1 (current on rubygems.org) will have some rails 7 bugs, so I prefer a newer version of devise which gets around those incompatibilities:

gem "devise", github: "heartcombo/devise", ref: "f8d1ea90bc3"

One last thing, depending on how you manage javascript in your rails app, you may have to open another terminal window and run ./bin/dev before starting your server to ensure javascript/turbo works.

Further resources

  • Devise ‘Getting Started’ docs (here).
  • Rails Girls guide to devise (here).
  • Devise youtube tutorial (here).
  • Letter_opener docs (here).
  • Devise with rails 7 (here, here, here).

--

--