使用Mixin覆盖ActiveRecord列方法

时间:2011-03-10 02:05:31

标签: ruby-on-rails ruby activerecord metaprogramming

我正在尝试这样做,以便我可以配置一些列,以便始终根据用户设置转换为不同的时区。我希望配置如下:

class MyClass
  include TimeZonify
  tz_column :col1, :col2
end

我的mixin显然不正确,但它看起来像这样:

module TimeZonify
  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods

    def tz_column(*columns)
      columns.each do |column|
        instance_eval do   # <-- obviously this block does not get executed
          <<-CODE
            def #{column}
              super.in_time_zone("Lima")
            end
          CODE
        end
      end
    end

  end

end

现在,当我呼叫MyClass.new.col1时,它将不再是UTC,而是用户在个人资料中的时区。

1 个答案:

答案 0 :(得分:1)

如果您使用的是Rails,那么时区支持必须开箱即用。你可以拥有different time zone for each user


我不建议覆盖日期/时间方法访问器,因为那时你还需要覆盖setter。

如果不这样做,以下操作将在每次执行时导致无效结果(例如,在更新时)。

original = it.effective_at
it.effective_at = it.effective_at # it +TimeZone
it.effective_at = it.effective_at # it +TimeZone
original == it.effective_at # => false - every assignment actually changes the time by +TimeZone

但是如果你需要一个快捷方式用于显示目的,我建议使用这种方法的扩展名:

it.effective_at_local

可以使用mixin实现:

module TimeZonify
  def self.included(base)
    base.extend(ClassMethods)
  end

  module ClassMethods

    def tz_column(*columns)
      columns.each do |column|
        instance_eval do
          <<-CODE
            def #{column}_local
              #{column}.in_time_zone("Lima")
            end
          CODE
        end
      end
    end

  end

end

顺便说一句,在相关说明中,您可以使用TimeZone