Rails:将模型构造成子文件夹而不创build子模块的优雅方法

我的应用程序/模型文件夹中有许多模型。 我想清理一下这个文件夹。 在子文件夹中移动属于彼此的模型。 问题是按照惯例,模型类被命名为相应的模块。

例如

应用程序/模型/博客/ post.rb
应用程序/模型/博客/ comment.rb
应用程序/模型/ user.rb

以便:

应用程序/模型/博客/ post.rb

class Post < ActiveRecord end 

并不是

 class Blog::Post < ActiveRecord end 

以下是我用于Rails 3的内容:

 config.autoload_paths += Dir[Rails.root.join('app', 'models', '{**}')] 

这个configuration告诉Railsrecursion地扫描所有app / models子文件夹并加载所有find的模型。 不需要命名空间。

我们需要这样做,而且有一个非常简单的方法。

将模型移动到子文件夹中,然后告诉导轨从您的environment.rb文件中的所有子文件夹中加载文件:

 config.load_paths += Dir["#{RAILS_ROOT}/app/models/*"].find_all { |f| File.stat(f).directory? } 

不需要命名空间,模型可以在您的应用程序中被称为正常

我也创build了子文件夹,然后将以下内容添加到application.rb文件中:

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

但是,如果子文件夹使用与模型相同的名称进行命名(例如,包含多个文件(其中之一是“用户”)的文件夹“用户”),那么仅仅这样做是不够的。 这导致了我的代码中的各种错误,直到我发现它可以通过简单地给与它们包含的模型(例如,“用户模型”)不同的文件夹名称来解决。 我在http://www.williambharding.com/blog/technology/rails-3-autoload-modules-and-classes-in-production/上find了这个build议,这个build议实际上指向了这个问题。;

所以我曾经在Rails 2中这样:

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

以下文件:

  • app / models / user / base.rb: class User::Base
  • app / models / user / admin.rb: class User::Admin

当我升级到Rails 3时,我不断收到这样的错误: Expected .../app/models/user/foo.rb to define Foo 。 这显然是疯狂的,因为Rails 2自动假定你放在user / foo.rb中的将是User::Foo而不仅仅是Foo

所以我最终解决这个问题的方式是摆脱autoload_paths的模型子目录并执行如下操作:

我创build了app / models / user.rb:

 module User autoload :User, 'user/base' autoload :User, 'user/admin' end 

也许你可以看看RailsEngines。 这不完全是你所需要的,但可以给你一些想法。

除此之外,如果你的脚本似乎工作正常(你也可以只读模型上的每个子文件夹中的所有文件,并要求他们),我没有看到任何问题。

这个版本的Tilendor的解决scheme适用于Rails 3

config.load_paths和RAILS_ROOT在Rails 3中被弃用,你也应该把它放在config / application.rb的configuration块中,而不是environment.rb

 config.autoload_paths += Dir["#{Rails.root.to_s}/app/models/*"].find_all { |f| File.stat(f).directory? } 

在我的Rails 3.2.3应用程序中,在将一些模型移动到子目录之后,我偶然发现了类似的错误

 Expected /.../.../app/models/project/project_category.rb to define Project::ProjectCategory 

用于关联调用(例如:Project.first.project_category)。

最后,我发现的解决方法是设置:class_name为每个关联在子目录中build模…

 class Project < ActiveRecord::Base belongs_to :project_category, :class_name => "::ProjectCategory" end 

这里的“::”部分指向Rails,尽pipe在'models / project'子目录中定义了事实,但ProjectCategory模型没有名称空间。

这在Rails 5中适用于我。

将以下内容添加到application.rb

 config.autoload_paths += Dir[ Rails.root.join('app/models/**/') ] 

但是要小心,你的文件夹不能和你的任何模型有相同的名字。

直到find更好的解决scheme,我在app / models文件夹中创build了一个init.rb:

应用程序/模型/ init.rb

 %w[blog].each do |folder| path = [File.dirname(__FILE__), folder, "*.rb"].join('/') Dir[path].each {|file| require file } end 

服务器到目前为止的目的。

以上所有的答案都不适合我。 不知何故,“模型”文件夹加载子文件夹,导致“预期包含::。

我的大部分Subdirs都是STI类的,所以我把它们移到了app / models_sti // *。 然后,我需要做的就是把application.rb

 #config.autoload_paths += Dir["#{Rails.root.to_s}/app/models/**/"] # Loaded dynamically (cache_classes == false ?) config.autoload_paths << Rails.root.join('app', 'models').to_s config.autoload_paths += Dir["#{Rails.root.to_s}/app/models_sti/*"].find_all { |f| File.stat(f).directory? } # Eager_load_paths - used only when cache_classes == true [rails spec says so] config.eager_load_paths.delete_if do |path| # If I didn't delete it from eager_load_paths I got errors even in develop path == Rails.root.join('app', 'models_sti').to_s end config.eager_load_paths += config.autoload_paths