Common issues

ernie edited this page Apr 23, 2012 · 5 revisions
Clone this wiki locally

Common issues

This is a collection of issues arising from misconceptions about Squeel that frequently crop up on the issue tracker.


Like any other scopes, scopes that use the Squeel DSL must be wrapped in lambdas if you want them to be lazy evaluated. For instance:

scope :recent, where{created_at > 1.week.ago}

Won't work -- for long. The value of 1.week.ago will be interpreted when the model is loaded, and never again. Instead, use a lambda:

scope :recent, lambda { where{created_at > 1.week.ago} }

or a class method:

def self.recent
  where{created_at > 1.week.ago}

DSL is instance_evaled

The Squeel DSL operates inside an instance_eval. This means that you won't have access to instance methods or instance variables from the calling class. You will, however, have access to local variables that exist inside the closure from which you call it.

So, if you intend to use, for instance, params[:id] inside a Squeel block, you can do it in a few ways. First, you can assign the variable locally:

params_id = params[:id]
@article = Article.where{id == params_id}.first

Alternately, you can use the my keyword, which grants you access to the instance from which the DSL was called:

@article = Article.where{id == my{params[:id]}}.first

Or, if you really like typing, you can give your block an arity, like so:

@article = Article.where{ |q| == params[:id]

Note that if given an arity, access to the DSL object (and thus creation of stubs, keypaths, etc) is via the block parameter.

Columns as Values

This one was subject of some debate, but observing a few simple, common-sense guidelines gives you a way to refer to columns in the value-side of conditions that wasn't previously available.

For instance, here's a query that finds all children with the same name as their parent -- note the tilde (~), which anchors the right-hand side of the comparison to the base model, instead of using the left-hand side's nesting:

Person.joins{children}.where{ == ~name}.to_sql
=> SELECT "people".* FROM "people" 
   INNER JOIN "people" "children_people" ON "children_people"."parent_id" = "people"."id" 
   WHERE "children_people"."name" = "people"."name""