我多次遇到过这个问题:我想在查询中应用范围,但前提是传递给范围的参数不是null。所以
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
放在那里,因为它会评估查询。有什么想法吗?
答案 0 :(得分:9)
在这里你可以使用lambda范围,并使用self
来调用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
此外:
答案 1 :(得分: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
。