更新范围内的关系?

时间:2014-09-04 20:23:48

标签: ruby-on-rails ruby activerecord

我怎样才能像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)

但这不起作用。

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

1 个答案:

答案 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的依赖,随着时间的推移而变化并且每次都需要重新评估,同样的技巧很有用。

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