Search code examples
ruby-on-rails-3.2development-environmentsingle-table-inheritance

How to reload files in app/models/subdirectory in dev environment for STI


I implemented STI in one of my models, using some tips from Alex Reisner's blog post. I already had all my subclasses use the superclass's controller, with serialize/store to hold the extra attributes. I added the model_name and self.select_options methods to the superclass, and the preload initializer from Alex's blog. I also changed my collection_select in the _form view helper and attribute validation to use the self.select_options method. All my subclasses are in individual files in a app/models/subfolder, though they're not namespaced like SubFolder::Subclass.

Then I start running into problems. Upon changing any code, self.select_options stops returning all of the subclasses. It only returns a small subset or none. Thus due to the validation and _form tie-in, I can't edit/update my models after a code change. From what I could tell, when I change any code, Rails reloads the environment, but not the models in the subfolder.

I tried adding the routes to config.autoload_paths like many suggest, but ultimately that didn't work.

So ultimately, I want:

  • Something to fix the autoloading, so I won't have to restart the server after every change
  • Base it off the subdirectory containing all the children, to avoid manually maintaining an array
  • Rails 3.2.11, ruby 1.9.3p125, ubuntu 12.04.01, rvm

Solution

  • I ended up combining the code from this answer and this one and knowledge gleaned from the wondible blog posts at the bottom. The config.autoload_paths never seemed to help anything, but I kept them in there. The key part is the initializer that requires all the files in the subdirectory on startup and then at each reload. I tried load over require_dependency, which didn't work. It's definitely been nice not having to reload all the time.

    In application.rb

    config.autoload_paths += %W(#{config.root}/app/models/configuration)
    

    In development.rb

    config.autoload_paths += Dir["#{config.root}/app/models/configuration/**"]
    

    In preload_sti_models.rb

    if Rails.env.development?
      Dir.entries("#{Rails.root}/app/models/subfolder").each do |c|
        require_dependency File.join("app","models", "subfolder", "#{c}") if c =~ /.rb$/
      end
      ActionDispatch::Reloader.to_prepare do
        Dir.entries("#{Rails.root}/app/models/subfolder").each do |c|
          require_dependency File.join("app","models", "subfolder", "#{c}") if c =~ /.rb$/
        end
      end
    end
    

    Some blog posts with useful information

    1. http://wondible.com/2012/01/13/rails-3-2-autoloading-in-theory/
    2. http://wondible.com/2011/12/30/rails-autoloading-cleaning-up-the-mess/
    3. http://wondible.com/2011/12/23/give-rails-autoloading-a-boot-to-the-head/
    4. http://www.williambharding.com/blog/technology/rails-3-autoload-modules-and-classes-in-production/

    Edit: it's a known thing.