{"id":759,"date":"2011-06-11T15:56:00","date_gmt":"2011-06-11T15:56:00","guid":{"rendered":"https:\/\/www.keenertech.com\/?p=759"},"modified":"2011-06-11T15:56:00","modified_gmt":"2011-06-11T15:56:00","slug":"the-empty-string-code-smell-in-rails","status":"publish","type":"post","link":"https:\/\/staging.keenertech.com\/?p=759","title":{"rendered":"The Empty String Code Smell in Rails"},"content":{"rendered":"\n<p>Sometimes you look at some source code and it just doesn&#8217;t look right. The code might seem inordinately complex for the simple task being accomplished. Or the developer might be performing certain actions repeatedly, such as checking variables for nil values. This is what is known as a&nbsp;<em>code smell.<\/em>.<\/p>\n\n\n\n<p>Code smells should be corrected at the earliest possible opportunity. In this article, I&#8217;ll talk about some real-world coding issues that my friend, Robb Kidd, and I recently encountered.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The Repetitive Value-Checking Code Smell<\/h3>\n\n\n\n<p>Here&#8217;s a code smell that I found in a Rails view:<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&lt;% if @item.summary.nil? || @item.summary == &#8221; %&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;p&gt;Not Defined&lt;\/p&gt;<br>&nbsp;&nbsp;&nbsp;&lt;% else %&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;p&gt;&lt;%= @item.summary %&gt;&lt;\/p&gt;<br>&nbsp;&nbsp;&nbsp;&lt;% end %&gt;<\/p>\n\n\n\n<p>This type of code was provided for every field associated with an &#8220;item.&#8221; Not good. Not surprising, though. This is a pretty common code smell from Ruby newbies.<\/p>\n\n\n\n<p>Here&#8217;s a slightly better modification:<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&lt;% if @item.summary.blank? %&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;p&gt;Not Defined&lt;\/p&gt;<br>&nbsp;&nbsp;&nbsp;&lt;% else %&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;p&gt;&lt;%= @item.summary %&gt;&lt;\/p&gt;<br>&nbsp;&nbsp;&nbsp;&lt;% end %&gt;<\/p>\n\n\n\n<p>The&nbsp;<em>blank?<\/em>&nbsp;method checks for both nil and empty strings in one method. It even works on arrays:<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;arr = []<br>&nbsp;&nbsp;&nbsp;arr.blank?<\/p>\n\n\n\n<p>If the array is empty, as it is in the code above, then&nbsp;<em>blank?<\/em>&nbsp;returns true.<\/p>\n\n\n\n<p>The&nbsp;<em>blank?<\/em>&nbsp;method is awfully convenient for these types of checks. It also has a companion method,&nbsp;<em>present?<\/em>, that does the inverse check, i.e. \u2014 it checks if a value is present (ensuring that the value is not blank).<\/p>\n\n\n\n<p>We can shorten the original code even further:<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&lt;p&gt;&lt;%= @item.summary.blank? ? &#8216;Not Defined&#8217; : @item.summary %&gt;&lt;\/p&gt;<\/p>\n\n\n\n<p>Now we&#8217;ve got the original code sample down to one line using what amounts to an inline if-statement. That&#8217;s pretty good.<\/p>\n\n\n\n<p>But we&#8217;re still repeating that if-statement for every field displayed. To DRY the code up even further, we could extract that statement into a helper method:<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;def format_text(txt)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;txt.blank? ? &#8216;Not Defined&#8217; : txt<br>&nbsp;&nbsp;&nbsp;end<\/p>\n\n\n\n<p>In the view, the code then becomes:<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&lt;%= format_text(@item.summary) %&gt;<\/p>\n\n\n\n<p>Now the view is simple. Just the way I like it.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The Empty String Code Smell<\/h3>\n\n\n\n<p>I still wasn&#8217;t happy though. You see, the developer had told me that the reason he needed to check for empty strings everywhere was because empty strings were being physically stored in the database.<\/p>\n\n\n\n<p>This was something that Robb Kidd and I began investigating immediately.<\/p>\n\n\n\n<p>To me, this code smell was far worse than the original view-related one that had triggered this deep dive into the codebase. I was appalled that empty strings were being stored in the database.<\/p>\n\n\n\n<p>This might not seem like a big deal to many Rails developers. But with the types of high-end enterprise systems that I typically build, high-quality data is vital. Relational databases represent empty fields as NULL. Once you start putting empty strings into database fields, you have compromised the usefulness of NULL to represent the absence of information. You&#8217;ve also doomed everybody who ever works with that database to check for both NULL&#8217;s and empty strings if they want to determine whether a valid value is present.<\/p>\n\n\n\n<p>You&#8217;ve stored a code smell in the database for all eternity. Not good.<\/p>\n\n\n\n<p>Even worse, the database may be an underlying component of a Rails application, but there&#8217;s nothing in an enterprise setting that ties it exclusively to the Rails application. If the Rails application is successful, then much of the application&#8217;s value derives from the integrity of the data that has been stored. Other applications, sometimes implemented in other languages, may be built on top of that database.<\/p>\n\n\n\n<p>By pushing a code smell into the database, we&#8217;re forcing all future developers, not just Rails developers, to deal with the compromised usefulness of NULL. We may very well hear this from some future Python developer, &#8220;Jeez. Those Rails dweebs were amateurs. This wouldn&#8217;t have happened if they&#8217;d used Django.&#8221;<\/p>\n\n\n\n<p>We should definitely deal with this problem. But first, how does it happen?<\/p>\n\n\n\n<p>The application allows users to enter data via forms. Upon submission, Rails collects all submitted values into the standard&nbsp;<em>params<\/em>&nbsp;hash that is made available to controllers. Any form field that is a text field or text area will be assigned the empty string as a value. the following controller code perpetuates the empty string into the database:<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;Item.create!(params[&#8216;item&#8217;])<\/p>\n\n\n\n<p>Whoa. So I can hear you asking: &#8220;So this is a Rails problem?&#8221;<\/p>\n\n\n\n<p>Yes. It is a Rails problem, and one that in my humble opinion should never have slipped through the cracks.<\/p>\n\n\n\n<p>But we still need to correct it in our application. So, Robb and I started researching possible solutions.<\/p>\n\n\n\n<p>The best solution we came across was from&nbsp;<a href=\"https:\/\/web.archive.org\/web\/20170417114059\/https:\/\/github.com\/henrik\">Henrik Nyh<\/a>, a Ruby developer in Stockholm, Sweden. He published an excellent code&nbsp;<a href=\"https:\/\/web.archive.org\/web\/20170417114059\/https:\/\/gist.github.com\/717764\">snippet<\/a>&nbsp;on GitHub&#8217;s gist sub-site. This is a site at&nbsp;<a href=\"https:\/\/web.archive.org\/web\/20170417114059\/http:\/\/gist.github.com\/\">gist.github.com<\/a>&nbsp;that allows developers to publish short snippets of code that solve problems.<\/p>\n\n\n\n<p>His code is a mix-in module that updates ActiveRecord&#8217;s write_attribute method to properly handle empty strings.<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;module NullifyBlankAttributes<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def write_attribute(attr_name, value)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new_value = value.presence<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super(attr_name, new_value)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br><br>&nbsp;&nbsp;&nbsp;end<\/p>\n\n\n\n<p>Note the use of the&nbsp;<em>presence<\/em>&nbsp;method, which takes an argument and returns either the argument itself or nil if the argument was blank.<\/p>\n\n\n\n<p>Now what? What do we do with the module?<\/p>\n\n\n\n<p>First, drop the module in the&nbsp;<em>lib<\/em>&nbsp;directory of the Rails application. Second, create an initialization file in the&nbsp;<em>config\/initializers<\/em>&nbsp;directory of the Rails application. Let&#8217;s call it&nbsp;<em>active_record_fixes.rb<\/em>. The contents of the file will be:<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;class ActiveRecord::Base<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;include NullifyBlankAttributes<br>&nbsp;&nbsp;&nbsp;end<\/p>\n\n\n\n<p>We have just monkey-patched Rails to correct our empty string code smell.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Conclusions<\/h3>\n\n\n\n<p>We discovered a code smell in our view code that masked a more pernicous underlying code smell. We got rid of both code smells with the help of a developer from Sweden that we&#8217;ve never met.<\/p>\n\n\n\n<p>There are a few lessons to be learned from all this. First, code smells increase the maintenance profile of your application over time, making it more difficult to add new features and maintain existing ones. Code smells are an indication of a coding problem, and should be fixed as soon as feasible, even if the code is functionally working just fine.<\/p>\n\n\n\n<p>Second, when you have a problem, don&#8217;t re-invent the wheel. We&#8217;re an international coding community. Somebody may very well have solved the problem already. Spend some time researching using Google in case somebody&#8217;s already developed a solution. In this case, Henrik solved the problem nicely a few years ago.<\/p>\n\n\n\n<p>Finally, give back to the community. If you solve a problem that might reasonably impact others in the community, post a solution. Write a blog entry (as I have done). Or post a code snippet on&nbsp;<em>gist.github.com<\/em>, or answer a question posed on sites like&nbsp;<a href=\"https:\/\/web.archive.org\/web\/20170417114059\/http:\/\/www.stackoverflow.com\/\">Stack Overflow<\/a>. Coding is hard enough as it is. Let&#8217;s share some solutions to make it easier on all of us.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Reception<\/h3>\n\n\n\n<p>This article was well received and generated a number of excellent comments. Since I don&#8217;t have a way of porting them in smoothly from the old website, I&#8217;ve included snapshots of the comments&#8230;<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"880\" src=\"https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/empty_comment_1-1024x880.png\" alt=\"First Batch of comments...\" class=\"wp-image-760\" srcset=\"https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/empty_comment_1-1024x880.png 1024w, https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/empty_comment_1-300x258.png 300w, https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/empty_comment_1-768x660.png 768w, https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/empty_comment_1.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=\"999\" height=\"1024\" src=\"https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/empty_comment_2-999x1024.png\" alt=\"Second Batch of comments...\" class=\"wp-image-761\" srcset=\"https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/empty_comment_2-999x1024.png 999w, https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/empty_comment_2-293x300.png 293w, https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/empty_comment_2-768x787.png 768w, https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/empty_comment_2.png 1296w\" sizes=\"auto, (max-width: 999px) 100vw, 999px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"981\" src=\"https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/empty_comment_3-1024x981.png\" alt=\"Third Batch of comments...\" class=\"wp-image-762\" srcset=\"https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/empty_comment_3-1024x981.png 1024w, https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/empty_comment_3-300x287.png 300w, https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/empty_comment_3-768x736.png 768w, https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/empty_comment_3.png 1290w\" 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=\"1024\" height=\"569\" src=\"https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/empty_comment_4-1024x569.png\" alt=\"Fourth Batch of comments...\" class=\"wp-image-763\" srcset=\"https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/empty_comment_4-1024x569.png 1024w, https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/empty_comment_4-300x167.png 300w, https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/empty_comment_4-768x427.png 768w, https:\/\/staging.keenertech.com\/wp-content\/uploads\/2026\/05\/empty_comment_4.png 1288w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>Sometimes you look at some source code and it just doesn&#8217;t look right. The code might seem inordinately<\/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-759","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\/759","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=759"}],"version-history":[{"count":0,"href":"https:\/\/staging.keenertech.com\/index.php?rest_route=\/wp\/v2\/posts\/759\/revisions"}],"wp:attachment":[{"href":"https:\/\/staging.keenertech.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=759"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/staging.keenertech.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=759"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/staging.keenertech.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=759"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}