Eric Roberts
2014-Jul-10 14:58 UTC
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? -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To view this discussion on the web visit https://groups.google.com/d/msgid/rubyonrails-talk/8af5104b-6e67-4dae-8e63-63216dcddccf%40googlegroups.com. For more options, visit https://groups.google.com/d/optout.