Module: ActiveRecord::Acts::Rated::RateMethods

Defined in:
lib/acts_as_rated.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object

:nodoc:



143
144
145
# File 'lib/acts_as_rated.rb', line 143

def self.included(base) #:nodoc:
  base.extend ClassMethods
end

Instance Method Details

#rate(value, rater = nil) ⇒ Object

Rate the object with or without a rater - create new or update as needed

  • value - the value to rate by, if a rating range was specified will be checked that it is in range

  • rater - an object of the rater class. Must be valid and with an id to be used.

    If the acts_as_rated was passed :with_rater => false, this parameter is not required
    

Raises:



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/acts_as_rated.rb', line 190

def rate value, rater = nil
  # Sanity checks for the parameters
  rating_class = acts_as_rated_options[:rating_class].constantize
  with_rater = rating_class.column_names.include? "rater_id"
  raise RateError, "rating with no rater cannot accept a rater as a parameter" if !with_rater && !rater.nil?
  if with_rater && !(acts_as_rated_options[:rater_class].constantize === rater)
    raise RateError, "the rater object must be the one used when defining acts_as_rated (or a descendent of it). other objects are not acceptable"
  end
  raise RateError, "rating with rater must receive a rater as parameter" if with_rater && (rater.nil? || rater.id.nil?)
  r = with_rater ? ratings.find(:first, :conditions => ['rater_id = ?', rater.id]) : nil
  raise RateError, "value is out of range!" unless acts_as_rated_options[:rating_range].nil? || acts_as_rated_options[:rating_range] === value
  
  # Find the place to store the rating statistics if any...
  # Take care of the case of a separate statistics table
  unless acts_as_rated_options[:stats_class].nil? || @rating_statistic.class.to_s == acts_as_rated_options[:stats_class]
    self.rating_statistic = acts_as_rated_options[:stats_class].constantize.new    
  end
  target = self if attributes.has_key? 'rating_total'
  target ||= self.rating_statistic if acts_as_rated_options[:stats_class]
  rating_class.transaction do
    if r.nil?
      rate = rating_class.new
      rate.rater_id = rater.id if with_rater
      if target
        target.rating_count = (target.rating_count || 0) + 1 
        target.rating_total = (target.rating_total || 0) + value
        target.rating_avg = target.rating_total.to_f / target.rating_count
      end
      ratings << rate
    else
      rate = r
      if target
        target.rating_total += value - rate.rating # Update the total rating with the new one
        target.rating_avg = target.rating_total.to_f / target.rating_count
      end
    end

    # Remove the actual ratings table entry
    rate.rating = value
    if !new_record?
      rate.save
      target.save if target
    end
  end
end

#rated?Boolean

Is this object rated already?

Returns:

  • (Boolean)


158
159
160
161
162
163
164
165
166
167
# File 'lib/acts_as_rated.rb', line 158

def rated?
  return (!self.rating_count.nil? && self.rating_count > 0) if attributes.has_key? 'rating_count'
  if acts_as_rated_options[:stats_class]
    stats = (rating_statistic.rating_count || 0) rescue 0
    return stats > 0
  end

  # last is the one where we don't keep the statistics - go direct to the db
  !ratings.find(:first).nil? 
end

#rated_by?(rater) ⇒ Boolean

Check if an item was already rated by the given rater

Returns:

  • (Boolean)

Raises:



267
268
269
270
271
272
273
274
275
# File 'lib/acts_as_rated.rb', line 267

def rated_by? rater
  rating_class = acts_as_rated_options[:rating_class].constantize
  if !(acts_as_rated_options[:rater_class].constantize === rater)
     raise RateError, "The rater object must be the one used when defining acts_as_rated (or a descendent of it). other objects are not acceptable" 
  end
  raise RateError, "Rater must be a valid and existing object" if rater.nil? || rater.id.nil?
  raise RateError, 'Rater must be a valid rater' if !rating_class.column_names.include? "rater_id"
  ratings.count(:conditions => ['rater_id = ?', rater.id]) > 0
end

#rated_countObject

Get the number of ratings for this object based on the special fields, or with a SQL query if the rated objects doesn’t have the avg and count fields



171
172
173
174
175
# File 'lib/acts_as_rated.rb', line 171

def rated_count
  return self.rating_count || 0 if attributes.has_key? 'rating_count'
  return (rating_statistic.rating_count || 0) rescue 0 if acts_as_rated_options[:stats_class]
  ratings.count 
end

#rated_totalObject

Get the sum of all ratings for this object based on the special fields, or with a SQL query if the rated objects doesn’t have the avg and count fields



179
180
181
182
183
# File 'lib/acts_as_rated.rb', line 179

def rated_total
  return self.rating_total || 0 if attributes.has_key? 'rating_total'
  return (rating_statistic.rating_total || 0) rescue 0 if acts_as_rated_options[:stats_class]
  ratings.sum(:rating) 
end

#rating_averageObject

Get the average based on the special fields, or with a SQL query if the rated objects doesn’t have the avg and count fields



149
150
151
152
153
154
155
# File 'lib/acts_as_rated.rb', line 149

def rating_average
  return self.rating_avg if attributes.has_key?('rating_avg')
  return (rating_statistic.rating_avg || 0) rescue 0 if acts_as_rated_options[:stats_class]
  avg = ratings.average(:rating) 
  avg = 0 if avg.nan?
  avg
end

#unrate(rater) ⇒ Object

Unrate the rating of the specified rater object.

  • rater - an object of the rater class. Must be valid and with an id to be used

Unrate cannot be called for acts_as_rated with :with_rater => false

Raises:



240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# File 'lib/acts_as_rated.rb', line 240

def unrate rater
  rating_class = acts_as_rated_options[:rating_class].constantize
  if !(acts_as_rated_options[:rater_class].constantize === rater)
    raise RateError, "The rater object must be the one used when defining acts_as_rated (or a descendent of it). other objects are not acceptable" 
  end
  raise RateError, "Rater must be a valid and existing object" if rater.nil? || rater.id.nil?
  raise RateError, 'Cannot unrate if not using a rater' if !rating_class.column_names.include? "rater_id"
  r = ratings.find(:first, :conditions => ['rater_id = ?', rater.id])
  if !r.nil?
    target = self if attributes.has_key? 'rating_total'
    target ||= self.rating_statistic if acts_as_rated_options[:stats_class]
    if target
      rating_class.transaction do
        target.rating_count -= 1
        target.rating_total -= r.rating
        target.rating_avg = target.rating_total.to_f / target.rating_count
        target.rating_avg = 0 if target.rating_avg.nan?
      end
    end

    # Removing the ratings table entry
    r.destroy
    target.save if !target.nil?
  end
end