InheritanceIntegerType
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:
class Company < ActiveRecord::Base; end
class Firm < Company; end
class Client < Company; end
class PriorityClient < Client; end
With a migration that looks something like:
class CreateCompanies < ActiveRecord::Migration
def change
create_table :companies do |t|
t.string :name
t.string :type
end
end
end
The 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.
Installation
Current versions of this gem (>= v0.2.0) only support Ruby 3+ and ActiveRecord >= v6.1. 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
Usage
The gem is pretty straightforward to use.
First, set the integer_inheritance
value on each of the subclasses.
class Firm < Company
self.integer_inheritance = 1
end
class Client < Company
self.integer_inheritance = 2
end
class PriorityClient < Client
self.integer_inheritance = 3
end
Note: 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.)
class CompanyToIntegerType < ActiveRecord::Migration
def up
change_table :companies do |t|
t.integer :new_type
end
execute <<-SQL
UPDATE companies
SET new_type = CASE type
WHEN 'Firm' THEN 1
WHEN 'Client' THEN 2
WHEN 'PriorityClient' THEN 3
END
SQL
change_table :companies, :bulk => true do |t|
t.remove :type
t.rename :new_type, :type
end
end
def down
change_table :companies do |t|
t.string :new_type
end
execute <<-SQL
UPDATE companies
SET new_type = CASE imageable_type
WHEN 1 THEN 'Firm'
WHEN 2 THEN 'Client'
WHEN 3 THEN 'PriorityClient'
END
SQL
change_table :companies, :bulk => true do |t|
t.remove :type
t.rename :new_type, :type
end
end
end
Lastly, 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.
Contributing
- 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