Skip to content

A Ruby gem that implements single-table inheritance (STI) for ActiveRecord models using string, integer and boolean column types.

License

Notifications You must be signed in to change notification settings

gregorw/discriminable

Repository files navigation

Discriminable

Gem Version CI Maintainability Test Coverage

This is a Ruby gem that implements single-table inheritance (STI) for ActiveRecord using string, integer and boolean column types.

In other words, it allows you to use any existing model attribute to discriminate between different subclasses in your class hierarchy. This is especially useful when dealing with legacy databases or third-party systems. Anytime you cannot use the default “inheritance column / class name” combo—discriminable is your friend.

It also supports aliased attributes and multiple values per subclass.

Installation

bundle add discriminable

or

gem install discriminable

Usage

class Order < ActiveRecord::Base
  include Discriminable

  discriminable_attribute :state
end

class Cart < Order
  discriminable_value :open
end

Cart.create
# => #<Cart id: 1, state: "open">
Order.all
# => #<ActiveRecord::Relation [#<Cart id: 1, state: "open">]>

Features

Compatible with enums

class Order < ActiveRecord::Base
  include Discriminable

  enum state: { open: 0, processing: 1, invoiced: 2 }

  discriminable_attribute :state
end

class Cart < Order
  discriminable_value :open
end

class Invoice < Order
  discriminable_value :invoiced
end

Aliased attributes

In case you are working with a legacy database and cannot change the column name easily it’s easy to reference an aliased attribute in the discriminable_attribute definition.

class Property < ActiveRecord::Base
  include Discriminable

  alias_attribute :kind, :kind_with_legacy_postfix

  # Aliased attributes are supported when specifying the discriminable attribute
  discriminable_attribute :kind
end

class NumberProperty < Property
  discriminable_value 1
end

Multiple values

Sometimes, in a real project, you may want to map a number of values to a single class. This is possible by specifying:

class OptionProperty < Property
  # The first mention becomes the default value
  discriminable_values 2, 3, 4
end

Note that when creating new records with e.g. OptionProperty.create a default value needs to be set in the database for this discriminable class. The Discriminable gem uses the first value in the list as the default.

Comparison with standard Rails

Rails STI

values string integer boolean enum decimal
single 🟡 class.name only 🔴 🔴 🔴 🔴 🔴
multiple 🔴 🔴 🔴 🔴 🔴 🔴

Discriminable Gem

values string integer boolean enum decimal
single 🟢 🟢 🟢 🟢 🟢 🟢
multiple 🟢 🟢 🟢 🟢 🟢 🟢

“Multiple” means that more than one value can map to a single subclass. This may or may not be useful for your use case. In standard Rails, the a single class name obviously maps to a single class.

Prerequisites

Rails 5+ is required.

Also, in order to make this work in development environment the class hierarchy needs to be loaded.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/gregorw/discriminable. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the Discriminable project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.

Related work

The idea for this Gem was influenced by “Bye Bye STI, Hello Discriminable Model” by Randy Burkes. This Gem has started out with his code.

See also:

About

A Ruby gem that implements single-table inheritance (STI) for ActiveRecord models using string, integer and boolean column types.

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks