‘Iacta alea est’

Basic Form: Rails

To represent our basic form in Rails we need an ActiveModel object and a template. I’m foregoing persistence and leaving ActiveRecord out for now.

class EmailSubscription
  include ActiveModel::Model
  attr_accessor :email
  validates :email, 
    presence: true, 
    email: true

That last line email: true leans on the following custom validator:

class EmailValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
      record.errors.add attribute, (options[:message] || "is not an email")

In the controller we need to initialize a new object so that it can be used by the form in the template.

def new
  @form = EmailSubscription.new

And then the template is as follows:

<%= form_for @form, 
    as: :subscription, 
    url: email_subscriptions_path do |f| %>
  <div class="form-group">
    <%= f.label :email, "Email address" %>
    <%= f.email_field :email, 
        class: "form-control #{@form.errors[:email].any? ? "is-invalid" : nil}"
        'aria-describedby': "subscription_email_help" %>
    <% if @form.errors[:email].any? %>
      <%= content_tag(:div, @form.errors[:email].join("; "), class: "invalid-feedback") %>
    <% end %>
        class="form-text text-muted">
      We'll never share your email with anyone else.
    <%= f.submit "Submit", class: "btn btn-primary" %>
<% end %>

There are certainly some things we could do to clean it up. Perhaps extract some elements into a form builder, like the error class and message.

The help text is also something pretty standard, although optional, and has no in-built Rails convention. It is similar to the label in that the accessibility text is referenced creating an interrelationship between form-control and another element, something that is ripe for abstracting.

It feels then like a half-way house. Some things are provided in a particular fashion, and it’s up to you to do the rest. In the same vein, you are writing some of the HTML yourself while also leaning on HTML generating helpers.

Thursday 17th June 2021.