Skip to content
This repository has been archived by the owner on Mar 30, 2022. It is now read-only.

Common issues

ernie edited this page Apr 23, 2012 · 5 revisions

Common issues

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

Scopes

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:

# DO NOT USE!
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}
end

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|
  q.id == params[:id]
}.first

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{children.name == ~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""
Clone this wiki locally