Easy Peasy Form Validation Errors with Rails Turbo Frames (modals)

Rmag Breaking News

This article was originally published on Rails Designer

Form Validations (or officially Active Record Validations) are a fundamental feature of the Rails framework since its very beginning.

Throughout this post I will continue using Form Validations, as I not only use them with Active Record objects (eg. Model), but (more often) with Form Objects (eg. SignupForm).

They ensure that only valid data is saved to the database, enforcing rules and constraints on model attributes to maintain data integrity and, most important to me, improve user experience.

I use Form Validations quite a lot, as it’s a super easy way to provide my app’s users with feedback about what’s incorrect about the data they submitted.

As a little side-note: I mostly use Form Validations for UX reasons when submitting forms, the data integrity is better handled on the database level.

Quick Primer on Form Validations

Rails comes with common built-in validators, such as presence, uniqueness, format, length, and many others.

class Comment < ApplicationRecord
belongs_to :post

validates :body, presence: true, length: { minimum: 10 }
end

When you try to save a record, like this Comment without a body, Rails returns an ActiveModel::Errors object to hold errors related to validation failures. In your view you can display them like so:

<% if @comment.errors.any? %>
<⁠% @comment.errors.full_messages.each do |message| %>

<%= message %>
<⁠% end %>

<% end %>

But when you have a form in a modal or slide-over, you notice that suddenly your app breaks when validation errors appear.

How to Show Form Validations in a Turbo Frame

So let’s see how to get this working with turbo-frames.

The comments form is shown in a modal like. It’s display after clicking a link like this link_to “Comment”, new_comment_path, data: {turbo_frame: “modal”}.

# app/views/comments/new.html.erb
<%= ModalComponent.new %>
<⁠%= component “comments/form”, label: @comment %>

<% end %>

(it’s using the Rails Designer Component).

The controller is as vanilla-Rails as it gets. Just take note of status: :unprocessable_entity part. This sends a 422 status code to the browser, that Turbo requires/expects to be able to replace the content with the response

# app/controllers/comments_controller.rb

def create
@comment = Comment.new(comment_params)

respond_to do |format|
if @comment.save
flash.now[:success] = Created

format.turbo_stream
format.html { redirect_to comments_path, notice: “Created” }
else
flash.now[:success] = “Error”

format.turbo_stream { render :new, status: :unprocessable_entity }
format.html { render :new, status: :unprocessable_entity }
end
end
end

Here the block, for both the html-format and the turbo_stream-format, are the same. For HTML responses it uses the new.html.erb view template. So now create a app/views/comments/new.turbo_stream.html turbo-stream template and you are off to the races.

# app/views/comments/new.turbo_stream.html
<%= turbo_stream.replace “modal” do %>
<⁠%= ModalComponent.new %>

<%= component “comments/form”, label: @comment %>
<% end %>
<⁠% end %>

You notice that the content is almost the same as the app/views/comments/new.html.erb view template. I’m fine with this little duplication. But that is all that is needed to display Form Validations in your turbo-frame Modals and Slide-overs.

Leave a Reply

Your email address will not be published. Required fields are marked *