更新范围内的关系?

Fis*_*ter 5 ruby activerecord ruby-on-rails

我怎么能有像 ActiveRecordscope这样的东西来修改它所作用的关系?

具体来说,我希望能够做到这一点:

Model.some_scope.fake_destroy_all
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

但这并不理想。我想做的是:

scope :fake_destroy_all, update_all(deleted: true)
Run Code Online (Sandbox Code Playgroud)

但这不起作用。

是否有可能做我所描述的事情?

D-s*_*ide 4

尝试这个:

def self.fake_destroy_all
  self.update_all(deleted: true)
end
Run Code Online (Sandbox Code Playgroud)

事实证明,关系保留了所有类方法。作用域也是类方法,它是允许作用域“链接”的确切机制。

因此,与该模型的关系也将具有self作为关系实例的该方法。

范围语法可能可以像这样修复(现在无法测试,但请注意 lambda 而不是简单的方法调用):

scope :fake_destroy_all, -> { update_all(deleted: true) }
Run Code Online (Sandbox Code Playgroud)

我想,如果不更新 lambda 内部,它会在调用类定义时有效地调用此方法scope。它确实适用于 simplewhere类型范围,因为where没有副作用,它只返回一个适用的过滤器。它被评估一次并保存在方法中以供将来按原样使用。

然而,对于 lambda,执行会一直保持到实际应用范围为止,而不是定义之前。这是必要的,因为update_all确实有副作用

如果您指定条件不断变化的范围(最简单的情况是依赖于 ),则同样的技巧很有用,Time.now它会随着时间的推移而变化,并且每次都需要重新评估。

但是,我建议您使用类方法:作用域更像是过滤器,而这更像是“过滤器执行”。虽然这也可能有效,但范围在语义上适用于不同的用例。