为什么这种类似范围的查询方法不能使用拒绝?

时间:2016-05-13 19:55:35

标签: ruby-on-rails ruby ruby-on-rails-4 rails-activerecord

根据Rails documentation for scope,范围如:

class Shirt < ActiveRecord::Base
    scope :red, -> { where(color: 'red') }
end

是真的:

class Shirt < ActiveRecord::Base
    def self.red
        where(color: 'red')
    end
end

他们还说该关系应该充当Array,所以做这样的事情

Shirt.red.each(&block)

应该有效......而且确实如此。

使用我们上面所知的一切,为什么以下不起作用?

class Shirt < ActiveRecord::Base
    def self.short_sleeved
        reject{|object| object.short_sleeved == false}
    end
end

Shirt.red.short_sleeved会产生undefined method 'reject' for #<Class:0xba552d4>

1 个答案:

答案 0 :(得分:1)

您无法按照您尝试的方式定义short_sleeved方法,因为ActiveRecord类不是ActiveRecord关系。

您在short_sleeved上定义了ShirtShirt是ActiveRecord模型类。它本身不是ActiveRecord关系。它有一些方法,包括allwhere以及许多其他返回ActiveRecord关系的方法。

Shirt.class
=> Class
Shirt.respond_to? :each
=> false
Shirt.respond_to? :reject
=> false

与内置查询方法类似,范围返回ActiveRecord关系。 ActiveRecord关系具有动态生成的类。它不是Enumerable,而是响应Enumerable方法:

red_shirts = Shirt.red
red_shirts.class
=> Shirt::ActiveRecord_Relation
red_shirts.respond_to? :each
=> true
red_shirts.respond_to? :reject
=> true

所以,你可以用这种方式编写你的方法:

def self.short_sleeved
  all.reject { |object| object.short_sleeved == false }
end

然而,它会从数据库中加载所有Shirt,然后在内存中过滤它们,这对于大量Shirt的效率不如在数据库中进行过滤{ {1}}正如MZaragosa所说。你可以这样做

where

def self.short_sleeved
  where short_sleeved: true
end