ruby-on-railsruby-on-rails-3will-paginategeokit

Combine arrays of conditions in Rails


I'm using the Rails3 beta, will_paginate gem, and the geokit gem & plugin.

As the geokit-rails plugin, doesn't seem to support Rails3 scopes (including the :origin symbol is the issue), I need to use the .find syntax.

In lieu of scopes, I need to combine two sets of criteria in array format:

I have a default condition:

conditions = ["invoices.cancelled = ? AND invoices.paid = ?", false, false]

I may need to add one of the following conditions to the default condition, depending on a UI selection:

#aged 0
lambda {["created_at IS NULL OR created_at < ?", Date.today + 30.days]}
#aged 30
lambda {["created_at >= ? AND created_at < ?", Date.today + 30.days, Date.today + 60.days]}
#aged > 90
lamdba {["created_at >= ?", Date.today + 90.days]}

The resulting query resembles:

@invoices = Invoice.find(
  :all, 
  :conditions => conditions,
  :origin => ll     #current_user's lat/lng pair
  ).paginate(:per_page => @per_page, :page => params[:page])

Questions:

  1. Is there an easy way to combine these two arrays of conditions (if I've worded that correctly)
  2. While it isn't contributing to the problem, is there a DRYer way to create these aging buckets?
  3. Is there a way to use Rails3 scopes with the geokit-rails plugin that will work?

Thanks for your time.


Solution

  • Try this:

    ca =  [["invoices.cancelled = ? AND invoices.paid = ?", false, false]]
    
    ca << ["created_at IS NULL OR created_at < ?", 
                        Date.today + 30.days] if aged == 0
    
    ca << ["created_at >= ? AND created_at < ?", 
                        Date.today + 30.days, Date.today + 60.days] if aged == 30
    
    ca << ["created_at >= ?", Date.today + 90.days] if aged > 30
    
    condition = [ca.map{|c| c[0] }.join(" AND "), *ca.map{|c| c[1..-1] }.flatten]
    

    Edit Approach 2

    Monkey patch the Array class. Create a file called monkey_patch.rb in config/initializers directory.

    class Array
      def where(*args)
        sql = args[0]     
        unless (sql.is_a?(String) and sql.present?)
          return self
        end    
        self[0] = self[0].present? ? " #{self[0]} AND #{sql}  " : sql 
        self.concat(args[1..-1])    
      end
    end
    

    Now you can do this:

    cond = []
    cond.where("id = ?", params[id]) if params[id].present?
    cond.where("state IN (?)", states) unless states.empty?
    User.all(:conditions => cond)