How can I make rail helpers more object oriented

I would like for all the helpers throughout my Rails application to replace this syntax:

time_ago_in_words(@from_time)

      

with this:

@from_time.time_ago_in_words

      

Ideally, this change would also make helpers available anywhere in my application (as well, for example 5.times

).

Does anyone know of a plugin that does this? Would it be hard to roll me?

+1


a source to share


4 answers


If you are creating a new model, you can force it to inherit methods from the 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 by calling it from the view:

<%= @my_string %>

      

displays like this is my string, while:

<%= @my_string.all_caps_and_reverse %>

      



displayed as GNIRTS YM SI SIHT.

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

It's basically just extending the current Ruby class with native methods instead of using functions / helpers.

Main board

Based on Jan's comment on this answer and his own answer to the above question, I played around with Rails a bit and came up with adding this to 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 line in your application:

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

      

.gnirts a si sihT

+4


a source


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

Helpers are structured as modules to be included in view rendering classes. In order to use them you will need to keep a copy of the ActionView (not a HUGE deal, I suppose).

You can always open classes and list each helper you want:



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 this approach, I recommend caching the ActionView :: Base instance you are using. Or, if you don't want to go for such a heavyweight, you can create your own class to just include the helpers you want (you don't want to include helpers directly in every time, date, string, etc., Class, though, since this clutters the method namespace pretty rigid - and contradicts the natural names you want).

+1


a source


If you are using Ruby 2.1 you can use Refinements. They are an alternative to the ruby ​​monkey protection classes. take @Jarrod monkey-patch example:

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

      

Now you can use this on any object you want:

class Post
  using MyString
end
@post.title.all_caps_and_reverse

      

You can read more about Clarifications here.

+1


a source


Make a model, TimeAgo or something similar. Implement the following idea here: code snippet to "mark" numbers

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

0


a source







All Articles