如何使用联接 table/model 在两个模型之间创建“has_one”关系?

How does one create a `has_one` relationship between two models using a join table/model?

TL;DR: 如何使用 through [=72= 创建 has_one 关联 ]join table 反之亦然 belongs_to through?

上下文:我有两个模型,ProcessLogEncounterProcessLog,顾名思义,保存外部进程(多次运行)的单个运行(对应数据库中的一行)的日志。另一方面,Encounter 是一个跟踪某些信息 X 的模型。Encounters 可以在内部生成,也可以作为前面提到的外部过程成功执行的结果生成。它意味着 not all Encounters 有关联的 ProcessLognot all ProcessLogs有关联的 Encounter。但是,如果 ProcessLog 对应 Encounter,则这是 1:1 关系 。一个 Encounter 不能 有多个 ProcessLog,一个 ProcessLog 不能属于多个 Encounter。从数据库设计的角度来看,这是一个 optional relationship(我希望我没有忘记我的教训)。在数据库中,这将使用连接 table 和 encounter_id 作为 主键 process_log_id 作为 外键来建模钥匙.

Rails:在 Rails 中,1:1 关系通常建模 使用加入 table 和 belongs_to table 通常有一个 外键 到另一个 table。所以在我的例子中,这将是 encounter_id in process_logs table.

问题:使用has_onebelongs_to的传统Rails方法,这将导致process_logs中有很多行table encounter_id 列的 NULL 值。现在 Rails 对这种方法有利有弊,但是,我无意在此讨论。是的,它将保持 table 结构简单,但是,在我的例子中,它破坏了语义并且还引入了许多 NULL 值,我认为这不是一个好的方法。这也是可选关系存在连接 table 的原因。

到目前为止我做了什么?:关于这个主题我找不到很多有用的文档,除了以下两个链接文档,尽管它们有他们自己的问题,不解决我的问题。

  1. SO Question 这里的方法是使用 has_many 作为连接模型,而我只有一个

  2. Discussion on RoR 同样,它正在使用 has_many,但不知何故谈论 has_one

我创建了一个名为 EncounterProcessLog 的连接模型(ProcessLogEncounter 都有 belongs_to),然后在另外两个上创建了 has_one ..., through:模型,但 Rails 正在寻找多对多关联,当然也在 process_logs table.

上寻找 encounter_id

问题:如何才能达到我想要达到的目的?下面的(非工作)代码行:

class Encounter:
    has_one :process_log, through: :encounter_process_logs

class ProcessLog:
    belongs_to :encounter, through: :encounter_process_logs # This may be incorrect way of specifying the relationship?

class EncounterProcessLog:
    belongs_to :encounter
    belongs_to :process_log # May be this should be a has_one?

我希望有人能够指导我正确的方向。感谢您到目前为止的阅读。

我能想到的一种方法是:

class Encounter:
  has_one :encounter_process_log
  has_one :process_log, through: :encounter_process_log

class ProcessLog:
  has_one :encounter_process_log
  has_one :encounter, through: :encounter_process_log

class EncounterProcessLog:
  belongs_to :encounter
  belongs_to :process_log

这将 return process_log 用于 encounter,反之亦然,这可能正是您想要的。