0

我有一个 Rails 项目,它实现了许多独立的引擎。

  1. 主引擎(始终存在)
  2. 扩展引擎#1(扩展主引擎的可选插件)
  3. 扩展引擎#2(扩展主引擎的可选插件)
  4. 等等。

长话短说,我需要扩展引擎来添加与主引擎模型有关系的模型。

扩展不应该修改任何其他引擎的物理表,但是扩展没有理由不能创建自己的表来充当连接表来引用主引擎的表。

为了简单起见,下面说明了我要做什么。

主引擎

.../app/models/models/user.rb

module PrimaryEngine
    User < ActiveRecord::Base
    End
end

车辆发动机

# .../vendor/engines/vehicle_engine/app/models/vehicle.rb
module VehicleEngine
    Vehicle < ActiveRecord::Base
    End
end

# .../vendor/engines/vehicle_engine/config/initializers/user_extension.rb
...
PrimaryEngine::User.class_eval do 
    has_one :vehicle, :through => :vehicle_engine_users_vehicles
end
...

我需要使用连接表的唯一原因是因为我不能(不应该)修改主引擎的 primary_engine_user表。通常,您只需向表中添加一个新列primary_engine_user,即primary_engine_user.vehicle_id.

问题是,我不想为:through =>零件创建一个模型,因为该连接表中没有我需要向其公开功能的任何内容。

CREATE TABLE vehicle_engine_users_vehicles
(
  primary_engine_user_id integer NOT NULL,
  vehicle_id integer NOT NULL
)

我想知道是否有一种方法可以has_onehas_and_belongs_to_many,其中推断连接表但不需要指定?

谢谢!

澄清更新:

APrimaryEngine::User可以有 1 辆车,但VehicleEngine::Vehicle可以有许多不同的用户。

4

2 回答 2

1

因此,我认为您要问的不是推断出通过(因为 has_and_belongs_to_many 推断出通过),而是在没有模型的情况下使用链接表。

我不这么认为。当使用 :through 选项时,ActiveRecord 会转到 :through 中指定的关联,然后转到该关联的模型(因此,通过关联和通过模型都需要存在)。

继续创建空模型。它不会造成太大的问题。

于 2013-02-25T18:34:24.543 回答
0

我想知道是否有办法让 has_one 像 has_and_belongs_to_many 一样工作,其中推断连接表但不需要指定?

如果您有一对一的关系,您可能不需要连接表,因为您只需在任一表中都有一个外键就可以做到这一点。但是,你说你不能做外键。

如果您知道以后需要切换到一对多或多对多,那么您可能会使用具有 id 列的成熟连接模型。(一般规则是 HABTM 适用于只有两列的连接表 - 要连接的表的两个外键,否则连接表将成为一个模型,您可以通过该模型执行 has_many 等. 根据需要。)这就是@Marlin_Pierce 所说的。

要使 has_one 像一个单一的 HABTM 一样,您将覆盖它的默认行为,这会让其他人感到困惑。不要这样做。

所以,我建议只在模型中添加额外的方法,让它更像一个 has_one:

has_and_belongs_to_many :vehicles

def vehicle
  vehicles.first
end

def vehicle=(vehicle)
  vehicles = vehicle ? [vehicle] : []
end

如果关系有效,即使没有返回任何行,HABTM 和 has_many 也总是返回一个空数组,因此您不需要try在 getter 中执行 a 或检查 nil。

但是,更多地考虑这一点,我认为你真正想要的是has_one :vehicle, through: :vehicle_engine_users_vehicle。这需要一个连接模型,但它是执行您想做的事情的“rails 方式”,并在指南中进行了描述。然后,如果您正在编写一个 gem 来执行此操作,为了在需要时使其更容易,您可以编写生成器来创建连接模型和相关的迁移。

于 2013-02-25T18:45:18.840 回答