Rails 基于模型名称的命名空间问题

Rails namespacing concerns based on model name

我正在寻找针对特定于模型的某些功能子集的关注点。 我引用了 here 并遵循了这个模式

module ModelName::ConcernName
  extend ActiveSupport::Concern

  included do
    # class macros
  end

  # instance methods
  def some_instance_method

  end

  module ClassMethods
    # class methods here, self included
  end
end

但是,当我尝试启动服务器时会导致以下错误

Circular dependency detected while autoloading constant ModelName::ConcernName

我想知道对模型的某些子集函数进行关注的最佳方法是什么。

编辑

提供型号代码: 路径:app/models/rent.rb

现在我的模型中有很多检查逻辑

class Rent < ActiveRecord::Base
    def pricing_ready?
        # check if pricing is ready
    end

    def photos_ready?
        # check if photo is ready
    end

    def availability_ready?
        # check if availability setting is ready
    end

    def features_ready?
        # check if features are set
    end
end

我想分开关注

class Rent < ActiveRecord::Base
    include Rent::Readiness
end

并按命名空间组织关注点 路径:app/models/concerns/rent/readiness.rb

module Rent::Readiness
  extend ActiveSupport::Concern

  included do
    # class macros
  end

  # instance methods
  def pricing_ready?
    # check if pricing is ready
  end

  ...

  module ClassMethods
    # class methods here, self included
  end
end

现在如果我用 app/models/concerns/rent_readiness.rb

中的路径 class RentReadiness 就可以正常工作了

Rails 使用 activesupport 加载 classes 和模块,因为它们是通过根据 class 或模块名称推断文件路径来定义的,这是作为 Ruby 解析器加载您的文件并遇到一个尚未加载的新常量。在您的情况下,Rent 模型被​​解析为 Rent::Readlines 引用,此时 activesupport 开始寻找与名称匹配的 rent/readlines.rb 代码文件。然后这个文件被 ruby 解析,但是在第一行,仍然未加载的 Rent class 被引用,这会触发 activesupport 关闭并寻找匹配的代码文件名字.

您可以将其范围限定为 Rents 并放置到 concerns/rents/readiness.rb:

module Rents
  module Readiness
    extend ActiveSupport::Concern

    included do
      # class macros
    end
  end
end

在模型中:

class Rent < ActiveRecord::Base
  include Rents::Readiness
end

您只需将包含模型特定问题的文件夹从 concerns 移动到 models 即可使其正常工作。所以,你会:

models/
    rent.rb
    rent/
        readiness.rb   

我喜欢这种使用模型作为其关注点的名称空间的约定,因为它可以让您从代码中删除一些冗余:

  • 由于您是在模型 class 中定义关注点,因此您可以在模型中编写 include Readiness 而不是 include Rent::Readiness
  • 定义关注点时,可以使用module Rent::Readiness代替

    class Rent < ApplicationRecord
         module Readiness
    ...
    

    这将是解决您在问题中提到的循环依赖问题的另一种方法。