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;博士
- cd 进入引擎的虚拟应用根目录
- 运行
rails g model User
- 运行
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]
.
我正在尝试制作一个 Rails 引擎,它可以插入我的应用程序并管理用户之间的友谊。为此,处理好友请求、接受等的所有逻辑都将存在于 Rails 引擎中。
当我创建 Friendship
模型时,它需要两个 Users
(两个朋友)的 belongs_to
关系。但是,我不想将用户绑定到该引擎。我希望此引擎能够与应用程序已建立的任何 User
通用。
人们使用什么技术来创建一个永远不会包含在主机应用程序中的虚拟 User
? (我想避免迁移这个虚拟 User
中的引擎。)
更新:
我删除了第二个问题,关于如何使用主机应用程序的 User
覆盖引擎的 User
。我在指南中找到了答案 (http://edgeguides.rubyonrails.org/engines.html#configuring-an-engine)。
tl;博士
- cd 进入引擎的虚拟应用根目录
- 运行
rails g model User
- 运行
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]
.