This gem makes it easy to have int (or tinyint) 'type' fields in your Rails database, instead of strings. It makes much more efficient use of disk space and RAM, especially if the column is indexed.
The example provided by the Rails documentation shows something like this:
classCompany < ActiveRecord::Base;endclassFirm < Company;endclassClient < Company;endclassPriorityClient < Client;endWith a migration that looks something like:
classCreateCompanies < ActiveRecord::Migrationdefchangecreate_table:companiesdo |t|
t.string:namet.string:typeendendendThe problem with this approach is that type is a string (and by default it is 255 characters). This is a little ridiculous. For comparison, if we had a state machine with X states, would we describe the states with strings "State1", "State2", etc or would we just enumerate the state column and make it an integer? This gem will allow us to use an integer for the type column.
Current versions of this gem (>= v0.2.3) only support Ruby 3+ and ActiveRecord >= 7.0. For ActiveRecord 6.1, use v0.2.2. For Ruby <= v2.7 or ActiveRecord <= 6.0, use v0.1.3.
Add this line to your application's Gemfile:
gem 'inheritance_integer_type'
And then execute:
$ bundle
Or install it yourself as:
$ gem install inheritance_integer_type
The gem is pretty straightforward to use.
First, set the integer_inheritance value on each of the subclasses.
classFirm < Companyself.integer_inheritance=1endclassClient < Companyself.integer_inheritance=2endclassPriorityClient < Clientself.integer_inheritance=3endNote: The mapping here can start from whatever integer you wish, but I would advise not using 0. The reason being that if you had a new class, for instance PriorityFirm, but forgot to include set the mapping, it would effectively get to_i called on it and stored in the database. "Priority".to_i == 0, so if your mapping included 0, this would create a weird bug.
If you want to convert a polymorphic association that is already a string, you'll need to set up a migration. (Assuming SQL for the time being, but this should be pretty straightforward.)
classCompanyToIntegerType < ActiveRecord::Migrationdefupchange_table:companiesdo |t|
t.integer:new_typeendexecute<<-SQL UPDATE companies SET new_type = CASE type WHEN 'Firm' THEN 1 WHEN 'Client' THEN 2 WHEN 'PriorityClient' THEN 3 END SQLchange_table:companies,:bulk=>truedo |t|
t.remove:typet.rename:new_type,:typeendenddefdownchange_table:companiesdo |t|
t.string:new_typeendexecute<<-SQL UPDATE companies SET new_type = CASE imageable_type WHEN 1 THEN 'Firm' WHEN 2 THEN 'Client' WHEN 3 THEN 'PriorityClient' END SQLchange_table:companies,:bulk=>truedo |t|
t.remove:typet.rename:new_type,:typeendendendLastly, you will need to be careful of any place where you are doing raw SQL queries with the string (type = 'Firm'). They should use the integer instead.
- Fork it ( https://github.com/[my-github-username]/inheritance_integer_type/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