Migrating Away from Devise Part 5: User Sign-up

Published: January 16, 2025
Part 5 of a multi-part series for moving away from devise to Rails' authentication generator
This is the fifth part of a multi-part series about moving from devise to the Rails generated authentication system

Next up is new user registration. This will use some of the functionality made in the previous step for sending a confirmation email. The app needs both an email and username (display name and what is used to sign in) as well as a password.

The routes look like this:

resource :registration, only: [:new, :create]

The controller is mostly a standard CRUD controller with only "new" and "create" actions with the addition of sending the confirmation email. The sign_up_ip on user which devise usually sets is also populated.

class RegistrationsController < ApplicationController
  rate_limit to: 10, within: 3.minutes, only: :create, with: lambda {
    redirect_to new_registration_path, alert: "Try again later."
  }

  def new
    @user = User.new
  end

  def create
    @user = User.new(sign_up_params)
    @user.sign_up_ip = request.remote_ip

    if @user.save
      UserMailer.confirmation_instructions(@user).deliver_later
      redirect_to new_registration_path,
                  notice: "We have sent an email with a confirmation link. Please click it to activate your account."
    else
      render :new, status: :unprocessable_entity
    end
  end

  private

  def sign_up_params
    params.expect(user: [:username, :email, :password, :password_confirmation])
  end
end

The custom devise view is moved to app/views/registrations/new.html.erb. The only change is where the form posts and any reference to resource, change to @user.

- <%= form_with model: resource, as: resource_name, url: registration_path do |f| %>
+ <%= form_with model: @user, url: registration_path do |f| %>

Any links referencing the old devise registration path is updated, and that should be it! For this app at least, that at least covers all the routes used, so if there's still a devise_for :users section in the routes file, that can be removed.

Moving on up to part six: Reimplementing trackable module and how tests work.