Skip to content

esbanarango/acts_as_inheritable

Repository files navigation

ActsAsInheritable

Gem Version Build Status Test Coverage security

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.

Self-Referential Association

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

Installation

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

Usage

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

Available methods

By adding acts_as_inheritable to your models you will have access to these methods:

inherit_attributes

Signature inherit_attributes(force = false, not_force_for = [], method_to_update = nil)

By default this method will only set values that are blank?.

params
  • force: Default to true. Set the attribute even if it's present.
  • not_force_for: Default to empty array. When setting force 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 or update_columns) instead of the normal asignation ("#{attribute}="). This is useful if you're using inherit_attributes inside an after_save callback or if you want to skip validations for example.

inherit_relations

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">

Handling your own dup

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.

Testing

All tests follow the RSpec format and are located in the spec directory. They can be run with:

$ rspec

Contributing

  1. Fork it ( https://github.com/esbanarango/acts_as_inheritable/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

Donating

Support this project and others by esbanarango via gratipay.

Support via Gratipay

Author

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.