Cleaning up rails view logic using Draper

Rails makes it super easy to create database backed applications fast, but sometimes we get sloppy in all the hurry.

First iteration (quick and dirty)

Assume we have a simple blog application (yeah, original, I know) with a BlogPost model. The BlogPost model has three properties: title, content and author, all of which are strings. Our scaffolded index view looks like this:

<% @blog_posts.each do |blog_post| %>
  <tr>
    <td><%= blog_post.title %></td>
    <td><%= blog_post.content %></td>
    <td><%= blog_post.author %></td>
    ... other code to display in each line
  </tr>

We now want to display when the post was published, and our first stab at it looks like this:

    <td><%= blog_post.created_at %></td>

While this does satisfy the core requirement, the datetime format is rather verbose. In fact, we only want to show the date (not time) for the index page. Our first attempt at this looks like the following:

<% @blog_posts.each do |blog_post| %>
  <tr>
    ... previous lines
    <td><%= blog_post.created_at.strftime("%m.%b.%Y") %></td>
    ... other code to display in each line
  </tr>

We also want to show the published time when viewing an individual post, but this time we want to include the time (hours and minutes only).

    <p><%= blog_post.created_at.strftime("%m.%b.%Y %H:%M") %></p>

Now the timestamps are displayed just the way we want them.

Iteration 2: reducing view logic

The problem with the above approach is that we now have logic in our view. Not only does this clutter the view code, but if we want to use the same date format for blog posts elsewhere in the app, we have to duplicate this code everywhere.

Our first attempt to clean this up is to add a new method to the BlogPost model which we can then call instead of #created_at:

class BlogPost < ActiveRecord::Base
  def short_date
    created_at.strftime("%m.%b.%Y")
  end

  def long_date
    created_at.strftime("%m.%b.%Y %H:%M")
  end
end

Which allows us to change the index view to:

  <td><%= blog_post.short_date %></td>

and our show view to:

  <p><%= @blog_post.long_date %></p>

This looks much better.

Third iteration: remove presentation logic from model

While our views are certainly cleaner, we just added view specific logic to our model. The model should not be concerned about how to format data for particular views. So, where then do we put it? The answer is Decorators.

For this I will rely on one of my favourite gems, namely Draper.

We’ll create a new decorator, simply called BlogPostDecorator. This will be our place for view specific logic.

class BlogPostDecorator < Draper::Decorator
  delegate_all

  def short_date
    object.created_at.strftime("%m.%b.%Y")
  end

  def long_date
    object.created_at.strftime("%m.%b.%Y %H:%M")
  end
end

To make this available in the views, we must decorate the objects returned by the controller:

  def index
    @blog_posts = BlogPost.all.decorate
  end

  def show
    @blog_post = BlogPost.find(params[:id]).decorate
  end

Conclusion

We have met our view requirements with cleaner views and cleaner models by using decorators. I have merely shown you a glimpse of what Draper is capable of and I encourage you to head over to the Draper Github page and look through it.

If you want to play around with this, you can take a look at the source code for the BlogPost app.

Default ordering of records in Ember.js

It is easy to change the default ordering of records in Ember.js.

Make RSpec clean up Mongoid records

I am currently working on a pet project in Rails that uses Mongoid to connect as its Object-Document-Mapper (which is similar to what Active Record does for SQL databases).

I then ran into issue when I had an RSpec test case that verified that tested a method that called find_or_create_by. In other words, a record should be created if it did not exist, otherwise the existing record should be returned.

So my test case looked something like this:

it 'creates entry from auth hash' do
  auth_hash = {'info' => {'name' =>  'Samuel Vimes'} }
  expect {
    User.find_or_create_from_auth_hash(auth_hash)
  }.to change(User, :count).by(1)
end

This test was green the first time I ran it, but failed the second time. The reason was that the database was not being cleaned up in between test runs.

Database Cleaner by Ben Mabey to the rescue. I added this to the :test group of my Gemfile:

gem 'database_cleaner', :github => 'bmabey/database_cleaner'

And this to the configure block of my spec_helper:

# Cleanup the DB in between test runs
config.before(:suite) do
  DatabaseCleaner[:mongoid].strategy = :truncation
  DatabaseCleaner[:mongoid].clean_with(:truncation)
end

config.before(:each) do
  DatabaseCleaner.start
end

config.after(:each) do
  DatabaseCleaner.clean
end

And whoila! Now my test passes in every run.

Ruby Mixins

Mixins are the Ruby way to eliminate the need for multiple inheritance. In short, a class can “mixin” multiple modules, which in practice means that it gains either the instance or class methods defined in the mixed in module, depending on how it was mixed in.

This has some benefits. When a an objects method gets called, it is clear in what order the interpreter will search for that method (see a more detailed discussion), thereby avoiding the “Deadly diamond of death” problem.

Let’s look at some code to clarify this.

module A
  def stuff
    puts "Hi, I'm module A"
  end
end

module B
  def stuff
    puts "Hi, I'm module B"
  end

  def is_a?(_class)
    "B#is_a?"
  end
end

class First
 include A
 include B
end

class Second
  include B
  include A
end

class Third
  def stuff
    puts "Hi, I'm class Third"
  end

  include A
  include B
end

class ThirdChild < Third
end

First.new.stuff  # Hi, I'm module B
Second.new.stuff # Hi, I'm module A
Third.new.stuff  # Hi, I'm class Third
puts ThirdChild.new.is_a?(First) # B#is_a?

For the First instance we print out “Hi, I’m module B”, since module B was mixed in after module A. The reverse is true for the Second instance, module A was mixed in after module B, so we print out “Hi, I’m module A”. The Third class has its own method called stuff, and it has precedence over the mixed in methods.

Finally, the instance of ThirdChild returns the “B#is_a?” string when its is_a? method is called. It is easy to jump to the conclusion that it should call Object#is_a? and return false. However, it’s first ancestor, Third, has mixed in module B, and has therefore overridden the Object#is_a? method.

Mixins are a powerful tool, in particular to DRY up code. A common example of its benefits is to mixin the Comparable module and get several comparison methods by implementing a single method (<=>). But mixins should be used with care.

Whenever you mixin a module, you are increasing the complexity and surface of that object. Added complexity means that it is more likely to contain bugs. You also need to think hard about whether the mixin violates the single responsibility principle (and if so, is the violation worth the benefits?).

Asset pipeline gotcha: Trailing newlines

TL;DR; If Asset pipeline is configured according to production recommendations (config.assets.debug = false and config.assets.compress = true) then all the stylesheets from your manifest file will be concatenated without adding a newline between them. This may break your styling when you deploy to production.

I have been putting the finishing touches on the next version of Brand Regard for the last couple of weeks and have reached a stage where I wanted feedback from the non-programmers in the team. So I deployed the app to a staging environment. Imagine my surprise when the staging version did not look anything like what appeared when I ran the app locally.

After reviewing a lot of diffs, deployment configs etc. I managed to narrow it down to one line in the environments configuration. Namely,:

config.assets.debug = true

What this does is that it skips the Sprockets preprocessor and includes each file from the application.css manifest file, rather than combining them into a single file. After playing around with this a bit I finally found the real problem.

Many of the CSS files included in the manifest, did not end with a blank newline. But when the asset pipeline preprocessor combines them, it compresses all whitespace (and does not include any whitespace).

To illustrate why this is a problem, consider these two stylesheets:

.style1 { stuff; }

and

.style2 { otherstuff; }

If these files contain no trailing newlines, the combined stylesheet will (with compression turned on) look like this:

.style1{stuff;}.style2{otherstuff;}

But what you probably want is this:

.style1{stuff;}
.style2{otherstuff;}

So, to make sure that your websites looks the same regardless of the config.assets.debug setting, please add a trailing newline to each of your stylesheets.

Using Vim for Rails development

After I started working fulltime on a Rails application, most of my daily work takes place in a text editor. I decided that this was as good an oppurtunity as any to learn vim properly. I want to list a few useful things that I’ve recently learned.

In my discussions below I’ll often mention the <leader> character. <leader> is bound to \ by default, but your configuration may vary.

Multiple commands at once

You can run multiple commands at once by seperating them with a | (pipe) character. For instance:

:vsp | e somefile

this is equivalent to running

:vsp

followed by

:e somefile.

The power of plugins

I’ve used vim off and on for a long time, but have only needed the most basic functionality. But there is a wide selection of plugins available that really turn a promising editor into an awesome workbench.

Fugitive

According to its README file, Fugitive “may very well be the best Git wrapper of all time”. The commands that I’ve used the most are:

:Gdiff for a split-pane comparison of my copy vs. the copy in the repository.

:Gread which is equivalent to git checkout, except that it works on the vim buffer instead of reverting the actual file. This means for instance that you can revert your changes by accident and then undo.

NerdCommenter

NerdCommenter is a powerful plugin that allows you to make all sorts of comments with ease. In my daily use I rely mostly on a single command, namely:

<leader> c <space>

which toggles comments on/off for the current line or for all the lines of a visual selection.

Vroom

Vroom makes it easy to run your Rails tests within vim. Simply jump to your test (say FooControllerTest), hit

<leader> r

then jump back to the class being tested (say FooController), make your changes then hit

<leader> r

again (without having to jump into the test file).

BufferGator

BufferGator allows you to view a list of active buffers, preview their contents and navigate them. To activate press

<leader> b

Vim Golf

One of the hallmarks of vim is how much you can accomplish using only the keyboard, with most activity taking place on the home row, with very few keystrokes. VimGolf is a fantastic tool for improving your vim chops. The gist of it is that you select a challenge, where you are given a file and an end result. Your goal is to edit the file to look like the end result in as few keystrokes as you can. I highly encourage you to check it out.

Unrestricted Length of SQLite3 Varchar

In one of my pet projects I have a SQLite3 database which contains a column defined as varchar(255), and is displayed as such when I execute the .schema command inside the sqlite3 console.

I wrote a unit test for my Rails model which inserts a 257 character string into that field, and expected it to trigger an error. I was therefore very surprised when the test failed due to the model both being valid and saving successfully. After poking around a bit I found this:

SQLite does not enforce the length of a VARCHAR. You can declare a VARCHAR(10) and SQLite will be happy to let you put 500 characters in it. And it will keep all 500 characters intact – it never truncates.

So if you want to enforce length restrictions on varchar fields in SQLite3, you must enforce them in your model code.

Ruby gotcha: using elsif instead of else if

These past few days I’ve been playing with Ruby and Rails. I’m really loving the experience so far, but every now and then I stumble upon something that doesn’t work as I expected it to.

Last night I encountered problems with one of the most fundamental expressions, namely a if-then-else construct. The interpreter kept complaining that it expected the end keyword, but did not find it.

My code was similar to the sample code below:

if 2 == 3
  puts "foo"
else if 3 == 3
  puts "bar"
end

Executing this yields an error:

5: syntax error, unexpected $end, expecting kEND

At first I was a bit confused and tried to put an extra end keyword after the other one, just to see if it would work:

if 2 == 3
  puts "foo"
else if 3 == 3
  puts "bar"
end end

This “fixed” the problem. However this solution is not going to win any awards for elegance, so I dug around to see why the original code did not work. The reason is that I should have used the elsif keyword which is not equivalent of an if followed by an else clause.

if 2 == 3
  puts "foo"
elsif 3 == 3
  puts "bar"
end

The reason why my original implementation did not work, and why adding an extra end worked becomes much more obvious if we change the indentation of the original example:

if 2 == 3
  puts "foo"
else
  if 3 == 3
    puts "bar"
  # Missing end here!
end