如果我有一个带有 lambda 的作用域并且它需要一个参数,根据参数的值,我可能知道不会有任何匹配项,但我仍然想返回一个关系,而不是一个空数组:
scope :for_users, lambda { |users| users.any? ? where("user_id IN (?)", users.map(&:id).join(',')) : [] }
我真正想要的是一个“none”方法,与“all”相反,它返回一个仍然可以链接的关系,但会导致查询短路。
Rails 4 现在有一个“正确”的机制:
>> Model.none
=> #<ActiveRecord::Relation []>
一个更便携的解决方案,不需要“id”列,并且不假设不会有 id 为 0 的行:
scope :none, where("1 = 0")
我还在寻找更“正确”的方式。
在 Rails 4 中,可链接的
ActiveRecord::NullRelation
将从像 Post.none
这样的调用中返回。
它和链式方法都不会生成对数据库的查询。
根据评论:
返回的ActiveRecord::NullRelation继承自 关系并实现空对象模式。它是一个对象 定义空行为并始终返回空记录数组 无需查询数据库。
查看源代码。
您可以添加一个名为“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
有很多方法可以得到这样的东西,但肯定不是保留在代码库中的最好方法。 我在重构时使用了范围 :none 并发现我需要在短时间内保证一个空的 ActiveRecord::Relation 。
scope :none, limit(0)
这是一个危险的解决方案,因为你的范围可能会被束缚。
用户.none.first
将返回第一个用户。使用更安全
scope :none, where('1 = 0')
我想我更喜欢它的外观而不是其他选项:
scope :none, limit(0)
导致这样的事情:
scope :users, lambda { |ids| ids.present? ? where("user_id IN (?)", ids) : limit(0) }
使用范围:
范围:for_users,lambda { |用户|用户.有吗? ? where("user_id IN (?)", users.map(&:id).join(',')) : 范围 }
但是,您也可以使用以下方法简化代码:
范围:for_users,lambda { |用户| where(:user_id => users.map(&:id)) if users.any? }
如果你想要一个空结果,请使用这个(删除 if 条件):
范围:for_users,lambda { |用户|其中(:user_id => users.map(&:id)) }
还有变体,但所有这些都向数据库发出请求
where('false')
where('null')
这是可能的,所以:
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
如果我错了请纠正我。