0x08: 10, 9, 8, … zero in on <what> ?

Rails – or to be more precise – ActiveRecord scopes can be a huge time saver. That is, unless you have a number of multiple conditions that stack onto each other. But if you are in need of an “advanced search” feature you will likely end up with something like the following:

condition1 = first_name && { :conditions => [ "first_name LIKE ?", "#{first_name}%" ] }
condition2 = last_name && { :conditions => [ "last_name LIKE ?", "#{last_name}%" ] }
condition3 = min_age && { :conditions => [ "birthday < ?", Date.now - min_age.years ] }

with_scope :find => condition1 do
  with_scope :find => condition2 do
    with_scope :find => condition3 do
      User.find :all, ...
    end
  end
end

That certainly is ok enough, but what I don’t like here is the wrapping of all those with_scopes into each other. What I want instead would look more like this

scope = User.scope 
scope.conditions "first_name LIKE ?", "#{first_name}%"    if first_name
scope.conditions "last_name LIKE ?", "#{last_name}%"      if last_name
scope.conditions "birthday < ?", Date.now - min_age.years if min_age
scope.find :all, ...

Not only is this five lines of code compared to eleven. I even think this expresses more clearly what is going on here: namely that we stack a number of conditions onto each other. Sadly the ActiveRecord interface doesn’t allow for something like that. But with Ruby so flexible it is easily possible to chew up the original interface and come up with something that matches my intent. And while we are at it: this way we can work around some bug limitation that occurs when stacking with_scopes: ActiveRecord doesn’t like multiple :join parameters to scopes. Or at least it didn’t like them…

So this is the code. I hope I managed to to without any typos… Have a great week!

Recommended reading

You want me to add a link here? Just write a comment…

Advertisements

2 responses to “0x08: 10, 9, 8, … zero in on <what> ?

  1. have you tried searchgasm? and maybe named scopes could help here too, not sure.

  2. onerubyaday

    Sure you are right, alex. But this blog is not about this plugin or that. Instead it is more about style and about what code can do. And 57 lines of code are not that bad to get some other piece of code into the shape I like. Once that you understand what is going on: that is the moment where you should start digging around for plugins, that do that stuff and do it in even greater depth.

    And maybe I should introduce a new section here: plugins you shouldn’t miss… This might help those searching for solutions in addition to understanding. You are free to volunteer :)

    A sidenote regarding the searchgasm (stupid name, btw) example: while I actually not totally disapprove of putting logic into views (in fact, when done right, this is one big step towards performance and DRYness) I know tons of people that would object.

    And speaking of code quality: this one – just an excerpt from the example:

    – users.fields_for users.object.orders do |orders|
    = orders.select :total_gt, (1..100)

    This is not what I call self-explananatory. Unless you know the insides and outs of searchgasm, I presume. What does this piece of code do? Selecting the “total_gt” column of the first 100 orders? Or is total_gt a collation, may be “total general teaconsumption” ? I wouldn’t know. If it was written in plain SQL or in ActiveRecord – then I would.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s