【问题标题】:How to structure namespaced modules如何构建命名空间模块
【发布时间】:2016-01-29 15:32:17
【问题描述】:

我在 Rails 引擎 gem 上下文中查找 Ruby 类(常量)时遇到问题。

我有一个作为 Rails 引擎的 gem MyGem。它定义了预期会被 MainApp 覆盖的非命名空间模型,这些模型将包括 gem 和命名空间模块,这些模块包含在 gem 和 main_app 的模型中,以具有定义可重用代码的 DRY 方式。

这是一个示例代码结构:

两个模型

# in /app/models/user.rb        
class User < ActiveRecord::Base
  include MyGem::User::CommonExt
end

# in /app/models/comment.rb        
class Comment < ActiveRecord::Base
  include MyGem::Comment::CommonExt
end

他们的两个模块

# in /app/models/concerns/my_gem/user/common_ext.rb
module MyGem::User::CommonExt
  def load_comment(id)
    return Comment.find(id)
  end
end

# in /app/models/concerns/my_gem/comment/common_ext.rb
module MyGem::Comment::CommonExt
  def load_user(id)
    return User.find(id)
  end
end

现在,如果我打电话

User.new.load_comment(1)

我收到undefined method #find for MyGem::Comment::Module

我想我理解为什么会发生这种情况 - 在 #load_comment 定义的上下文中,它在 MyGem 下命名,Comment 常量查找返回 MyGem::Comment,而不是更遥远的 ::Comment

我宁愿不必在每个模型实例前面加上 ::
是否有文件结构、模型/类定义或配置更改可以用来调用 Comment 返回模型 Comment,而不是 MyGem::Comment 模块?

【问题讨论】:

  • 问题:为什么要让 gem 包含 Rails 引擎,而不是将共享(可重用)功能定义为常规抽象类,派生自 ActiveRecord::Base,在你的 gem 中?
  • 抽象类可能足以管理模型代码,但我需要整个生态系统,尤其是迁移。

标签: ruby-on-rails-4 rubygems rails-engines


【解决方案1】:

在这种情况下,我会使用继承而不是 mixin。

因此,在您的 gem/engine 中,您可以定义类似这样的通用类:

module MyGem
  module Common
    class Base < ActiveRecord::Base
      # common functionality goes here
      def load(record_type, id)
        record_type.find(id)
      end
    end
  end
end

然后在您的main_app 代码中:

class User < MyGem::Common::Base
  ...
end

现在你可以这样做了:

User.new.load(Comment, 1)

这违反了Law of Demeter,但希望它能说明这一点。

这样做是 DRY 并且具有额外的好处,它可以防止您的 gem 必须了解它自己范围之外的类。

【讨论】:

    猜你喜欢
    • 2020-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-31
    • 2014-01-26
    • 1970-01-01
    • 1970-01-01
    • 2014-02-12
    相关资源
    最近更新 更多