Acts As Inheritable is a Ruby Gem specifically written for Rails/ActiveRecord models. It is meant to be used with the Self-Referential Association, or with a model having a parent
that shares the inheritable attributes. This will let you inherit any attribute or relation from the parent model.
This is a code example on how to implement Self-Referential Association
class Person < ActiveRecord::Base
belongs_to :parent, class: Person
has_many :children, class: Person, foreign_key: :parent_id
has_many :grandchildren, class: Person, through: :children, source: :children
end
Add this line to your application's Gemfile:
gem 'acts_as_inheritable'
And then execute:
$ bundle
Or install it yourself as:
$ gem install acts_as_inheritable
You can enable ActsAsInheritable by adding acts_as_inheritable
into your model. You need to define at least one option, either attributes
or associations
. Those options are arrays containing the atrributes names or the associations names.
class Person < ActiveRecord::Base
acts_as_inheritable attributes: %w(favorite_color last_name soccer_team),
associations: %w(shoes pictures clan)
# Associations
belongs_to :parent, class_name: 'Person'
belongs_to :clan
has_many :children, class_name: 'Person', foreign_key: :parent_id
has_many :toys
has_many :shoes
has_one :pet
has_many :pictures, as: :imageable
# Callbacks
before_validation :inherit_attributes, on: :create
before_validation :inherit_relations, on: :create
end
parent = Person.create(last_name: 'Arango', soccer_team: 'Verdolaga', favorite_color:'Green')
son = Person.create(parent: parent)
son.last_name # => Arango
son.soccer_team # => Verdolaga
son.favorite_color # => Green
By adding acts_as_inheritable
to your models you will have access to these methods:
Signature
inherit_attributes(force = false, not_force_for = [], method_to_update = nil)
By default this method will only set values that are blank?.
force
: Default to true. Set the attribute even if it's present.not_force_for
: Default to empty array. When settingforce
to true, you can also specify the attributes you don't want to overwrite.method_to_update
: Default to nil. Uses the specified method (update_attributes
orupdate_columns
) instead of the normal asignation ("#{attribute}="
). This is useful if you're using inherit_attributes inside anafter_save
callback or if you want to skip validations for example.
Signature
inherit_relations(model_parent = send(:parent), current = self)
class Person < ActiveRecord::Base
acts_as_inheritable associations: %w(pet)
# Associations
has_one :pet
# Callbacks
before_validation :inherit_relations, on: :create
end
parent = Person.create(last_name: 'Arango')
parent_pet = Pet.create(person: parent, name: 'Mango', breed:'Golden Retriver')
parent_pet.inspect #=> #<Pet id: 1, person_id: 1, name: "Mango", breed: "Golden Retriver">
son = Person.create(parent: parent)
son.pet.inspect # => #<Pet id: 2, person_id: 2, name: "Mango", breed: "Golden Retriver">
By default new relations are duplicated using dup, which produces a shallow copy of the object. But you can also handle this as you want by defining a duplicate!
method.
All tests follow the RSpec format and are located in the spec directory. They can be run with:
$ rspec
- Fork it ( https://github.com/esbanarango/acts_as_inheritable/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create a new Pull Request
Support this project and others by esbanarango via gratipay.
This was written by Esteban Arango Medina while working at Blue Sky Cards.
Thanks to @danielosorio83 who also wrote part of the logic for this gem.