Dex
Dex

Reputation: 12749

Overriding ActiveRecord Column Methods with a Mixin

I'm trying to make it so that I can configure some columns to always convert to a different timezone based on user settings. I'd like the config to be like:

class MyClass
  include TimeZonify
  tz_column :col1, :col2
end

My mixin is obviously incorrect but it looks something like this:

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

So now, when I call MyClass.new.col1, it will no longer be in UTC, but instead in whatever timezone the user has in their profile.

Upvotes: 1

Views: 777

Answers (1)

Dmytrii Nagirniak
Dmytrii Nagirniak

Reputation: 24088

If you are using Rails, then time zone support must work out of the box. And you can have different time zone for each user.


I would not recommend to override the date/time method accessors because then you will also need to override the setter.

If you will not, following will result in invalid result every time it is executed (for example, on update).

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

But if you need a shortcut for display purposes, instead I would recommend to use an extension to this method:

it.effective_at_local

which can be implemented with the 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

BTW, on the related note you can use TimeZone.

Upvotes: 1

Related Questions