如何返回一个空的ActiveRecord关系?
如果我有一个lambda函数的作用域,并且需要一个参数,取决于参数的值,我可能知道不会有任何匹配,但是我仍然想返回一个关系,而不是一个空的数组:
scope :for_users, lambda { |users| users.any? ? where("user_id IN (?)", users.map(&:id).join(',')) : [] }
我真正想要的是一个“无”方法,与“全部”相反,它返回一个仍然可以链接的关系,但导致查询被短路。
Rails 4中现在有一个“正确的”机制:
>> Model.none => #<ActiveRecord::Relation []>
一个更便携的解决scheme,不需要一个“ID”列,并不假设不会有一个ID为0的行:
scope :none, where("1 = 0")
我仍然在寻找更“正确”的方式。
你可以添加一个名为“none”的作用域:
scope :none, where(:id => nil).where("id IS NOT ?", nil)
这将给你一个空的ActiveRecord ::关系
你也可以将它添加到初始化器中的ActiveRecord :: Base(如果你想):
class ActiveRecord::Base def self.none where(arel_table[:id].eq(nil).and(arel_table[:id].not_eq(nil))) end end
有很多方法可以得到这样的东西,但是当然不是保存在代码库中的最好的东西。 我已经使用的范围:没有重构,发现我需要保证一个空的ActiveRecord ::关系短时间。
来到Rails 4
在Rails 4中,可链接的ActiveRecord::NullRelation
将从Post.none
调用中返回。
它既不是链式方法,也不会产生对数据库的查询。
根据评论:
返回的ActiveRecord :: NullRelationinheritance自Relation并实现Null Object模式。 它是具有已定义的null行为的对象,并且始终返回一个空数组的logging,而不查询数据库。
看到源代码 。
scope :none, limit(0)
是一个危险的解决scheme,因为你的范围可能被链接在一起。
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 | 其中(:user_id => users.map(&:id))如果users.any? }
如果你想要一个空的结果,使用这个(删除if条件):
范围:for_users,lambda {| users | 其中(: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
如我错了请纠正我。