【问题标题】:if using a join table, does the relationship have to be HABTM?如果使用连接表,关系是否必须是 HABTM?
【发布时间】:2026-02-22 15:05:01
【问题描述】:

我在 Rails 2.x 中有 Worker、Manager 和 Title 模型。还有一个只有 worker_id、manager_id 和 title_id 的 JOIN 表(没有明确的模型)。由于这个 JOIN 表(并且没有模型),我假设我必须具备以下条件:

在 Worker 模型中,我有:

Worker
has_and_belongs_to_many :managers
has_and_belongs_to_many :titles

但实际上,Worker 只能有 1 个 Manager,但可以有多个 Title。此外,许多 Worker 拥有相同的 Manager。

一些示例数据来说明关系:

Worker | Title | Manager
Tom    | A     | M1
Tom    | B     | M1
Bob    | A     | M2
Pam    | C     | M1

上面的 Worker 模型“正确”吗?在创建一个新的 Worker(以及他们的所有关系)时,我会这样做:

worker = Worker.new("A")
title = "B"
manager = "C"
worker.titles << title
worker.managers << manager
worker.save

当我这样做时,我会在我的数据库中得到以下信息:

Worker | Title | Manager
A      | B     | null
A      | null  | C

我想得到:

Worker | Title | Manager
A      | B     | C

【问题讨论】:

  • 你说一个工人只能有1个经理,但可以有多个头衔。如果是这样,你为什么要将这两种类型的关系(具有不同的基数)放在同一张表中?

标签: ruby-on-rails join relationship has-and-belongs-to-many


【解决方案1】:

您可以移动 manager_id(因为 Worker 只能在 Manager 上拥有)并拥有这样的关系

class Manager < AR::Base
  has_many :workers
end

然后,在 Worker 中,belongs_to 一个 Manager。

class Worker < AR::Base
  belongs_to :manager
end

你需要有一个连接表,比如“workers_titles”来保存workers和titles之间的关系

create_table "workers_titles", :id => false do |t|
  t.column "worker_id", :integer, :null => false
  t.column "title_id",  :integer, :null => false
end

型号:

class Worker < AR::Base
  has_and_belongs_to_many :titles
end

class Title < AR::Base
  has_and_belongs_to_many :workers
end

【讨论】:

  • 如果我从上面执行 worker.save,它会(正确地)写入两个 JOIN 表吗?