module ActiveRecord
  module Acts
    module Rateable
      def self.included(base)
        base.extend(ClassMethods)
      end
      
      module ClassMethods
        def acts_as_rateable(options = {})
          has_many :ratings, :as => :rateable, :dependent => :destroy
          
          include ActiveRecord::Acts::Rateable::InstanceMethods
        end
      end
            
      module InstanceMethods
        # Rates the object by a given score. A user id should be passed to the method.
        def rate_it(score, user_id)
          returning(ratings.find_or_initialize_by_user_id(user_id)) do |rating|
            rating.update_attributes!(:score => score)
          end
        end
        
        # Calculates the average rating. Calculation based on the already given scores.
        def average_rating
          (ratings(true).inject(0.0){|total,rating| total += rating.score}.to_f / ratings.size)
        end

        # Rounds the average rating value.
        def average_rating_round
          average_rating.round
        end
    
        # Returns the average rating in percent. The maximal score must be provided or the default value (5) will be used.
        # TODO make maximum_rating automatically calculated.
        def average_rating_percent(maximum_rating = 5)
          f = 100 / maximum_rating.to_f
          average_rating * f
        end
        
        # Checks wheter a user rated the object or not.
        def rated_by?(user_id )
          ratings.exists?(:user_id => user_id)
        end
      end
      
    end
  end
end

module ActiveRecord
  module Acts
    module Rateable
      def self.included(base)
        base.extend(ClassMethods)
      end
      
      module ClassMethods
        def acts_as_rateable(options = {})
          has_many :ratings, :as => :rateable, :dependent => :destroy
          
          include ActiveRecord::Acts::Rateable::InstanceMethods
        end
      end
            
      module InstanceMethods
        # Rates the object by a given score. A user id should be passed to the method.
        def rate_it(score, user_id)
          returning(ratings.find_or_initialize_by_user_id(user_id)) do |rating|
            rating.update_attributes!(:score => score)
          end
        end
        
        # Calculates the average rating. Calculation based on the already given scores.
        def average_rating
          rating = (ratings(true).inject(0.0){|total,rating| total += rating.score}.to_f / ratings.size)
          rating.nan? ? 0.0 : rating
        end

        # Rounds the average rating value.
        def average_rating_round
          average_rating.round
        end
    
        # Returns the average rating in percent. The maximal score must be provided or the default value (5) will be used.
        # TODO make maximum_rating automatically calculated.
        def average_rating_percent(maximum_rating = 5)
          f = 100 / maximum_rating.to_f
          average_rating * f
        end
        
        # Checks wheter a user rated the object or not.
        def rated_by?(user_id )
          ratings.exists?(:user_id => user_id)
        end
      end
      
    end
  end
end

Return 0.0 if no ratings.
Return 0.0 if no ratings.
