Adding Sign Up to the Rails 8 Authentication Generator
This article spurned from writing about the new Rails 8 Authentication Generator in my Build A SaaS App in Ruby on Rails 8 book, and I wanted to share this small tip from the chapter on Users and Authentication.
Within the book, I set up a Rails 8 application with authentication using the bin/rails generate authentication
command. This command creates a User model, a Sessions controller, and a few views to get you started. However, it does not include a Sign-up process at all.
In this quick article, we will add a Sign-Up form to the application.
Prerequisites
Before we start, ensure you have the Rails 8 application set up with the authentication generator.
rails new myapp --maincd myappbin/rails generate authenticationbin/rails db:migrate
Adding Sign Up
To add a Sign-Up form, we will need to add a few things:
- A route to the Sign Up form
- A controller action to render the Sign-Up form
- A view to display the Sign Up form
- A controller action to handle the form submission
Route
In the config/routes.rb
file, add a route to the Sign Up form in addition to the routes created by the authentication generator:
Rails.application.routes.draw do resource :session resource :registration, only: %i[new create] resources :passwords, param: :tokenend
Controller
Create a new controller called RegistrationsController
:
class RegistrationsController < ApplicationController allow_unauthenticated_access
def new @user = User.new end
def create @user = User.new(user_params) if @user.save start_new_session_for @user redirect_to root_path, notice: 'Successfully signed up!' else render :new end end
private
def user_params params.require(:user).permit(:email_address, :password, :password_confirmation) endend
It’s pretty standard stuff here. First, allow_unauthenticated_access
is a method that allows unauthenticated access to the new
and create
actions. Otherwise, we could use this controller with a valid session. The only other thing that is not standard Rails controller CRUD is the start_new_session_for @user
, which allows the app to be signed in (add session record, secure cookie, etc.) after the user is created.
View
Create a new view file called new.html.erb
in the app/views/registrations
directory (view assumes Tailwind was added and has some classes):
<div class="mx-auto md:w-2/3 w-full"> <% if alert = flash[:alert] %> <p class="py-2 px-3 bg-red-50 mb-5 text-red-500 font-medium rounded-lg inline-block" id="alert"><%= alert %></p> <% end %>
<% if notice = flash[:notice] %> <p class="py-2 px-3 bg-green-50 mb-5 text-green-500 font-medium rounded-lg inline-block" id="notice"><%= notice %></p> <% end %>
<h1 class="font-bold text-4xl">Sign up</h1>
<%= form_with model: @user, url: registration_url, class: "contents" do |form| %> <div class="my-5"> <%= form.email_field :email_address, required: true, autofocus: true, autocomplete: "username", placeholder: "Enter your email address", value: params[:email_address], class: "block shadow rounded-md border border-gray-400 outline-none px-3 py-2 mt-2 w-full" %> </div>
<div class="my-5"> <%= form.password_field :password, required: true, autocomplete: "current-password", placeholder: "Enter your password", maxlength: 72, class: "block shadow rounded-md border border-gray-400 outline-none px-3 py-2 mt-2 w-full" %> </div>
<div class="my-5"> <%= form.password_field :password_confirmation, required: true, autocomplete: "current-password", placeholder: "Confirm your password", maxlength: 72, class: "block shadow rounded-md border border-gray-400 outline-none px-3 py-2 mt-2 w-full" %> </div>
<div class="col-span-6 sm:flex sm:items-center sm:gap-4"> <div class="inline"> <%= form.submit "Sign up", class: "rounded-lg py-3 px-5 bg-blue-600 text-white inline-block font-medium cursor-pointer" %> </div>
<div class="mt-4 text-sm text-gray-500 sm:mt-0"> <%= link_to "Forgot password?", new_password_path, class: "text-gray-700 underline" %> </div> </div> <% end %></div>
Form Submission
If you were to try to submit the form now, it would work, but redirect to the registration form as there is no root path or authenticated path to test this all out on. Let’s create a quick controller and route to handle this:
class HomeController < ApplicationController def index render plain: "Welcome to the app!" endend
Rails.application.routes.draw do get 'home/index' root to: 'home#index' resource :session resource :registration, only: %i[new create] resources :passwords, param: :tokenend
If you visit the root path of your application, you should see the Sign-Up form. You can fill it out and submit it to create a new user. Upon successful creation, you should be redirected to the root path with the message “Welcome to the app!”
Bonus Idea
Usually, when building an app, there is a different layout when you are logged in than when you are on one of the “authentication adjacent” pages. You can add a method to the ApplicationController
to determine if the user is authenticated or not:
class ApplicationController < ActionController::Base before_action :set_layout
def set_layout @layout = user_signed_in? ? 'application' : 'authentication' endend
Then, in your app/views/layouts
directory, create two layout files: application.html.erb
and authentication.html.erb
. In the application.html.erb
file, you can add a navigation bar, footer, etc. You can add a different navigation bar, footer, etc., in the authentication.html.erb
file.