Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor letsrate model to fix rating on inherited models #60

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
67 changes: 32 additions & 35 deletions lib/letsrate/model.rb
Expand Up @@ -4,60 +4,40 @@ module Letsrate

def rate(stars, user, dimension=nil, dirichlet_method=false)
dimension = nil if dimension.blank?
raise "User has already rated." unless can_rate? user, dimension

if can_rate? user, dimension
rates(dimension).create! do |r|
r.stars = stars
r.rater = user
end
if dirichlet_method
update_rate_average_dirichlet(stars, dimension)
else
update_rate_average(stars, dimension)
end
rates(dimension).create! do |r|
r.stars = stars
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this code was moved to a private method

r.rater = user
end

if dirichlet_method
update_rate_average_dirichlet(stars, dimension)
else
raise "User has already rated."
update_rate_average(stars, dimension)
end
end

def update_rate_average_dirichlet(stars, dimension=nil)
## assumes 5 possible vote categories
dp = {1 => 1, 2 => 1, 3 => 1, 4 => 1, 5 => 1}
stars_group = Hash[rates(dimension).group(:stars).count.map{|k,v| [k.to_i,v] }]
posterior = dp.merge(stars_group){|key, a, b| a + b}
sum = posterior.map{ |i, v| v }.inject { |a, b| a + b }
davg = posterior.map{ |i, v| i * v }.inject { |a, b| a + b }.to_f / sum

if average(dimension).nil?
RatingCache.create! do |avg|
avg.cacheable_id = self.id
avg.cacheable_type = self.class.name
avg.qty = 1
avg.avg = davg
avg.dimension = dimension
end
create_rating_cache davg, dimension
else
a = average(dimension)
a.qty = rates(dimension).count
a.avg = davg
a.save!(validate: false)
update_rating_cache davg, dimension
end
end

def update_rate_average(stars, dimension=nil)
if average(dimension).nil?
RatingCache.create! do |avg|
avg.cacheable_id = self.id
avg.cacheable_type = self.class.name
avg.avg = stars
avg.qty = 1
avg.dimension = dimension
end
create_rating_cache stars, dimension
else
a = average(dimension)
a.qty = rates(dimension).count
a.avg = rates(dimension).average(:stars)
a.save!(validate: false)
avg = rates(dimension).average(:stars)
update_rating_cache avg, dimension
end
end

Expand All @@ -66,7 +46,7 @@ def average(dimension=nil)
end

def can_rate?(user, dimension=nil)
user.ratings_given.where(dimension: dimension, rateable_id: id, rateable_type: self.class.name).size.zero?
rates(dimension).where(rater_id: user.id).size.zero?
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is much simpler than the previous code and dont violate the "Law of Demeter"

end

def rates(dimension=nil)
Expand Down Expand Up @@ -106,6 +86,23 @@ def letsrate_rateable(*dimensions)
end
end

private

def create_rating_cache(avg, dimension=nil)
options = {avg: avg, qty: 1, dimension: dimension}
if dimension
send "create_#{dimension}_average", options
else
create_rate_average_without_dimension options
end
end

def update_rating_cache(avg, dimension=nil)
a = average(dimension)
a.qty = rates(dimension).count
a.avg = avg
a.save!(validate: false)
end
end

class ActiveRecord::Base
Expand Down