如何在开发环境中的app / models /子目录中为STI重新加载文件

时间:2013-02-05 15:54:24

标签: ruby-on-rails-3.2 development-environment single-table-inheritance

我使用Alex Reisner's blog post中的一些提示在我的一个模型中实现了STI。我已经让所有子类都使用超类的控制器,使用serialize / store来保存额外的属性。我将model_nameself.select_options方法添加到超类中,并将预加载初始化程序添加到Alex的博客中。我还在_form视图助手和属性验证中更改了我的collection_select以使用self.select_options方法。我的所有子类都在app / models /子文件夹中的单个文件中,尽管它们不像SubFolder :: Subclass那样被命名空间。

然后我开始遇到问题。在更改任何代码后,self.select_options将停止返回所有子类。它只返回一个小子集或没有。因此,由于验证和_form绑定,我无法在代码更改后编辑/更新我的模型。据我所知,当我更改任何代码时,Rails会重新加载环境,而不是子文件夹中的模型。

我尝试将路由添加到config.autoload_paths like many suggest,但最终还是没有用。

所以最终,我想:

  • 修复自动加载的内容,因此我不必在每次更改后重新启动服务器
  • 将其基于包含所有子项的子目录,以避免手动维护数组
  • Rails 3.2.11,ruby 1.9.3p125,ubuntu 12.04.01,rvm

2 个答案:

答案 0 :(得分:3)

我最终合并了此answer和此one的代码以及从底部的wondible博客帖子收集的知识。 config.autoload_paths似乎没有任何帮助,但我把它们留在那里。关键部分是初始化程序,它在启动时需要子目录中的所有文件,然后在每次重新加载时。我尝试load而不是require_dependency,但没有效果。无需一直重装,这绝对是一件好事。

在application.rb

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

在development.rb

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

在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

一些包含有用信息的博客文章

  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/
  5. 修改:it's a known thing

答案 1 :(得分:1)

此解决方案类似于上面的undefinedvariable,但更多一些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