{"id":751,"date":"2011-06-26T15:32:00","date_gmt":"2011-06-26T15:32:00","guid":{"rendered":"https:\/\/www.keenertech.com\/?p=751"},"modified":"2011-06-26T15:32:00","modified_gmt":"2011-06-26T15:32:00","slug":"recipe-detecting-required-fields-in-rails","status":"publish","type":"post","link":"https:\/\/staging.keenertech.com\/?p=751","title":{"rendered":"Recipe: Detecting Required Fields in Rails"},"content":{"rendered":"\n<p>It&#8217;s a familiar problem. You&#8217;re creating a form and you want to mark certain fields as required. You&#8217;d rather not hard-code which fields are required, because this might change over time. Plus, you&#8217;ve already got validations in your model that check for the presence of required fields, and you&#8217;d really rather not duplicate any of that logic. So, how can you tell whether a field associated with an ActiveRecord model is required?<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The Problem<\/h3>\n\n\n\n<p>Let&#8217;s assume that we have a model called Author, with required fields of first_name and last_name. The model looks like this:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">   class Author &lt; ActiveRecord::Base\n\n      validates_presence_of :first_name\n      validates_presence_of :last_name\n\n   end<\/pre>\n\n\n\n<p>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.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The Solution<\/h3>\n\n\n\n<p>After a little bit of research, it turns out that ActiveRecord has a validators_on method. Let&#8217;s fire up the Rails console and see how it works:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">      <strong>console&gt;<\/strong>  Author.validators_on(:first_name)\n      =&gt; [#&lt;ActiveModel::Validations::PresenceValidator:0x45c4770 \n      @attributes=[:first_name, :last_name], @options={}&gt;]<\/pre>\n\n\n\n<p>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&#8217;s somewhat useful, but we can do better.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">      <strong>console&gt;<\/strong> Author.validators_on(:first_name).map(&amp;:class)\n      =&gt; [ActiveModel::Validations::PresenceValidator]<\/pre>\n\n\n\n<p>That&#8217;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 &#8220;&amp;:class&#8221; argument to the map method causes the class method to be executed for each element in the array.<\/p>\n\n\n\n<p>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&#8217;m going to throw in one wrinkle, though. I&#8217;d like to be able to call the method using either a class or an instance of a class.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">   def required?(obj, attr)\n      target = (obj.class == Class) ? obj : obj.class\n      target.validators_on(attr).map(&amp;:class).include?(\n         ActiveModel::Validations::PresenceValidator)\n   end\n<\/pre>\n\n\n\n<p>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:<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;required?(Author, :first_name)<\/p>\n\n\n\n<p>Or, assuming that the controller has passed an instance of the Author model to the view as @author:<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;required?(@author, :first_name)<\/p>\n\n\n\n<p>By the way, this call works just fine, as well:<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;required?(@author, &#8220;first_name&#8221;)<\/p>\n\n\n\n<p>Now my view logic can easily check whether a field is required.<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&lt;%= form_for(@author) do |f| %&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;p&gt;&lt;%= f.text_field :first_name %&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;% if required?(@author, :first_name) %&gt;*&lt;% end %&gt;&lt;\/p&gt;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Reception<\/h3>\n\n\n\n<p>[May 5, 2026] This article was quite well received back in the day. Since I can&#8217;t easily port the comments from the old version of the KeenerTech.com website, I pulled some screenshots instead:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"891\" height=\"1024\" src=\"https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/comments_1-891x1024.png\" alt=\"First Batch of comments...\" class=\"wp-image-752\" srcset=\"https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/comments_1-891x1024.png 891w, https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/comments_1-261x300.png 261w, https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/comments_1-768x882.png 768w, https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/comments_1.png 1304w\" sizes=\"auto, (max-width: 891px) 100vw, 891px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"728\" src=\"https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/comments_2-1024x728.png\" alt=\"Second Batch of comments...\" class=\"wp-image-753\" srcset=\"https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/comments_2-1024x728.png 1024w, https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/comments_2-300x213.png 300w, https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/comments_2-768x546.png 768w, https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/comments_2.png 1292w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1019\" height=\"1024\" src=\"https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/comments_3-1019x1024.png\" alt=\"Third Batch of comments...\" class=\"wp-image-754\" srcset=\"https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/comments_3-1019x1024.png 1019w, https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/comments_3-300x300.png 300w, https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/comments_3-150x150.png 150w, https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/comments_3-768x772.png 768w, https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/comments_3.png 1296w\" sizes=\"auto, (max-width: 1019px) 100vw, 1019px\" \/><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>It&#8217;s a familiar problem. You&#8217;re creating a form and you want to mark certain fields as required. You&#8217;d<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[160,172],"class_list":["post-751","post","type-post","status-publish","format-standard","hentry","category-technology","tag-rails","tag-ruby"],"_links":{"self":[{"href":"https:\/\/staging.keenertech.com\/index.php?rest_route=\/wp\/v2\/posts\/751","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/staging.keenertech.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/staging.keenertech.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/staging.keenertech.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/staging.keenertech.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=751"}],"version-history":[{"count":0,"href":"https:\/\/staging.keenertech.com\/index.php?rest_route=\/wp\/v2\/posts\/751\/revisions"}],"wp:attachment":[{"href":"https:\/\/staging.keenertech.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=751"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/staging.keenertech.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=751"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/staging.keenertech.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=751"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}