The Tail of Truncation

Last week I came across a pretty solid problem, by the time I found the most appropriate solution it had evolved quite a bit. I felt it had the making for a worthwhile blog post, so here it goes.

The problem: we need to display only the first 220 characters of the body of a Press article on the Press Index page.

Initial solution: implement Rails truncate helper. It can be used in the view, as such:

truncate(press.description, length: 220)

This worked for the first 9 items on the page, running as a standard each loop. But we are also implementing infinite scroll on this page with javascript, which renders each item after the ninth through an HMTL template and JSON. So, for the template I had to make a method in the press_serializer.rb file that looks like this:

def description
    object.description.truncate(220)
end

That all worked, but didn’t render well with the other styles on the page, was showing some markup tags, and isn’t the most efficient solution. So, I moved the nuts and bolts from the view to the application_helper.rb and made it into a method:

def truncate_description(description)
    description.truncate(220).html_safe
 end

So now in the view it looks like this:

truncate_description(press.description)

I also modified the method in the serializer for the html template to this:

def description
    object.description.truncate(220).html_safe
end

It’s definitely cleaner code in the view file, and its faster coming from the application helper.

Note that the .html_safe is necessary because we are using a WYSIWYG (What You See Is What You Get) editor to create the description, so there are potentially a lot of opening and closing of tags.

This all worked in our QA and the clients. The first 9 records were being produced via the each loop, and all the rest with the JSON and HTML template. But, as it so happened, we came across an edge case, and that was my problem to solve.

New problem: Basically, what was happening was that the clients wrote a description and included a link within the first 220 characters, which was cut off by the truncate helper. This meant that there was a tag that wasn’t closing, and it bled the link content onto the first piece of text in the next description card.

What would have been super easy was just to tell the clients to rewrite the article, and move the link. Oh, and in the future, don’t put a link within the first 220 characters, thanks! But, of course, that’s not an option. The solution seems like an obvious one, even to me as a write this, but it actually took a good bit of googling to find it.

New Solution: Ultimately I ended up using the truncate_html gem for the Ruby components and html-truncate gem for the JSON components. The Ruby part can be setup like this:

Add truncate_html gem to Gemfile

Replace truncate with truncate_html in the view

truncate_html(press.description)

It can be as simple as that, but to add some versatility I also created a truncate_html.rb file in my initializers folder:

TruncateHtml.configure do |config|
   config.length        = 220
 end

The length could have been added to the line in the view file, but it’s cleaner to have the initializer file, and allows for growth, should any other parameters be necessary.

As for the JSON and HTML templates, after I installed html-truncate I just had to two variables to the top of the HTML template file:

var truncate = require('html-truncate');

let description = truncate(press.description, 220);

Now both the Ruby gem and JS package will close any open tags before truncating, allowing for there to be links, bold tags, or whatever at any place in the description with no problem at all.

Resources:
http://api.rubyonrails.org/classes/ActionView/Helpers/TextHelper.html#method-i-truncate
https://github.com/hgmnz/truncate_html
https://www.npmjs.com/package/html-truncate