我怎样才能像ActiveRecord scope
那样修改它所处理的关系?
具体来说,我希望能够做到这一点:
Model.some_scope.fake_destroy_all
fake_destroy_all
是我尝试创建的功能。它几乎等同于.update_all(deleted: true)
。
弱选择是:
def fake_destroy_all(relation = Model)
relation.update_all(deleted: true)
end
#...
Model.fake_destroy_all(Model.some_scope)
但那并不理想。我想做的是:
scope :fake_destroy_all, update_all(deleted: true)
但这不起作用。
是否有可能做出我所描述的事情?
答案 0 :(得分:3)
试试这个:
def self.fake_destroy_all
self.update_all(deleted: true)
end
事实证明,关系保留了所有类方法。范围也是类方法,它是允许范围被“链接”的确切机制。
因此,与此模型的关系也将使用self
作为关系实例的此方法。
范围语法可能会像这样修复(现在无法测试,但请注意lambda而不是简单的方法调用):
scope :fake_destroy_all, -> { update_all(deleted: true) }
我想,没有在lambda内部更新它在类定义上调用scope
时有效地调用了这个方法。它适用于简单的where
类型范围,因为 where
没有副作用,它只返回适用的过滤器。它被评估一次并保存在未来的使用方法中。
使用lambda ,执行将保持到实际应用范围,直到定义为止。这是必要的,因为update_all
确实有副作用。
如果要指定具有不断变化的条件的范围,最简单的情况是对Time.now
的依赖,随着时间的推移而变化并且每次都需要重新评估,同样的技巧很有用。
但是,我建议您使用类方法:范围更像是过滤器,而这更像是“过滤器实施”。虽然这可能也有效,但范围在语义上适用于不同的用例。