Firstly I would like to point out that I am not talking about STI (Single Table Inheritance) here. What I am referring to is when you need each of your model classes inheriting a number of properties that need to be stored in each table on a per record basis, much like ActiveRecord does with the its timestamps (updated_at, created_at) properties.
Each of your model classes will need to include a module that defines the common properties. The module can also set out the property default’s and also shared behaviors for your model objects.
require 'dm-core'
require 'dm-validations'
require 'dm-types'
module Shout
module Record
#DataMapper::Logger.new(STDOUT, :debug)
DataMapper.setup(:default, "sqlite:///#{File.dirname(__FILE__)}/../../../db/shout_mouth.db")
def self.included(base)
base.class_eval do
include DataMapper::Resource
property :id, DataMapper::Property::Serial
property :is_active, DataMapper::Property::Boolean, :default => true
property :created_at, DataMapper::Property::DateTime, :default => lambda{ |p,s| DateTime.now}
#Scope
def self.all_active
all(:is_active => true, :order => [ :created_at.desc ])
end
#Help
def created_at_iso8601
created_at.strftime("%Y%m%dT%H:%M:%S")
end
end
end
end
end
In the above module I have set three properties that all my classes will include id, is_active and created_at. Also a default all_active scope will be shared amongst all the model objects.
require Dir.pwd + '/app/models/base/shout_record'
class Tag
include Shout::Record
property :tag, String, :length => 1000
has n, :posts, :through => Resource, :is_active => true, :order => [ :created_at.desc ]
validates_uniqueness_of :tag
#Instance Methods
def permalink
"#{Blog.url}/tag/#{tag}"
end
#Factory Methods Input
def self.tags_from_array(array)
array.map{|tag| Tag.first_or_create({:tag => tag.strip}, {:tag => tag.strip})}
end
#Factor Methods Output
def self.usable_active_tags
all.posts #need to force dynamic creation of the tag_posts class - this does not fire a query
all_active.all(:tag.not => "page", :post_tags => {:post => { :is_active => true }}, :order => [:tag.asc])
end
end
Each of the model classes will now need include the module. In the case above the class will now have the following properties id, is_active, created_at and tag. Also the all_active scope defined in the module is now accessible to the model class allowing chaining of methods such as :-
all_active.all(:tag.not => "page")
It’s a great way to keep your model classes DRY and perfect for when you need to change some default behaviors system wide.