This post describes how to create a User registration functionality for a Rails 8 application that uses the default Rails 8 authentication framework.
In the routes file, add routes for the registration: new
and create
. Note:
the route is singular.
# config/routes.rb
resource :registration, only: [:new, :create]
Add a new RegistrationsController
in
app/controllers/registrations_controller.rb
with new
and create
actions.
# app/controllers/registrations_controller.rb
class RegistrationsController < ApplicationController
allow_unauthenticated_access only: [ :new, :create ]
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
flash.now[:alert] = "Something went wrong."
render :new, status: :unprocessable_entity
end
end
private
def user_params
params.expect(user: [:first_name, :last_name, :email_address, :password, :password_confirmation])
end
end
Create a new view in registrations/new.html.erb
with this content:
<%= form_with model: @user, url: registration_url do |form| %>
<%= render "shared/errors", object: @user %>
<div>
<%= form.label :first_name %>
<%= form.text_field :first_name,
required: true,
autofocus: true,
placeholder: "your first name" %>
</div>
<div>
<%= form.label :last_name%>
<%= form.text_field :last_name,
required: true,
placeholder: "your last name" %>
</div>
<div>
<%= form.label :email_address%>
<%= form.email_field :email_address,
required: true,
placeholder: "your email address" %>
</div>
<div>
<%= form.label :password, "New password" %>
<%= form.password_field :password,
required: true,
placeholder: "your new password",
maxlength: 72 %>
</div>
<div>
<%= form.label :password_confirmation %>
<%= form.password_field :password_confirmation,
required: true,
placeholder: "your password again",
maxlength: 72 %>
</div>
<%= form.submit "Sign up" %>
<% end %>
User Model
class User < ApplicationRecord
has_secure_password
has_many :sessions, dependent: :destroy
validates :first_name, presence: true
validates :last_name, presence: true
validates :email_address, presence: true, uniqueness: true
validates :password, presence: true
validates :password_confirmation, presence: true
validates_confirmation_of :password
normalizes :email_address, with: ->(e) { e.strip.downcase }
end
Errors partial app/views/shared/_errors.html.erb
<% if object.errors.any? %>
<section class="bg-orange-200 p-8 my-8 mx-auto">
<h2>
Your form could not be saved.
</h2>
<h3>
Please correct the following
<%= pluralize(object.errors.size, "error") %>:
</h3>
<ul>
<% object.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</section>
<% end %>
Styling the .field_with_errors
class in the main application.css
file:
/* app/assets/stylesheets/application.css */
div.field_with_errors > label {
color: red;
}
div.field_with_errors > :is(input, textarea, select) {
border: 2px solid red;
margin-bottom: 1rem;
}