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

Chr*_*ung 4 ruby-on-rails separation-of-concerns

我希望将特定于模型的某些功能子集的关注点分开。我在此处引用并遵循此模式

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
Run Code Online (Sandbox Code Playgroud)

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

自动加载常量 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
Run Code Online (Sandbox Code Playgroud)

我想把它分开

class Rent < ActiveRecord::Base
    include Rent::Readiness
end
Run Code Online (Sandbox Code Playgroud)

并按命名空间路径组织关注点: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
Run Code Online (Sandbox Code Playgroud)

现在,如果我只是RentReadiness用路径上课,我就可以工作了app/models/concerns/rent_readiness.rb

hlc*_*lcs 6

您可以将其范围Rents和放置到concerns/rents/readiness.rb:

module Rents
  module Readiness
    extend ActiveSupport::Concern

    included do
      # class macros
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

在模型中:

class Rent < ActiveRecord::Base
  include Rents::Readiness
end
Run Code Online (Sandbox Code Playgroud)


jma*_*bia 5

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

models/
    rent.rb
    rent/
        readiness.rb   
Run Code Online (Sandbox Code Playgroud)

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

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

    class Rent < ApplicationRecord
         module Readiness
    ...
    
    Run Code Online (Sandbox Code Playgroud)

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


man*_*bot 3

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