【问题标题】:How can I make rails helpers more object-oriented如何使 Rails 助手更加面向对象
【发布时间】:2009-05-12 02:50:38
【问题描述】:

我想在我的整个 Rails 应用程序中为所有助手替换以下语法:

time_ago_in_words(@from_time)

用这个:

@from_time.time_ago_in_words

理想情况下,此更改还将使帮助程序在我的应用程序中的任何位置都可用(同样的方式,例如,5.times)。

有谁知道有这样的插件吗?自己动手会不会很困难?

【问题讨论】:

  • 为什么这很重要?也许一些上下文会有所帮助......
  • 我只是觉得他们现有的语法既烦人又丑陋。在我的模型中调用 @post.truncate 之类的东西也会很好(例如用于缓存)

标签: ruby-on-rails oop helpers


【解决方案1】:

如果你创建一个新模型,你可以让它继承现有类的方法。

示例(app/models/mykindofstring.rb):

class Mykindofstring < String

    def all_caps_and_reverse
        self.upcase.reverse
    end 

end

然后从控制器:

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

最后从视图中调用它:

<%= @my_string %>

显示为这是我的字符串,而:

<%= @my_string.all_caps_and_reverse %>

显示为 GNIRTS YM SI SIHT。

该类继承自字符串类,因此适用于字符串的所有方法也适用于 mykindofstring 对象。其中的方法只是两个现有字符串方法组合的新名称,但您可以让它为所欲为,例如将时间转换为格式化字符串的方法。

基本上,它只是使用您自己的方法扩展当前的 Ruby 类,而不是使用函数/帮助器。

重大修改

根据 Ians 对此答案的评论和他自己对上述问题的回答,我在 Rails 中进行了一些尝试,并想出将其添加到 application_helper.rb:

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

现在只需在应用程序中的任何字符串上调用该方法:

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

.gnirts a si sihT

【讨论】:

  • 但它是 Ruby!子类化是“正确的”面向对象,但是您不想创建另一种类型的新对象,您想使用真正的上帝赋予的字符串,所以只需打开 String 类并添加您的方法: class String; def all_caps_and_reverse; self.upcase.reverse;结尾;结束
  • 谢谢,好点子。我相应地修改了答案。顺便说一句,这就是我喜欢 Stack Overflow 的原因;我才来这里几天,我的代码已经在改进了。
  • 为什么要使用 class_eval 而不是重新声明字符串类?
  • 在 ApplicationHelper 模块中,class_eval 有效。在外面时,重新打开课程是可行的(我只是在 ApplicationHelper 下的同一个文件中完成了它)。它可能与在模块中定义一个类有关。在使用它进行一些试验和错误时,我不得不重新启动应用程序,因此它也可能与 Rails 如何自动加载事物有关。我确信还有其他地方可以放置它以及其他方法可以做到这一点,但是为了快速添加到类中,在 Rails 加载路径中已经存在的东西中使用 class_eval 似乎是更好的做法。
【解决方案2】:

对于所有(甚至大多数)帮助程序,您不会在整个应用程序中找到任何简单的方法来执行此操作。

Helper 被构建为模块,旨在包含在视图呈现类中。要利用它们,您必须保留一个 ActionView 的副本(我想这不是一笔大买卖)。

不过,您始终可以打开类并指定所需的每个帮助器:

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"

如果您采用这种方法,我建议您缓存您使用的 ActionView::Base 实例。或者,如果您不想变得如此重量级,您可以创建自己的类以仅包含您想要的帮助器(虽然您不想直接在每个时间、日期、字符串等类中包含帮助器,因为这会使方法命名空间非常混乱——并且与您想要的自然名称冲突)。

【讨论】:

    【解决方案3】:

    如果您使用的是 Ruby 2.1,则可以使用 Refinements。它们是猴子修补 Ruby 类的替代方案。借用@Jarrod's monkey-patch例子:

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

    您现在可以在任何您想要的对象中使用它:

    class Post
      using MyString
    end
    @post.title.all_caps_and_reverse
    

    你可以在这里read more about Refinements

    【讨论】:

      【解决方案4】:

      制作一个模型,TimeAgo 或类似的东西。在这里实现以下这个想法: a code snippet for "wordifying" numbers

      然后,在您的控制器中,使用此类创建实例变量。然后,在您看来,请致电@from_time.in_words

      【讨论】:

        猜你喜欢
        • 2010-10-19
        • 2013-05-18
        • 2012-08-17
        • 2020-12-20
        • 2015-09-27
        • 1970-01-01
        • 1970-01-01
        • 2014-01-26
        • 1970-01-01
        相关资源
        最近更新 更多