Rails 引擎:为关系创建虚拟模型?

Rails Engine: Create dummy model for relations?

我正在尝试制作一个 Rails 引擎,它可以插入我的应用程序并管理用户之间的友谊。为此,处理好友请求、接受等的所有逻辑都将存在于 Rails 引擎中。

当我创建 Friendship 模型时,它需要两个 Users(两个朋友)的 belongs_to 关系。但是,我不想将用户绑定到该引擎。我希望此引擎能够与应用程序已建立的任何 User 通用。

人们使用什么技术来创建一个永远不会包含在主机应用程序中的虚拟 User? (我想避免迁移这个虚拟 User 中的引擎。)

更新: 我删除了第二个问题,关于如何使用主机应用程序的 User 覆盖引擎的 User。我在指南中找到了答案 (http://edgeguides.rubyonrails.org/engines.html#configuring-an-engine)。

tl;博士

  1. cd 进入引擎的虚拟应用根目录
  2. 运行rails g model User
  3. 运行 rake db:migrate

讨论

我来这里是为了寻找答案,但看到没有答案,我将分享我最终如何解决这个问题。

创建 mountable Rails 引擎时(通过 rails plugin new . --mountable --dummy-path=spec/dummy 之类的东西),Rails 将为您的引擎生成一个 "dummy" 应用程序,它将作为通常需要引擎的主要应用程序。

我们 RSpec 用户使用“--dummy-path”指令并将虚拟应用程序放在 /spec 文件夹中,但对您来说它可能在其他地方。找到它的位置并 cd 进入该虚拟应用程序的根目录。

进入虚拟应用程序后,调用 rails g model User 为虚拟应用程序生成用户模型。 运行 rake db:migrate 添加 table.

现在您有一个占位符 User 模型,它应该在测试中作为关联正常运行。
您可能想在 User 上定义一些模拟方法,在位于 /path/to/dummy/app/models/user.rb

的模型定义文件中执行此操作

自然地,您可以创建一个具有关联和逻辑的完整模型,而不仅仅是 dummy 中的占位符。

当应用程序中包含引擎时,不会使用虚拟应用程序中的迁移和代码,如 rake railties:install:migrations 所示。

这可能有点老套!

我有一个包含多个引擎的应用程序。每个引擎都需要在其他引擎中调用有限数量的功能。

例如,Engine1 和 Engine2 不依赖(要求或加载)彼此。但是,Engine1::User 等模型可能需要使用 Engine2::Department 模型中名为 all_active 的作用域来调用记录选择。这在两个引擎都作为 Gems 加载的整个 Rails 应用程序的上下文中是可以的。

当 Engine1 的开发人员想要 Engine2::Department.all_active 而他们没有时,问题就出现了。

我使用的解决方案是在 Engine2 的 test/dummy/app/models(或 spec/dummy/app/models,如果您使用 RSpec ) 文件夹。

像这样的东西将在 Engine1 中工作:

# spec/dummy/app/models/engine2/department.rb
require '../../app/models/engine2/department' if File.exist?('../../app/models/engine2/department')

module Engine2
  class Department
    unless Engine2::Department < ActiveRecord::Base
      def self.all_active
        [{ id: 1, name: 'Finance', active: true},
         { id: 2, name: 'Sales', active: true}]
      end
    end
  end
end

因为这个文件在虚拟应用程序中,它不会被主 Rails 应用程序找到,所以它不会干扰那里。它只会在开发和测试期间加载到虚拟 rails 应用程序中。

仅供参考,unless Engine2::Department < AR::Base 检测 Department 模型是否已经从 ActiveRecord 继承,如果是,则不会加载封闭代码。这是一种安全机制,可以防止 class 方法 all_active 被上面显示的散列中的硬编码样本数据覆盖。

如果您的系统中有很多引擎,也许您应该考虑创建一个 git 引擎模板的 repo,可以将其拉入每个引擎(包含公共代码等)。

您的示例数据可能受益于成为 OpenStruct 对象,因此可以使用点表示法访问您的散列键。然后,您可以编写 @engine2_departments.first.name 之类的代码,而不是 @engine2_departments.first[:name].