STI where inheritance column values are not the same as the name of the class

I recently tried to retrofit STI on a database table that had already
existed for a while. Here’s a basic outline of the scenario.

  1. I had a class ‘Code’ and a database table ‘codes’.
  2. ‘Code’ had an attribute ‘units’, which could be either ‘$’ or ‘%’
  3. I wanted the STI classes to be Code::Dollar or Code::Percent

I successfully implemented this with the following:

class Code
self.inheritance_column = ‘units’

class << self
def find_sti_class(units)
unit_class_for[units]
end

def sti_name
  unit_class_for.invert[self]
end

def unit_class_for
  {
    '$' => Code::Dollar,
    '%' => Code::Percent
  }
end

end
end

This works perfectly if I use it in the following way:

Code::Dollar.new(initialization_hash)
Code::Percent.new(initialization_hash)

However, if I do just Code.new(units: ‘$’) or something.build(units:
‘$’),
I get an error like the following:

ActiveRecord::SubclassNotFound: Invalid single-table inheritance type: $
is not a subclass of Code

What I really want is for Code.new(units: ‘$’) to return me a
Code::Dollar
object.

I was able to trace the lookup of the class name into
ActiveRecord::Inheritance::ClassMethods#subclass_from_attrs. From there
I
could see that it was trying to build the class name from the units
value
in the database, which obviously doesn’t work as there isn’t a class
named
$ or %.

What I’m really trying to do is setup STI to work correctly when the
value
of the database column doesn’t correspond to a class name. As there is
already another method called find_sti_class, it seems curious that we
couldn’t use it inside of subclass_from_attrs in order to make it work
in
this way. I did try it and was successful, but as find_sti_class is a
private method, I did not submit a patch using this.

So, after all of that, I guess what I’m after is finding out if doing
such
a thing is possible in Rails as is. If not, would a patch to make it
possible be desired by people other than myself? And if that patch made
find_sti_class part of the public interface, would that be likely to be
accepted?

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs