我能够得到我想要的行为,如果我创建一个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.something
和foo.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