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

时间:2016-03-27 04:58:07

标签: ruby-on-rails rails-engines

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

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

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

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

2 个答案:

答案 0 :(得分:3)

TL;博士

  1. cd into engine的dummy app root
  2. 运行rails g model User
  3. 运行rake db:migrate
  4. 讨论

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

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

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

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

    现在你有一个占位符User模型,它应该在测试中作为一个关联可以接受 您可能希望在User上定义一些模拟方法,在/path/to/dummy/app/models/user.rb

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

    当然,你可以创建一个带有关联和逻辑的完整模型,而不仅仅是假人中的占位符。

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

答案 1 :(得分:0)

这可能有点老套!

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

例如,Engine1 和 Engine2 不依赖(要求或加载)彼此。但是,诸如 Engine1::User 之类的模型可能需要使用 all_active 模型中名为 Engine2::Department 的范围调用一组记录。这在整个 Rails 应用的上下文中是可以的,两个引擎都作为 Gems 加载到其中。

当 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,如果是,则不会加载封闭代码。这是一种安全机制,可防止类方法 all_active 被上述哈希中的硬编码样本数据覆盖。

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

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