vidibus-inheritance
This gem is part of the open source SOA framework Vidibus: www.vidibus.org
It allows inheritance of objects and is depends on Rails 3 and Mongoid. It will update all attributes and embedded documents of inheritors when ancestor gets changed. Custom attributes (mutations) of inheritors will not be overridden, unless a :reset option is set.
Installation
Add the dependency to the Gemfile of your application:
gem "vidibus-inheritance"
Then call bundle install on your console.
Usage
Include the Vidibus::Uuid::Inheritance module in your Mongoid model:
class Model
include Mongoid::Document
include Vidibus::Uuid::Mongoid
include Vidibus::Inheritance::Mongoid
field :name
end
To establish an inheritance relationship, add ancestor to a model of same class:
ancestor = Model.create(:name => "Anna")
# To establish a relation, call #inherit_from!
inheritor = Model.new
inheritor.inherit_from!(ancestor)
# ...or set :ancestor attribute
inheritor = Model.create(:ancestor => ancestor)
Mongoid configuration
When inheriting, the attribute :_reference_id will be set on embedded documents of inherited objects. So make sure this field is available or Mongoid is configured to allow dynamic fields. Add to config/mongoid.yml:
allow_dynamic_fields: true
Acquired attributes
All attributes will be inherited, except these ACQUIRED_ATTRIBUTES:
_id
_type
uuid
ancestor_uuid
mutated_attributes
mutated
created_at
updated_at
version
versions
You may overwrite acquired attributes by defining a method on your inherited document and its embedded documents:
def acquired_attributes
Vidibus::Inheritance::Mongoid::ACQUIRED_ATTRIBUTES + %w[my custom values]
end
Manage mutations of embedded documents
All custom changes on inherited objects will be stored in #mutated_attributes. On embedded documents of inherited objects, however, mutations of attributes will not be tracked. But you may flag a document as mutated when applying custom values:
class Job
include Mongoid::Document
field :salary
field :mutated, :type => Boolean
:model, :inverse_of => :jobs
def set_custom_salary(amount)
self.salary = amount
self.mutated = true
end
end
To control how inherited data will be updated, you may define a callback method and check #mutated:
def update_inherited_attributes(attrs)
attrs.delete("salary") if mutated? # preserve custom salary
update_attributes(attrs)
end
TODO
-
Removed items will be re-added when inheritance is performed again. Introduce paranoid behaviour for embedded collection items? Or add a list of deleted associations like _destroyed_children?
-
Use delayed_job for inheritance across a huge pedigree.
-
Fix relations when deleting an ancestor.
-
Rewrite root_ancestor_id when deleting the root ancestor.
Copyright
Copyright © 2010 Andre Pankratz. See LICENSE for details.
Thank you!
The development of this gem was sponsored by Käuferportal: www.kaeuferportal.de