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 (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"}
.
# app/views/comments/new.html.erb
<%= ModalComponent.new %>
<%= component "comments/form", comment: @comment %>
<% end %>
(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
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 %>
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)