如何返回一个空的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

如我错了请纠正我。