Ruby on Rails 中空作用域问题

18
以下问题:
我需要类似于空作用域的东西。这意味着该作用域为空,但响应所有通常响应的作用域方法。 我目前使用一种有点不干净的技巧。我只需提供“1=0”作为条件。我觉得这真的很丑陋,因为它会访问数据库。仅返回一个空数组是行不通的,因为结果必须响应作用域方法。
是否存在更好的现有解决方案,还是我需要自己编写代码?
也许一些示例代码可以帮助解释我需要什么:

class User < ActiveRecord::Base
  named_scope :admins, :conditions => {:admin => true }
  named_scope :none_dirty, :conditions => "1=0" # this scope is always empty

  def none_broken
    []
  end

  def self.sum_score # okay, a bit simple, but a method like this should work!
    total = 0
    self.all.each do |user|
      total += user.score
    end
    return total
  end
end
User.admin.sum_score # the score i want to know
User.none_drity.sum_score # works, but hits the db
User.none_broken.sum_score # ...error, since it doesn't respond to sum_score

一个空集的分数为什么会不是0?你在这里想要实现什么? - jdl
1
您正在寻找一个空集合。 - Swanand
@jdl:它不会是除了0以外的东西。 - Baju
7个回答

25

Rails 4引入了none作用域。

它适用于当您有一个返回关系的方法,但存在一种情况,您不希望查询数据库时使用它。

如果您想要一个范围返回未更改的范围,请使用all

在Rails 4中,调用Model.all不再立即执行查询并返回记录数组。现在,调用Model.all等同于已弃用的Model.scoped。这意味着可以将更多关系链接到Model.all并且结果将被惰性地评估。


11
User.where('false')

返回一个具有零个元素的 ActiveRecord::Relation,它是一个可链式调用的范围,只有在您实际尝试访问其元素之一时才会触发数据库查询。这类似于 PhilT 的解决方案 ('1=0'),但更加优雅。


2

抱歉,User.scoped 不是您想要的内容。正如评论所述,这将返回所有内容。应该更加关注问题。

我之前见过建议使用 where('1 = 0'),Rails 也应该缓存它。

此外,where('1 = 0') 不会在您执行 .all.each 或其中一个计算方法之前访问数据库。


1
User.scoped 返回所有用户,因此它并不是真正的“空”范围。我认为他的意思是一个返回零个用户的空范围。有点类似于[]但是一个范围。 - Brian Armstrong

0

那么 User.where(id: nil) 怎么样?

或者对于 mongoid,使用 User.where(_id: nil)


这仍然会访问数据库,而且不可靠(特别是对于遗留的、非 Rails 数据库,可能存在一个空 id 字段的记录)。 - PhilT

0

我认为你需要使用User.scoped({})


User.scoped({})User.all 相等吗? - Swanand
@Swanand:它们不是等价的,scoped 返回一个惰性的 ActiveRecord::NamedScope::Scope,而 User.all 返回一个数组。 - tokland

0

您正在寻找的内容不存在。您可以通过猴子补丁find方法来实现类似的功能。然而,这将是一种过度设计,因此我建议除非性能关键,否则保留此内容。


-1

嗯,不,和是只是上面提到的一个例子。 - Baju

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接