Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails, apply a scope or not depending on whether a parameter is nil

I've been running into this problem several times: I want to apply a scope on a query, but only if the parameter passed to the scope is not null. So

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

However, there are two problems with this. One is that Rails will evaluate the query immediately, and so if I want to apply more conditions to it, say

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

It will query the DB again. The second problem is that it doesn't look very nice, which I've tried to get around with class methods.

  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

However, I cannot simply just put all in there, because that evaluates a query. Any thoughts?

like image 877
varatis Avatar asked Feb 26 '13 19:02

varatis


Video Answer


1 Answers

Here you can use a lambda scope, and use the self to call 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

This is taking too much lines for a very basic scope, here is the compressed version:

class Tab < ActiveRecord::Base

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

end

Also:

  • Never use direct String interpolation inside a Where clause: http://blog.presidentbeef.com/blog/2013/02/08/avoid-sql-injection-in-rails/
like image 79
MrYoshiji Avatar answered Sep 22 '22 12:09

MrYoshiji