Search code examples
ruby-on-railsrubyruby-on-rails-3rails-activerecordvirtual-attribute

sum() or group() virtual attributes in ruby on rails


let's say I have a model like this:

class Surface < ActiveRecord::Base
  attr_accessible :width, :length

  def area
     self.width * self.length
  end
end

Where @surface.area returns the area of a surface. Now, lets say I have many surfaces called @surfaces and I want to sum all areas. How do I do this?

My favorite solution would look like this:

@surfaces.sum(:area)

But it does not work. So how can I call .sum() or .group() or any similar functions on a virtual attributes like this in rails? I would like to avoid .each do |surface| calls.

Thanks in advance.


Solution

  • sum will quite happily accept an SQL expression instead of just a column name so all you need to do is translate your sum method into SQL:

    @surfaces.sum('width * height')
    @surfaces.sum('surface.width * surface.height') # If you think other tables might be involved.
    

    Also, class methods on your models are mixed into relations (since scopes and class methods are really the same thing) so you could add a class method to go with your instance method:

    class Surface < ActiveRecord::Base
      def self.area
        sum('surface.width * surface.height')
      end
      def area
         self.width * self.length
      end
    end
    

    and say:

    @surfaces.area
    

    You're usually better off letting the database do the heavy lifting with your data, that's what they're for and what they're good at.