Search code examples
ruby-on-railsactiverecordinheritancesti

Rails subclassing and STI


I'm working on a Rails project OldApp that's using STI for some class Foo. At the moment we have a big, incremental, rewrite going on. To ease the pain we chose a rather unconventional approach. The new, namespaced, application NewApp lives as an engine in OldApp for now.

The models we're going to reuse in NewApp have been created in NewApp and OldApp now uses these models as their parent classes. Why? Now we can move and refactor code from OldApps models to the new ones, OldApp still works, the tests from OldApp ensure that the refactoring in NewApp doesn't break stuff and OldApp basically works as a todo-list (if everything from OldApp is gone, we're done). However ;-)

The problem is, STI kinda kills this (otherwise surprisingly nicely working) approach at the moment.

   class OldApp::Foo < NewApp::Foo; end
   class NewApp::Foo < ActiveRecord::Base; end

   # in the console
   OldApp::Foo.count #=> SELECT COUNT(*) FROM `foos` WHERE `foos`.`type` IN ('Foo')
   NewApp::Foo.count #=> SELECT COUNT(*) FROM `foos`

of course, OldApp::Foo does this, because it's assuming it's just a STIish subclass of NewApp::Foo and not the base Foo class for NewApp. Disabling STI completly for Whatever::Foo doesn't work either because, well, in fact we are using STI for Foo.

I'm basically looking for something to tell NewApp::Foo that it's the base class for the STI chain.

Does this make sense? A little hard to explain...


Solution

  • Using an abstract base class and let inherit OldApp::Foo and NewApp::Foo from it would do the trick:

    class NewApp::FooBase < ActiveRecord::Base
        self.abstract_class = true
    end
    
    class NewApp::Foo < NewApp::FooBase; end
    class OldApp::Foo < NewApp::FooBase; end
    

    You would put all your refactored code in the base class so that OldApp::Foo and NewApp::Foo act as starting point for STI.