如果我有一个带有 lambda 的范围并且它需要一个参数,这取决于参数的值,我可能知道不会有任何匹配项,但我仍然想返回一个关系,而不是一个空数组:
scope :for_users, lambda { |users| users.any? ? where("user_id IN (?)", users.map(&:id).join(',')) : [] }
我真正想要的是一个“无”方法,与“全部”相反,它返回一个仍然可以链接的关系,但会导致查询短路。
如果我有一个带有 lambda 的范围并且它需要一个参数,这取决于参数的值,我可能知道不会有任何匹配项,但我仍然想返回一个关系,而不是一个空数组:
scope :for_users, lambda { |users| users.any? ? where("user_id IN (?)", users.map(&:id).join(',')) : [] }
我真正想要的是一个“无”方法,与“全部”相反,它返回一个仍然可以链接的关系,但会导致查询短路。
Rails 4 现在有一个“正确”的机制:
>> Model.none
=> #<ActiveRecord::Relation []>
一种更便携的解决方案,它不需要“id”列并且不假设不会有 id 为 0 的行:
scope :none, where("1 = 0")
我仍在寻找更“正确”的方式。
在 Rails 4 中,一个可链式ActiveRecord::NullRelation
调用将从像Post.none
.
它和链式方法都不会生成对数据库的查询。
根据评论:
返回的 ActiveRecord::NullRelation 继承自 Relation 并实现 Null Object 模式。它是一个定义了空行为的对象,并且总是返回一个空的记录数组而不查询数据库。
请参阅源代码。
您可以添加一个名为“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)
是一个危险的解决方案,因为您的范围可能会受到束缚。
User.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 { |users| users.any? ? where("user_id IN (?)", users.map(&:id).join(',')) : scoped }
但是,您还可以通过以下方式简化代码:
范围 :for_users, lambda { |users| where(:user_id => users.map(&:id)) 如果 users.any?}
如果您想要一个空结果,请使用它(删除 if 条件):
范围 :for_users, lambda { |users| 其中(:user_id => users.map(&:id)) }
也有变种,但所有这些都在向 db 发出请求
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
如我错了请纠正我。