This one threw me for far too many minutes. In ActionView::Helpers::TextHelper the truncate method is broken for Ruby 1.8.7. I’m not exactly sure the version of ruby that it stopped working for, but I was previously on 1.8.6, and I don’t recall it not working. But after I upgraded to the latest patchlevel of 1.8.7, truncate stopped working.
Update 12/2/08: Fixed in Rails 2.2! (read more)
The error that I received was thus:
ActionView::TemplateError (undefined method `length' for #) on line #83 of dashboard/index.html.erb:
Fortunately, someone has submitted a ticket to Rails core. I hope it’s applied in the Rails 2.2.0 release.
Current Method, Done Busted
As of Rails 2.1.0, this is the current method (Rails 2.0.2 is similar, and also broken).
[sourcecode lang=’ruby’]
# File actionpack/lib/action_view/helpers/text_helper.rb, line 49
def truncate(text, length = 30, truncate_string = “…”)
if text
l = length – truncate_string.chars.length
chars = text.chars
(chars.length > length ? chars[0…l] + truncate_string : text).to_s
end
end
[/sourcecode]
The problem is that chars method called on the string object (truncate_string) returns an <Enumerable::Enumerator> object. And according to the Ruby 1.8.7 RDoc, there is no ‘length’ method in Enumerable::Enumerator. To be honest, I can’t find the ‘chars’ method in any of the Ruby 1.8.6 docs or 1.8.7 docs. I guessing that it may have been Rails method at some time.
Fix #1
The fix is to get rid of all the chars methods. On the bug ticket, the author gives his fix, but you are going to have to monkey-patch rails, or change the method name.
[sourcecode lang=’ruby’]
def truncate(text, length = 30, truncate_string = “…”)
if text
l = length – truncate_string.chars.to_a.length
chars = text.chars
(chars.to_a.length > length ? chars.to_a[0…l].to_s + truncate_string : text).to_s
end
end
[/sourcecode]
Fix #2 (mine, tiny bit better?)
I’m not exactly sure why the string needs to be converted to an array, when the length function works just dandy on string objects. So I added this to my application_helper.rb file. Also, in the submitted patch, the result of the ternary is converted to a string (.to_s), when all the resulting methods of the ternary return strings. Unnecessary IMHO and probably left over from when the string object was converted to an enumerable. Note that I started with the Rail 2.0.1 version, so it’s slightly different than if I started with the 2.1.0 version.
[sourcecode lang=’ruby’]
def truncate_string(text, length = 30, truncate_string = ‘…’)
if text.nil? then return end
l = length – truncate_string.length
text.length > length ? text[0…l] + truncate_string : text
end
[/sourcecode]
Yeah, yeah, I could have monkey-patched the TextHelper module, but why tempt fate if you don’t have to. A quick find/replace on ‘truncate’ to ‘truncate_string’ is all that was necessary. Works for me.
I like fix #2 better because it works under older ruby versions, too. *However*, the whole point of calling ‘chars’ on the string and asking it for the length was to support multibyte character formats. The best solution would be to figure out why ‘chars’ in ruby 1.8.7 returns an Enumerable::Enumerator instead of an ActiveSupport::Multibyte::Chars object and fix it there.
Also see:
http://railsforum.com/viewtopic.php?id=27226
Thanks for posting your fix. This one bit me when my host upgraded Ruby versions without announcing it. My whole admin interface broke on my site. Such are the woes of shared hosting.
But thanks for your fix.