我已经多次遇到这个问题了:我想在查询中应用范围,但前提是传递给范围的参数不是null.所以
tags = Tag.where(name: params[:name]) if params[:name]
但是,这有两个问题.一个是Rails会立即评估查询,所以如果我想对它应用更多条件,比如说
tags.where(location: params[:place]) if params[:place]
它将再次查询DB.第二个问题是它看起来不太好,我试图用类方法来解决它.
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
解决方法
在这里你可以使用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
也:
>切勿在Where子句中使用直接字符串插值:http://blog.presidentbeef.com/blog/2013/02/08/avoid-sql-injection-in-rails/