Ruby on Rails模型中的全局方法

6

我所有的模型都有类似这样的方法:

def formatted_start_date
  start_date ? start_date.to_s(:date) : nil
end

我希望有一种自动为每个模型中的每个日期时间字段编写此类方法的工具,最好的方法是什么?
-C
3个回答

17

我必须回答这个问题,因为这是一个有趣的Ruby练习。

向类添加方法可以通过多种方式完成,但其中一种最简洁的方法是使用Ruby的一些反射和评估功能。

在你的 lib 文件夹中创建此文件作为 lib/date_methods.rb。

module DateMethods

  def self.included(klass)

    # get all dates
    # Loop through the class's column names
    # then determine if each column is of the :date type.
    fields = klass.column_names.select do |k| 
                  klass.columns_hash[k].type == :date
                end


    # for each of the fields we'll use class_eval to
    # define the methods.
    fields.each do |field|
      klass.class_eval <<-EOF
        def formatted_#{field}
          #{field} ? #{field}.to_s(:date) : nil
        end

      EOF
    end
  end
end

现在只需将它包含在需要它的任何模型中即可。

 class CourseSection < ActiveRecord::Base
   include DateMethods
 end

当包含此模块时,它将查看任何日期列并为您生成已格式化的方法。

学习如何使用Ruby。这很有趣。

话虽如此,你必须问自己这是否必要。我个人认为不是,但再次写起来很有趣。

-b-


2
为什么在数组上使用collect和compact而不是select? - Chris Drappier
1
你说得对。在这里使用.select会更合适。我发现有时候即使看起来不应该,.collect.compact也会更快一些,但在这种情况下,.select是一个更好的选择。谢谢你指出来。我一直在专注于做难的事情,错过了简单的东西。 - Brian Hogan
+1 有趣的内容。如果您在Stack Overflow中更正答案以包含Chris的评论,那将更好。 - Dan Rosenstark

11

在我看来,它更像是一个帮手。在你的应用程序帮助中尝试这个:

def formatted_date(date)
   date ? date.to_s(:date) : nil
end

格式化并不是模型应该包含的内容(正如你所发现的那样...在每个模型中放置这样的共同代码很烦人)

如果你真的想按照你说的那样做,那么你可以猴子补丁 ActiveRecord 的超类,并在其中添加你想要的函数。它将在所有你的模型中都可用。请注意,猴子补丁可能会导致无法预测和未定义的行为,请自行承担风险! 它也相当的 hacky :)

class ActiveRecord::Base
   def formatted_start_date
      start_date ? start_date.to_s(:date) : nil
   end
end

只需将其放在应用程序中任何其他内容运行之前的位置,它将动态地将该方法添加到您的模型基类中,使其可供使用。

或者您可以为所有模型创建一个混合类,但是对于单个方法来说,这似乎有点过头了。


好的,假设将格式设置放在模型中是合适的,或者我想在我的应用程序中除了格式化之外做其他事情,我该怎么做? - Chris Drappier
是的,但这里的“start_date”部分是硬编码的,我需要对应用程序中的所有日期字段执行此操作,它们可能被称为 start_date、end_date、term_date、finish_date、date 等等。我该如何检查所有日期列的子类,然后为每个日期列编写一个动态方法? - Chris Drappier
我不知道那个...听起来像是一个坏主意 :P - workmad3

0

回复您的评论: 您可以将常见的代码/功能提取到模块中,然后将其包含在类中(我认为这被称为mixin?),或者您可以选择子类。当您只想将常见功能放入对象中而不是真正的继承情况时,我不认为子类是可行的方法。

请查看此处了解有关模块和Ruby的更多信息


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接