David Sulc wrote a nice article entitled, Self-marking required fields in Rails 3 that utilized a key element of Ryan Bates' Railscast on Validations in Rails 3. In Ryan's original solution, he creates a new helper method named mark_required
that uses the Rails validation reflection to determine if the model requires that the field to be present (via validates :presence => true
or validates_presence_of
). If the field is required, this helper method adds a '*', otherwise it does nothing. Using this helper method in your code, your code would look like:
<%= f.label :name %><%= mark_required(@user, :name) %>
<%= f.text_field :name %>
David improves upon this idea by enhancing the
ActionView::Helpers::FormBuilder
label helper instead of adding a new helper. This eliminates the need to add the extra call to the
mark_required
helper for every label, which can be easily forgotten. If the field is required, the enhanced
label
helper appends a "*" to the label text to indicate that the field is required. So now your code is back to the normal form of:
<%= f.label :name %>
<%= f.text_field :name %>
That's a nice improvement, but I thought it would be an even better design practice to simply give the label a
required
CSS class, and then allow the designer to be able to easily modify how required fields should be indicated. My version of
config/initializers/form_builder.rb
looks like:
class ActionView::Helpers::FormBuilder
alias :orig_label :label
# add a 'required' CSS class to the field label if the field is required
def label(method, content_or_options = nil, options = nil, &block)
if content_or_options && content_or_options.class == Hash
options = content_or_options
else
content = content_or_options
end
if object.class.validators_on(method).map(&:class).include? ActiveModel::Validations::PresenceValidator
if options.class != Hash
options = {:class => "required"}
else
options[:class] = ((options[:class] || "") + " required").split(" ").uniq.join(" ")
end
end
self.orig_label(method, content, options || {}, &block)
end
end
With this revised version in place, all labels of required fields are given a
required
CSS class. If you want to indicate required fields with an asterisk after the label, you can do that by adding this CSS rule to your stylesheet,
/* add required field asterisk */
label.required:after {
content: " *";
}
However, by extracting the method of indicating that the field is required from being hard-coded in the helper to instead using a CSS class, anything you can do with CSS is open to you and can be quickly and easily modified without updating the helper code. You can change colors, fonts, borders, add images before or after, you could even use the dreaded
text-decoration:blink
. The options are nearly endless.
Update for Rails 4!
Thanks to the input from
alex_m and
Dan in the comments below, the follow revised version should work for Rails 4 (with ActiveAdmin):
class ActionView::Helpers::FormBuilder
alias :orig_label :label
# add a 'required' CSS class to the field label if the field is required
def label(method, content_or_options = nil, options = nil, &block)
if content_or_options && content_or_options.class == Hash
options = content_or_options
else
content = content_or_options
end
if object.class.respond_to?(:validators_on) &&
object.class.validators_on(method).map(&:class).include?(ActiveRecord::Validations::PresenceValidator)
if options.class != Hash
options = {:class => "required"}
else
options[:class] = ((options[:class] || "") + " required").split(" ").uniq.join(" ")
end
end
self.orig_label(method, content, options || {}, &block)
end
end
Thanks again
alex_m and
Dan!