DEV Community

Cover image for Easy Peasy Form Validation Errors with Rails Turbo Frames (modals)
Rails Designer
Rails Designer

Posted on • Edited on • Originally published at railsdesigner.com

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

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
Enter fullscreen mode Exit fullscreen mode

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 %>
Enter fullscreen mode Exit fullscreen mode

But when you have a form in a modal or slide-over (that both use turbo-frames), 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. It's displayed 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", comment: @comment %>
<% end %>
Enter fullscreen mode Exit fullscreen mode

(this is using the Rails Designer ModalComponent).

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
Enter fullscreen mode Exit fullscreen mode

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", comment: @comment %>
  <% end %>
<⁠% end %>
Enter fullscreen mode Exit fullscreen mode

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.

That is all that is needed to display Form Validations in your turbo-frame Modals and Slide-overs.

Top comments (0)