【问题标题】:Elegant way to structure models into subfolders without creating submodules在不创建子模块的情况下将模型构建到子文件夹中的优雅方式
【发布时间】:2009-09-18 15:38:05
【问题描述】:

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

例如

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

这样:

app/models/blog/post.rb

class Post < ActiveRecord
end

而不是

class Blog::Post < ActiveRecord
end

【问题讨论】:

  • 添加到 config/application.rb config.autoload_paths += Dir[ Rails.root.join('app', 'models', "blog", '**/') ]

标签: ruby-on-rails activerecord


【解决方案1】:

这是我用于 Rails 3 的内容:

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

此配置告诉 Rails 递归扫描所有 app/models 子文件夹并加载所有找到的模型。不需要命名空间。

【讨论】:

  • 这对我来说不是递归的。相反,我使用: Dir[ Rails.root.join('app', 'models', '**/') ]
  • 这很奇怪,因为我在几个项目中使用它并且它为我递归地工作。你的 Ruby/RoR 版本是多少?
  • 如果我有更多的嵌套子文件夹,例如“app/models/user/premium/”,我该怎么办?
  • 它在 activerecord 关联中不起作用。您可以调用 Post 和 Comment,但不能调用 Post.first.cmets。有什么想法吗?
  • freshfunk 的评论+1。如果您使用 JohnZ 的答案,您还可以在顶级目录中添加纯文件,例如在应用程序/模型中
【解决方案2】:

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

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

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

不需要命名空间,模型可以在您的应用中正常引用

【讨论】:

  • 还没有进入 Rails 3 :(
  • 这适用于 Rails 3。修改 config/application.rb:将 app/models/ 添加到 autoload_paths - 不需要命名空间
  • 代码高尔夫:config.load_paths += Dir["#{Rails.root}/app/models/*/**/"]
  • 对我不起作用。 “模型”文件夹仍然以某种方式加载了子文件夹,这导致“预期 包含 ::
【解决方案3】:

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

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

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

【讨论】:

  • 至少在 Rails 4 中,这条线似乎不起作用,直到我将 config.root 更改为 Rails.root
  • 啊,是的,这是一个很好的陷阱。那里的参考将其标识为深奥:“您在子目录中有一个模型,其中子目录的名称与模型的名称匹配”。但是,我刚刚发生了这种情况,因为我有一个在变形器中定义为相同单数和复数的模型。我对像 users/user.rb 和 posts/post.rb 这样的路径很好。但在这种情况下,我有 series/series.rb,导致了问题。而且问题仅出在一个文件上并不是很明显。重命名为 series_models/series.rb 有效。
【解决方案4】:

所以我曾经在 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 中的模型子目录并执行以下操作:

我使用以下命令创建了 app/models/user.rb:

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

【讨论】:

    【解决方案5】:

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

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

    【讨论】:

      【解决方案6】:

      此版本的 Tilendor 解决方案适用于 Rails 3

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

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

      【讨论】:

      • config.autoload_paths += Dir["#{Rails.root.to_s}/app/models/**/"] 更简洁一些
      【解决方案7】:

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

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

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

      最后,我找到的解决方法是为每个关联设置 :class_name 以在子目录中建模...

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

      "::" 这里的部分指向 Rails,ProjectCategory 模型没有命名空间,尽管事实上它是在 'models/project' 子目录中定义的。

      【讨论】:

        【解决方案8】:

        这在 Rails 5 中对我有用。

        将以下内容添加到application.rb

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

        请注意,您的文件夹中的名称不能与任何模型的名称相同。

        【讨论】:

          【解决方案9】:

          在找到更好的解决方案之前,我在 app/models 文件夹中创建了一个 init.rb:

          app/models/init.rb

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

          直到现在为止的目的。

          【讨论】:

          • 这是否会为每个请求重新加载模型?
          【解决方案10】:

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

          我的大部分子目录都是 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
          

          【讨论】:

            猜你喜欢
            • 2012-03-19
            • 2014-01-31
            • 1970-01-01
            • 1970-01-01
            • 2017-02-28
            • 1970-01-01
            • 1970-01-01
            • 2017-02-10
            • 1970-01-01
            相关资源
            最近更新 更多