How to return an empty ActiveRecord relation?

前端 未结 9 1763
有刺的猬
有刺的猬 2020-12-07 07:38

If I have a scope with a lambda and it takes an argument, depending on the value of the argument, I might know that there will not be any matches, but I still want to return

相关标签:
9条回答
  • 2020-12-07 08:09

    Coming in Rails 4

    In Rails 4, a chainable ActiveRecord::NullRelation will be returned from calls like Post.none.

    Neither it, nor chained methods, will generate queries to the database.

    According to the comments:

    The returned ActiveRecord::NullRelation inherits from Relation and implements the Null Object pattern. It is an object with defined null behavior and always returns an empty array of records without quering the database.

    See the source code.

    0 讨论(0)
  • 2020-12-07 08:10

    A more portable solution that doesn't require an "id" column and doesn't assume there won't be a row with an id of 0:

    scope :none, where("1 = 0")
    

    I'm still looking for a more "correct" way.

    0 讨论(0)
  • 2020-12-07 08:13

    There is a now a "correct" mechanism in Rails 4:

    >> Model.none 
    => #<ActiveRecord::Relation []>
    
    0 讨论(0)
  • You can add a scope called "none":

    scope :none, where(:id => nil).where("id IS NOT ?", nil)
    

    That will give you an empty ActiveRecord::Relation

    You could also add it to ActiveRecord::Base in an initializer (if you want):

    class ActiveRecord::Base
     def self.none
       where(arel_table[:id].eq(nil).and(arel_table[:id].not_eq(nil)))
     end
    end
    

    Plenty of ways to get something like this, but certainly not the best thing to keep in a code base. I have used the scope :none when refactoring and finding that I need to guarantee an empty ActiveRecord::Relation for a short time.

    0 讨论(0)
  • 2020-12-07 08:24
    scope :none, limit(0)
    

    Is a dangerous solution because your scope might be chained upon.

    User.none.first

    will return the first user. It's safer to use

    scope :none, where('1 = 0')
    
    0 讨论(0)
  • 2020-12-07 08:28

    Use scoped:

    scope :for_users, lambda { |users| users.any? ? where("user_id IN (?)", users.map(&:id).join(',')) : scoped }
    

    But, you can also simplify your code with:

    scope :for_users, lambda { |users| where(:user_id => users.map(&:id)) if users.any? }
    

    If you want an empty result, use this (remove the if condition):

    scope :for_users, lambda { |users| where(:user_id => users.map(&:id)) }
    
    0 讨论(0)
提交回复
热议问题