Instructions Plugin for Rails 3

Introduction

Instructions is a form builder plugin for Ruby on Rails 3 that displays model errors and hints for form fields next to those fields.

The plugin renders instructions for fields when the fields don’t have errors, and renders model errors for fields when they do have errors.

It wraps labels for fields with errors in a div that has a unique HTML ID and class names that provide easy control over styling, as well as selecting elements for web testing frameworks like Selenium and context-scraping tools.

A field with many error messages is represented as a comma-separated list. For Example: Name can't be blank, is not a number

The rendering of the field and the hints and error messages can be piped through procs for further formatting. These procs can be configured globally, as well as specified directly in markup on a field-by-field basis. Global configuration is done with a Rails initializer.

How it Plugs in to Rails

During initialization, the plugin replaces the ActionView::Base.field_error_proc with the plugin’s code (found in field_error.rb) and mixes in the instructions helper into the existing FormHelper. See lib/instructions/core_ext/action_view.ext for details.

Installation

The Instructions plugin is a Ruby Gem hosted at rubygems.org.

Install the gem using:

gem install instructions

Configurable Formatting of Field Names, Error Messages, and Instructions

Field names and instructions and error message formatting can be controlled and customized using configurable interceptors.

There are three contexts where the plugin can produce different results. In all three cases, these results are configurable using Proc objects that can provided using a Rails initializer:

Symbol Conditions
:new The initial rendering of a new action when a field’s hint is rendered
:valid The rendering for an attribute that has no validation errors after a post
:invalid The rendering for an attribute that does have validation errors after a post

In each case, the attribute name formatting and the instructions formatting can be intercepted and replaced.

The following code is an example of a Rails initializer (in the config/initializers directory of your rails app).

NOTE: The filename of the initializer is instructions.rb, but the filename isn’t significant. As long as the initializer is in the initializer directory.

upcase_proc = Proc.new { |text| text.upcase }
downcase_proc = Proc.new { |text| text.downcase }
empty_proc = Proc.new { "" }</code>

<code>Instructions.configure do |config|
  config.format_attribute_name :new, &downcase_proc
  config.format_instructions :new, &downcase_proc</code>
  
<code>  config.format_attribute_name :valid, &downcase_proc
  config.format_instructions :valid, &empty_proc</code>
  
<code>  config.format_attribute_name :invalid, &downcase_proc
  config.format_instructions :invalid, &downcase_proc</code>
  
<code>  config.message_joiner { |messages| messages.join ', ' }
end

Note also that you can configure a proc that controls how a list of messages are joined.

The configuration code above:

  • Converts the attribute name and the instructions to lower case during the initial get of an input form for a “new” action
  • Converts the attribute name to lower case when rendering the instructions for a field for an attribute that has a value and has no validation errors. The instructions, in this case, are not rendered at all as they are replaced with an empty string.
  • Converts the attribute name and error message to lower case when rendering the instructions for a field for an attribute that has a value and has validation errors.
  • Joins all error messages using a comma followed by a space.

A Note on Attribute Name Formatting

Attribute names are humanized using model.class.human_attribute_name(attribute_name) before being passed to the tag helpers.

Example

The example demonstrates the use of Field Instructions with a label and a textbox. The example model is a Person and the model attribute is Name.

The name attribute has a validates_presence_of constraint.

The ERB code for the label, text box, and instructions helper is:

<%= form.label(:name, "Name") %>
<%= form.text_field(:name) %>
<%= form.instructions(:name, "can't be blank") %>

The HTML rendering for this is:

<label for="project_name">Name</label>
<input id="project_name" name="project[name]" size="30" type="text" />
<div id="project_name_instructions" data-for="project_name" class="instructions">name can't be blank</div>

When the project_name input is posted with a blank value, the instructions div is replaced with an error message div that contains any model errors for the project.name attribute:

<div id="project_name_error_message" data-for="project_name" class="instructions invalid">name can't be blank</div>

Example App

See https://github.com/sbellware/instructions-example for a (very) basic example of a Rails 3 app with Instructions.

Using Symbols and i18n Errors to Render Hints

The instructions helper can be invoked with a symbol (eg: :blank) rather than passing instructions as text. This will use the error messages defined in Rails’ i18n as hints. In order to use this, the default error message strings have to be changed to allow them to be used both as hints and as error messages.

See extras/hint_errors.en.yml for examples. This file can be copied into your application’s config/locals if you prefer to use this technique.

Some Examples

Render the i18n :blank error message as a hint:

<%= form.instructions(:name, :blank) %>

Render the i18n :blank and :too_short error messages as a hint:

<%= form.instructions(:name, [:blank, => 2]) %>

Note that in the above example, the minimum length of the field must be specified since the :too_short string requires an interpolation argument to be provided. The definition of the :too_short string is hint_errors.en.yml is:

too_long: "can't be more than %{count} characters"

Rails Defaults Changed by the Plugin

The default rails rendering of the HTML when the form is posted with a blank value in the name textbox is:

<div class="field_with_errors"><label for="project_name">Name</label></div>
<div class="field_with_errors"><input id="project_name" name="project[name]" size="30" type="text" value="" /></div>

Using the Instructions plugin, the rendering of the HTML when the form is posted with a blank value in the name textbox is:

<div class="field_with_errors_label"><label for="project_name">Name</label></div>
<div class="field_with_errors"><input id="project_name" name="thing[name]" size="30" type="text" value=""></div>
<div id="project_name_error_message" data-for="project_name" class="instructions invalid">name can't be blank</div>

CSS Classes and HTML Markup

Name Attribute Type Notes
instructions Class Applied to the div that contains the instructions
valid Class Applied to the div that contains the instructions for fields with valid data after the form is posted. This class is always rendered together with the “instructions” class. The order of precedence of the class renderings is instructions first, followed by valid second, allowing styling for valid instructions to override the general instructions styling. The HTML rendering for the class attribute for the span is: class="instructions valid"
invalid Class Applied to the div that contains error messages after the form is posted
model_attribute_instructions Id A unique ID applied to the div that contains the instructions for the field, where {model} is the name of the ActiveModel object and {attribute} is the name of the attribute that has the error. Example: project_name_instructions
model_attribute_error_message Id A unique ID applied to the div that contains the error messages for the field, where {model} is the name of the ActiveModel object and {attribute} is the name of the attribute that has the error. Example: project_name_error_message
field_with_errors Class Applied to a div that wraps the HTML element that represents the model field that has errors.
field_with_errors_label Class Applied to a div that wraps any HTML label for the field with errors.