如果我有一个带有lambda的范围并且它接受一个参数,根据参数的值,我可能知道不会有任何匹配,但我仍然想要返回一个关系,而不是一个空数组:
scope :for_users, lambda { |users| users.any? ? where("user_id IN (?)", users.map(&:id).join(',')) : [] }
我真正想要的是一种“无”方法,与“所有”相反,它返回一个仍然可以链接的关系,但会导致查询被短路。
答案 0 :(得分:433)
Rails 4中现在有一个“正确”的机制:
>> Model.none
=> #<ActiveRecord::Relation []>
答案 1 :(得分:75)
更便携的解决方案,不需要“id”列,并且不会假设不会有id为0的行:
scope :none, where("1 = 0")
我仍然在寻找一种更“正确”的方式。
答案 2 :(得分:43)
在Rails 4中,可以通过ActiveRecord::NullRelation
之类的调用返回可链接的Post.none
。
它和链式方法都不会生成对数据库的查询。
根据评论:
返回的ActiveRecord :: NullRelation继承自 关系并实现Null对象模式。它是一个对象 定义了null行为,并始终返回一个空的记录数组 没有查询数据库。
请参阅source code。
答案 3 :(得分:42)
您可以添加名为“none”的范围:
scope :none, where(:id => nil).where("id IS NOT ?", nil)
这会给你一个空的ActiveRecord :: Relation
您也可以在初始化程序中将其添加到ActiveRecord :: Base(如果需要):
class ActiveRecord::Base
def self.none
where(arel_table[:id].eq(nil).and(arel_table[:id].not_eq(nil)))
end
end
有很多方法可以获得这样的东西,但肯定不是保留在代码库中的最佳方法。我使用范围:无重构时发现我需要保证一个空的ActiveRecord :: Relation很短的时间。
答案 4 :(得分:24)
scope :none, limit(0)
是一种危险的解决方案,因为您的范围可能会受到限制。
User.none.first
将返回第一个用户。使用
更安全scope :none, where('1 = 0')
答案 5 :(得分:14)
我认为我更喜欢这种方式与其他选项的对比:
scope :none, limit(0)
导致类似这样的事情:
scope :users, lambda { |ids| ids.present? ? where("user_id IN (?)", ids) : limit(0) }
答案 6 :(得分:3)
使用范围:
scope :for_users, lambda { |users| users.any? ? where("user_id IN (?)", users.map(&:id).join(',')) : scoped }
但是,您也可以使用以下方法简化代码:
scope :for_users, lambda { |users| where(:user_id => users.map(&:id)) if users.any? }
如果您想要一个空结果,请使用它(删除if条件):
scope :for_users, lambda { |users| where(:user_id => users.map(&:id)) }
答案 7 :(得分:1)
还有变体,但所有这些都向db
发出请求where('false')
where('null')
答案 8 :(得分:1)
这是可能的,所以
:scope :for_users, lambda { |users| users.any? ? where("user_id IN (?)", users.map(&:id).join(',')) : User.none }
http://apidock.com/rails/v4.0.2/ActiveRecord/QueryMethods/none
如果我错了,请纠正我。