Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding a computed column to an ActiveRecord query

I am running a query using a scope and some conditions. Something like this:

conditions[:offset] = (options[:page].to_i - 1) * PAGE_SIZE unless options[:page].blank?    
conditions[:limit] = options[:limit] ||= PAGE_SIZE
scope = Promo.enabled.active
results = scope.all conditions 

I'd like to add a computed column to the query (at the point when I'm now calling scope.all). Something like this:

(ACOS(least(1,COS(0.71106459055501)*COS(-1.2915436464758)*COS(RADIANS(addresses.lat))*COS(RADIANS(addresses.lng))+ COS(0.71106459055501)*SIN(-1.2915436464758)*COS(RADIANS(addresses.lat))*SIN(RADIANS(addresses.lng))+ SIN(0.71106459055501)*SIN(RADIANS(addresses.lat))))*3963.19) as accurate_distance

Is there a way to do that without just using find_by_sql and rewriting the whole existing query?

Thanks!

like image 438
rmw Avatar asked Jan 14 '11 02:01

rmw


1 Answers

Sure, use this:

conditions = Hash.new
conditions[:select] = "#{Promo.quoted_table_name}.*, (ACOS(...)) AS accurate_distance")
conditions[:offset] = (options[:page].to_i - 1) * PAGE_SIZE unless options[:page].blank?    
conditions[:limit] = options[:limit] ||= PAGE_SIZE
scope = Promo.enabled.active
results = scope.all conditions 

Note the new :select - that tells ActiveRecord what columns you want returned. The returned object in results will have a #accurante_distance accessor. Unfortunately, ActiveRecord is dumb and won't be able to infer the column's type. You can always add a method:

class Promo
  def accurate_distance
    raise "Missing attribute" unless has_attribute?(:accurate_distance)
    read_attribute(:accurate_distance).to_f # or instantiate a BigDecimal
  end
end

See #has_attribute for details.

like image 129
François Beausoleil Avatar answered Sep 22 '22 00:09

François Beausoleil