Skip to content
benilovj edited this page Nov 22, 2012 · 8 revisions

ORM/ODM Support

The plugin is built on the ActiveModel validation system. This means it can allow multiple ORMs which support this system to use the plugin. This was not possible in previous versions.

To add full and proper support to an ORM, a few class method hooks need to be defined.

Hooks

Attribute Method Generation

The first hook is a for the attribute method generation performed by the ORM. To properly validate a date/time attribute, its raw value must be known. This is because an attribute value of nil may result from parsing an invalid value or the attribute is just nil. The plugin needs to be able to tell the difference so that it can add an error when invalid value has been parsed, but not when it is legitimately nil.

ActiveRecord, and perhaps other ORMs, does not store the raw value for timezone enabled attributes e.g. datetimes. To get around this, the plugin creates a write method for each validated attribute which stores the raw value and then calls super. In previous ActiveRecord versions this process was more complex because you could not just call super to resume the normal write method behaviour for the attribute.

In order to properly create this method, it must be done after the ORM has generated all the regular attribute methods. This method generation process can be triggered in various ways but each ORM seems to handle it differently. This is why a custom shim for each ORM must be created to hook into this process.

Here is the hook method for ActiveRecord:

def define_attribute_methods
  super
  define_timeliness_methods(true)
end

The super will allow ActiveRecord to do its normal method generation and then the plugin creates it methods for each validated attribute. The ‘true’ value passed to ‘define_timeliness_methods’ is indicate that the _before_type_cast methods should also be created for each validated attribute. This before_type_cast convention originally added to ActiveRecord, but may exist in other ORMs.

Attribute Type

The type for the attribute needs to be known when the plugin parser is being used. The method will be defined with the type passed to the parse method.

def timeliness_attribute_type(attr_name)
  columns_hash[attr_name.to_s].type
end

Timezone Handling

ActiveRecord uses the sophisticated timezone handling provided by ActiveSupport. The timezone handling is added for all datetime and timestamp columns by default unless explicitly excluded. To be able to accurately handle timezones for each attribute, the plugin must be able to query whether an attribute is timezone aware. ActiveRecord has a specific technique of doing this and will likely differ in other ORMs if supported at all.

Here is how the hook works for ActiveRecord:

def timeliness_attribute_timezone_aware?(attr_name)
  create_time_zone_conversion_attribute?(attr_name, columns_hash[attr_name])
end

An attribute name is passed to the plugin method timeliness_attribute_timezone_aware? and you are left to define how to discover the timezone awareness of that attribute as supported by the ORM.

Reload

Most ORM/ODMs support a reload mechanism to flush change for a saved record and use the original values. If this is the case then you may need to hook into the reload method to clear the timeliness values cache using _clear_timeliness_cache.

Example

See this file for the full shim for ActiveRecord.

Custom Shims

If you create a custom shim for an ORM, please let me know and it is likely I can add it to the plugin to make things easier.