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



我能够得到我想要的行为,如果我创建一个Foo类,一些STI类继承它(Foo1, Foo2等),然后添加不同的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这样的参数,但我可能错了。

还有别的办法吗?

STI是这样做的正确方法。一般认为,任何特定的模型类都应该与其他记录具有定义良好且一致的关系。

如果您的关系只适用于特定类型的记录,这正是STI的作用:创建一个子类来定义这些关系。

你经常看到这种情况。例如,"家长"one_answers"学生"都是基本类型"人",但是学生有一个belongs_to: parent关联,家长有一个has_many: children关系。

当然,这假定父母不太可能成为学生,而学生也不可能成为父母,这一假定可能是不正确的。无论你做什么假设,我希望你认真思考一下这些限制是相关的,还是只是过于偏执。

在记录上切换类型通常是不好的,即使技术上可以这样做。如果你认为这是非常必要的,你可以使用它来调整一个记录的关系是如何定义的。

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

用这种方式覆盖您的bars方法可能会让您满意?这个super只是返回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

最新更新