【问题标题】:Rails namespacing concerns based on model name基于模型名称的 Rails 命名空间问题
【发布时间】:2018-06-17 01:10:57
【问题描述】:

我希望针对特定于模型的某些功能子集分离关注点。 我引用了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

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

自动加载常量 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 中的路径进行RentReadiness 课程,我就可以正常工作了

【问题讨论】:

    标签: ruby-on-rails separation-of-concerns


    【解决方案1】:

    您可以将其范围限定为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
    

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 那我应该如何解决这个问题呢?
      • 首先,Rails 关注点模式的设计使得每个关注点都应该可用于任何模型,更新您的 readlines 关注点以实现这一点将首先消除对其命名空间的需要。否则,如果这确实是仅与 Rent 模型相关的逻辑,我可能会因此移动到 /lib 并将其重命名为 RentReadlines(它仍然可以使用关注扩展来帮助语法)
      • 将其移至 lib 的原因是什么?
      • 他的意思是:关注被应用于两个或多个模型。如果你想分离一个模型的具体方法,通常这样做的模式是将方法写入一个分离的类,放在/lib中,然后包含这个类就是模型。
      • 是的,正如@lcguida 指出的那样,将模型方法移出类的模式是将它们移到模块中,并将其放在/lib 中。使用/lib 的原因是什么? Rails 没有存储这些文件的默认位置,它们不适合 MVC,所以/lib 是次佳位置,因为其他程序员会明白它们是重要的代码文件,但它们不不适合标准 Rails 位置。当然,您可以将这些文件放在您喜欢的任何地方,但这会让新程序员更难理解您的项目意图。
      【解决方案3】:

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

      models/
          rent.rb
          rent/
              readiness.rb   
      

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

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

        class Rent < ApplicationRecord
             module Readiness
        ...
        

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

      【讨论】:

      • 感谢豪尔赫的精彩回答,它对我有用。这是您在 Basecamp 使用的目录结构类型吗?在 models 而不是 concerns 目录下的命名空间关注点?
      • 根据 DHH 的tweet,我相信上述问题的答案是肯定的。
      猜你喜欢
      • 2012-02-16
      • 1970-01-01
      • 2013-02-12
      • 2020-01-31
      • 1970-01-01
      • 2012-09-10
      • 2022-12-09
      • 2017-12-27
      • 2017-03-21
      相关资源
      最近更新 更多