如何有条件地包含关联定义?

How to conditionally include association definitions?

如果我创建一个 Foo class,一些继承它的 STI classes(Foo1、Foo2 等)然后到为每个 class 添加不同的 has_many :bars 关联。例如:

class Foo < ApplicationRecord
  has_many :bars
end

class Foo1 < Foo
  has_many :bars, -> { where(user_id: 1) }
end

我希望能够在对象上调用 bars 并根据对象的状态获得不同的关联行为。这行得通,但是有没有办法在不设置 STI 的情况下做到这一点?

我尝试在 foo.rb 中执行所有操作,但我似乎正在加载我的第一个 has_many :bars 定义,即使我这样做也是如此:

has_many :bars ... if some_method_returning_boolean?
has_many :bars ... if some_other_method_returning_boolean?

即使这确实有效,它似乎也有点笨拙。

我也考虑过作用域,但据我了解作用域然后我不得不调用 foo.bars.somethingfoo.bars.something_else 而不是依赖对象的状态 foo 来给我 foo.bars 不同的。此外,范围似乎只涵盖了 has_many 定义的一部分,但不能修改 :source:foreign_key 等参数,但我可能错了。

还有其他方法吗?

也许您会满意以这种方式覆盖您的 bars 方法? super 只是 return 来自 something_foo.bars 的通常结果。

class Foo
    def bars
      super.where(something: something_value) if your_condition
      super.where(something_else: something_value) if other_condition
    end
end

STI 是执行此操作的正确方法。人们普遍认为,任何特定模型 class 都应该与其他记录具有 well-defined 和 一致的 关系。

如果您的关系仅适用于某些类型的记录,而这正是 STI 的用途:创建一个定义这些关系的子class。

你经常看到这个。一个例子是 "Parent" 和 "Student" 都是基本类型 "Person",但是学生有一个 belongs_to: parent 关联,而 parents 有一个 has_many: children关系。

当然这个假设parents不太可能成为学生,而学生parents,这个假设未必正确。无论您做出何种假设,我都希望您认真考虑一下这些限制是相关的还是过于偏执。

尽管在技术上可以做到,但在记录上切换类型通常是一种错误的形式。如果您认为这是绝对必要的,您可以使用它来调整记录关系的定义方式。

一般来说,我建议您坚持一致的关系结构。那些不应该与任何东西相关的记录不需要那些物理删除的方法,它们可以在那里而不做任何有用的事情。无论如何,他们都是免费的。