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:
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
Edit: it's a known thing.