9

我已经多次遇到这个问题:我想在查询上应用范围,但前提是传递给范围的参数不为空。所以

tags = Tag.where(name: params[:name]) if params[:name]

但是,这样做有两个问题。一种是 Rails 会立即评估查询,所以如果我想对它应用更多条件,比如说

tags.where(location: params[:place]) if params[:place]

它将再次查询数据库。第二个问题是它看起来不太好,我试图用类方法来解决这个问题。

  class Tag < ActiveRecord::Base
    def self.name_like this_name
      if !this_name.blank?
        where("name ILIKE '%#{this_name}%'")
      else
        #what do I put here? `all` does not work
      end
    end
  end

但是,我不能简单地放在all那里,因为它会评估一个查询。有什么想法吗?

4

2 回答 2

9

在这里您可以使用 lambda 范围,并使用selfto 调用self.all

  class Tag < ActiveRecord::Base

    scope :named_like, (lambda do |name| 
      if name.present?
        where("name ILIKE ?", "%#{name}%")
      else
        scoped # does not apply a where clause
      end
    end)

  end

对于一个非常基本的范围来说,这需要太多的行,这是压缩版本:

class Tab < ActiveRecord::Base

  scope :named_like, lambda{ |name| self.where("name ILIKE ?", "%#{name}%") if name.present? }

end

还:

于 2013-02-26T19:06:59.067 回答
0

据我所知(以及这里写的内容:ActiveRecord::Relation),实际上只有在迭代结果时才会执行查询。因此,当您编写以下内容时:

tags = Tags.where(name: params[:name])
# other stuff here
tags = tags.where(location: params[:place])

在此代码段中,不执行任何查询。

tags.each { # do something }

但它就在那里!当然只有一次。
首先,标签是一个 ActiveRecord::Relation 对象,因此您可以链接where您喜欢的程度。

于 2013-02-26T21:24:48.913 回答