Recipe: Detecting Required Fields in Rails

It's a familiar problem. You're creating a form and you want to mark certain fields as required. You'd rather not hard-code which fields are required, because this might change over time. Plus, you've already got validations in your model that check for the presence of required fields, and you'd really rather not duplicate any of that logic. So, how can you tell whether a field associated with an ActiveRecord model is required?

The Problem

Let's assume that we have a model called Author, with required fields of first_name and last_name. The model looks like this:

   class Author < ActiveRecord::Base

      validates_presence_of :first_name
      validates_presence_of :last_name


The validations ensure that the first_name and last_name attributes of the model will have values. The bottom line is that the model has information about which fields are required. We need to be able to interrogate the model to determine if a field is required.

The Solution

After a little bit of research, it turns out that ActiveRecord has a validators_on method. Let's fire up the Rails console and see how it works:

      console>  Author.validators_on(:first_name)
      => [#<ActiveModel::Validations::PresenceValidator:0x45c4770 
      @attributes=[:first_name, :last_name], @options={}>]

OK, that gives us an array of validations for the specified field, where each validation is an instance of some type of validation class. That's somewhat useful, but we can do better.

      console> Author.validators_on(:first_name).map(&:class)
      => [ActiveModel::Validations::PresenceValidator]

That's even better. Now we have an array of classes, where each element is the class of a validator that has been placed on the specified attribute. The "&:class" argument to the map method causes the class method to be executed for each element in the array.

Now that we know how to get a list of the validations that are on a particular field, we can write a method that will return TRUE or FALSE based on whether a field is required. I'm going to throw in one wrinkle, though. I'd like to be able to call the method using either a class or an instance of a class.

   def required?(obj, attr)
      target = (obj.class == Class) ? obj : obj.class

I can put this method in my application_helper.rb file for my Rails application. Then I can call it from a view in two ways:

      required?(Author, :first_name)

Or, assuming that the controller has passed an instance of the Author model to the view as @author:

      required?(@author, :first_name)

By the way, this call works just fine, as well:

      required?(@author, "first_name")

Now my view logic can easily check whether a field is required.

   <%= form_for(@author) do |f| %>
      <p><%= f.text_field :first_name %>
      <% if required?(@author, :first_name) %>*<% end %></p>


David Keener By Stefan Huska on Thursday, August 11, 2011 at 10:25 AM EST

Thanks! Nice solution.

David Keener By zuev.evgenii on Thursday, April 18, 2013 at 06:39 PM EST



should be:


David Keener By dkeener on Friday, April 19, 2013 at 05:03 AM EST

Argh. You're right. Thanks for the correction, Zuev. I'll make that change to the original blog entry shortly.

Jeez, this article has been read like 2000+ times since it was first posted, and you're the first person to point out that little flaw. Sigh.

David Keener By dkeener on Friday, April 19, 2013 at 05:06 AM EST


David Keener By Steven Nunez on Friday, July 12, 2013 at 01:50 AM EST

Great post! If you're using Rails 4 it's:


David Keener By dkeener on Monday, August 26, 2013 at 02:52 PM EST

Thanks for the great update, Steven. I like to make sure these articles stay relevant.

David Keener By Aschen on Friday, October 16, 2015 at 12:45 PM EST

Thanks you for the tips but unfortunately its won't work if you have conditional validation like that : validates :nature, presence: true, if: ->(obj){ obj.is_secondary? }

David Keener By dkeener on Tuesday, October 20, 2015 at 02:38 AM EST

That's true, Aschen. But then again, you've added a further complication on top of the original problem, which was solved quite succinctly.

Once you add conditional validations in to the mix, your conditions could be as complex as you want (or need) them to be. It's not really feasible for an external method to determine whether conditions are met or not...that requires too much knowledge of the inner workings of the class.

From a user experience perspective, I'd mark the field as required, and add text under the field detailing when the element is required. From a pragmatic perspective, you get to keep the original clean solution and you push the responsibility back on the user to meet the necessary requirements.

Not all things have to be handled in code.

David Keener By Hugo Hernani on Friday, March 11, 2016 at 05:52 PM EST

I have a similar solution for a similar problem. If one wants to have a list of attributes marked as required in a activerecord subclass, that is how he could do it: def required_attributes(obj) target = obj.class == Class ? obj : obj.class do |amv| amv.class == ActiveRecord::Validations::PresenceValidator end

Leave a Comment

Comments are moderated and will not appear on the site until reviewed.

(not displayed)