DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Kanani Nirav
Kanani Nirav

Posted on

Form validations in Ruby On Rails Application.

In this article, we will learn how to manage server-side and client-side form validations according to our requirements and how we manage this at the application level.

Recently I have worked on form-validation systems in a couple of modern Rails apps, and I learned a few things along the way I would like to share.

Example and source code

I prepared a demo project here. It’s a Rails 5.2 application with a scaffold generated for managing users. A user has 2 attributes: name and email. The validations are:

  • Both name and email are required: to exercise client-side validations.

  • The email has to be unique, to exercise server-side validations.

Server-side validations with Rails

I love Rails validations. They are a powerful mechanism to capture your domain model validation rules, which are essential components of any app. For our example, we can capture the model constraints with something like this:

class User < ApplicationRecord
  validates :name, :email, presence: true
  validates :email, uniqueness: true
end
Enter fullscreen mode Exit fullscreen mode

A common Rails pattern for dealing with form errors is re-rendering the form with the invalid model carrying the errors to inform about them:

class UsersController < ApplicationController
  ...
  def create
    @user = User.new(user_params)
    if @user.save
      redirect_to @user, notice: 'User was successfully created.'
    else
      render :new
    end
  end

  def update
    if @user.update(user_params)
      redirect_to @user, notice: 'User was successfully updated.'
    else
      render :edit
    end
  end
  ...
end
Enter fullscreen mode Exit fullscreen mode

If you are going to use this approach there is a problem with it how we can show errors next to fields.

For dealing with the problem, you can customize ActionView::Base.field_error_proc which is a block of code that Rails uses to render fields with errors. By default, it will wrap them in a div.field_with_errors tag. You can configure it to render the same structure as client-side validations. In our example:

  1. Invalid fields are marked with a .invalid class

  2. Information about the error is shown in a p.error element next to the invalid field.

# Place this code in a initializer. 
# E.g: config/initializers/form_errors.rb
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance_tag|
  fragment = Nokogiri::HTML.fragment(html_tag)
  field = fragment.at('input,select,textarea')

  html = if field
           field['class'] = "#{field['class']} invalid"
           html = <<-HTML
              #{fragment&.to_s}
              <p class="error">#{instance_tag&.error_message&.first}</p>
           HTML
           html
         else
           html_tag
         end

  html.html_safe
end

Enter fullscreen mode Exit fullscreen mode

CSS β€” You can customize it according to your requirements.

# app/assets/stylesheets/application.css

.field p{
  margin-top: 0;
}

.error{
  color: red;
}

.invalid{
  border: 1px solid red;
}
Enter fullscreen mode Exit fullscreen mode

The new form validations look like this:

Image description

we will have a form that validates duplicated emails consistently with our system.

Image description

What I love about this approach is that you don’t need to do any extra work to show model errors in your forms. Just add model validations.

Client side validations with HTML 5

Form validations are captured in the HTML markup. You can read a nice reference here. For our purposes, we will modify the generated scaffold form to use them:

<%= form.text_field :name, required: true %>
...
<%= form.email_field :email, required: true %>
Enter fullscreen mode Exit fullscreen mode

With this in place, the browser won’t allow submitting invalid data, and it will show an error message based on the kind of validation.

Image description

This works but you probably won’t love how it looks, and you can’t style it at all.

I like server-side validation because it is not dependent on the client machine or browser or OS.

Conclusions

The discussed approach works great because, with a little bit of infrastructure in place, it lets you express your form validations very succinctly while being robust and comprehensive:

  • Use HTML5 form validations when they cover the validation you need

  • Use model validations in your server. This is something you want to do nevertheless.

If this guide has been helpful to you and your team please share it with others!

Top comments (0)

πŸ—£ Want to join the conversation?

Β 
It's easy! Become a DEV member to follow this post, comment, and more.