Easy Peasy Form Validation Errors with Rails Turbo Frames (modals)
Tags: rails, hotwire
Published: 2024-04-04 18:00:00

This article was originally published on [Rails Designer](https://railsdesigner.com/turbo-frame-form-validations/)

---

Form Validations (or officially [Active Record Validations](https://guides.rubyonrails.org/active_record_validations.html)) 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.

```ruby
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:

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

But when you have a form in a [modal](https://railsdesigner.com/components/modals/) or [slide-over](https://railsdesigner.com/components/slide-overs/) (that both use `turbo-frame`s), 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"}`.

```ruby
# app/views/comments/new.html.erb
<⁠%= ModalComponent.new %>
  <⁠%= component "comments/form", comment: @comment %>
<⁠% end %>
```

(this is using the [Rails Designer ModalComponent](https://railsdesigner.com/components/modals/)).

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

```ruby
# 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.

```ruby
# app/views/comments/new.turbo_stream.html
<⁠%= turbo_stream.replace "modal" do %>
  <⁠%= ModalComponent.new %>
    <⁠%= component "comments/form", comment: @comment %>
  <⁠% end %>
<⁠% end %>
```

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.