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

微笑、不失礼 提交于 2019-12-10 19:07:21

问题


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

回答1:


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.




回答2:


This solution is similar to undefinedvariable's above, but a bit more DRY.

# organize your sti classes in directories named after the parent
sti_directory_paths = [
  Rails.root.join("app","models","subfolder_one"),
  Rails.root.join("app","models","subfolder_two"),
]

def require_sti_model(path, filename)
  require_dependency (path + filename).to_s
end

# if you use something like guard, just exclude from production
unless Rails.env.production?
  sti_directory_paths.each do |sti_directory_path|
    Dir[sti_directory_path + "*.rb"].each do |filename|
      require_sti_model(sti_directory_path, filename)
      ActionDispatch::Reloader.to_prepare do
        require_sti_model(sti_directory_path, filename)
      end
    end
  end
end


来源:https://stackoverflow.com/questions/14711505/how-to-reload-files-in-app-models-subdirectory-in-dev-environment-for-sti

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!