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:migrateAdding 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: :tokenendController
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) endendIt’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!" endendRails.application.routes.draw do get 'home/index' root to: 'home#index' resource :session resource :registration, only: %i[new create] resources :passwords, param: :tokenendIf 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' endendThen, 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.