Question

I'd like to, for all helpers, across my entire Rails application, replace this syntax:

time_ago_in_words(@from_time)

with this:

@from_time.time_ago_in_words

Ideally this change would also make the helpers available anywhere in my application (the same way, say, 5.times is).

Does anyone know of a plugin that does this? Would it be difficult to roll my own?

Was it helpful?

Solution

If you create a new model you can make it inherit the methods from an existing class.

Example (app/models/mykindofstring.rb):

class Mykindofstring < String

    def all_caps_and_reverse
        self.upcase.reverse
    end 

end

Then from the controller:

@my_string = Mykindofstring.new('This is my string')

and finally calling it from the view:

<%= @my_string %>

displays as This is my string, while:

<%= @my_string.all_caps_and_reverse %>

displays as GNIRTS YM SI SIHT.

The class inherits from the string class, so all the methods that apply to a string also apply to a mykindofstring object. The method in it is just a new name for a combination of two existing string methods, but you can make it do whatever you want, such as a method to convert a time into a formatted string.

Basically it's just extending a current Ruby class with your own methods instead of using functions/helpers.

Major Edit

Based on Ians comment to this answer and his own answer to the above question, I played around a bit in Rails and came up with adding this to the application_helper.rb:

module ApplicationHelper
  String.class_eval do
    def all_caps_and_reverse
      self.upcase.reverse
    end
  end
end

Now just call the method on any string in the app:

@string = 'This is a string.'
@string.all_caps_and_reverse

.gnirts a si sihT

OTHER TIPS

You won't find any easy way to do this across your whole application for all (or even most) helpers.

Helpers are structured as modules meant to be included in view rendering classes. To leverage them, you'd have to keep a copy of an ActionView around (not a HUGE deal I suppose).

You can always open up the classes and specify each helper you want, though:

class Time
  def time_ago_in_words
    ActionView::Base.new.time_ago_in_words self
  end
end

>> t = Time.now
=> Tue May 12 10:54:07 -0400 2009
>> t.time_ago_in_words
=> "less than a minute"
(wait a minute)
>> t.time_ago_in_words
=> "1 minute"

If you take that approach, I recommend caching the instance of ActionView::Base that you use. Or, if you don't want to go so heavyweight, you can create your own class to just include the helpers you want (you don't want to include the helpers directly in each Time, Date, String, etc, class, though, as that will clutter up the method namespace pretty fierce -- and conflict with the natural names you want).

If you are using Ruby 2.1 you can use Refinements. They are an alternative to monkey-patching Ruby's classes. to borrow @Jarrod's monkey-patch example:

module MyString
  refine String do
    def all_caps_and_reverse
      upcase.reverse
    end
  end
end

You can now use this in any object you want:

class Post
  using MyString
end
@post.title.all_caps_and_reverse

You can read more about Refinements here.

Make a model, TimeAgo or something similar. Implement following this idea here: a code snippet for "wordifying" numbers

Then, in your controller, create the instance variables using this class. Then, in your view, call @from_time.in_words

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top