jam-cloud/ruby/lib/jam_ruby/models/review.rb

103 lines
3.5 KiB
Ruby
Raw Normal View History

module JamRuby
class Review < ActiveRecord::Base
2016-01-13 03:01:39 +00:00
include HtmlSanitize
html_sanitize strict: [:description]
attr_accessible :target, :rating, :description, :user, :user_id, :target_id, :target_type
belongs_to :target, polymorphic: true
belongs_to :user, foreign_key: 'user_id', class_name: "JamRuby::User"
belongs_to :deleted_by_user, foreign_key: 'deleted_by_user_id', class_name: "JamRuby::User"
2015-07-22 00:14:18 +00:00
scope :available, -> { where("deleted_at iS NULL") }
2016-01-13 03:01:39 +00:00
scope :all, -> { select("*") }
2015-07-22 00:14:18 +00:00
2016-01-13 03:01:39 +00:00
validates :description, length: {maximum: 16000}, no_profanity: true, :allow_blank => true
validates :rating, presence: true, numericality: {only_integer: true, minimum: 1, maximum: 5}
2016-01-13 03:01:39 +00:00
validates :target, presence: true
validates :user_id, presence: true
validates :target_id, uniqueness: {scope: :user_id, message: "There is already a review for this User and Target."}
2016-01-13 03:01:39 +00:00
after_save :reduce
def self.create(params)
review = Review.new
review.target = params[:target]
review.user = params[:user]
review.rating = params[:rating]
review.description = params[:description]
review.target_type = params[:target].class.to_s
review.save
review
end
2016-01-13 03:01:39 +00:00
def self.index(options={})
if options.key?(:include_deleted)
arel = Review.all
else
arel = Review.available
end
if options.key?(:target_id)
arel = arel.where("target_id=?", options[:target_id])
end
2016-01-13 03:01:39 +00:00
if options.key?(:user_id)
arel = arel.where("user_id=?", options[:user_id])
end
2016-01-13 03:01:39 +00:00
arel
end
2016-01-13 03:01:39 +00:00
# Create review_summary records by grouping reviews
def self.reduce_all
ReviewSummary.transaction do
ReviewSummary.destroy_all
Review.select("target_id, target_type AS target_type, AVG(rating) as avg_rating, count(*) as review_count, SUM(CASE WHEN rating>=3.0 THEN 1 ELSE 0 END) AS pos_count")
.where("deleted_at IS NULL")
.group("target_type, target_id")
.each do |r|
wilson_score = ci_lower_bound(r.pos_count, r.review_count)
ReviewSummary.create!(
target_id: r.target_id,
target_type: r.target_type,
avg_rating: r.avg_rating,
wilson_score: wilson_score,
review_count: r.review_count
)
end
end
2016-01-13 03:01:39 +00:00
end
# http://www.evanmiller.org/how-not-to-sort-by-average-rating.html
def self.ci_lower_bound(pos, n, confidence=0.95)
pos=pos.to_f
n=n.to_f
return 0 if n == 0
z = 1.96 # Statistics2.pnormaldist(1-(1-confidence)/2)
phat = 1.0*pos/n
(phat + z*z/(2*n) - z * Math.sqrt((phat*(1-phat)+z*z/(4*n))/n))/(1+z*z/n)
end
2016-01-13 03:01:39 +00:00
def reduce
ReviewSummary.transaction do
ReviewSummary.where(target_type: target_type, target_id: target_id).destroy_all
Review.select("target_id, target_type AS target_type, AVG(rating) as avg_rating, count(*) as review_count, SUM(CASE WHEN rating>=3.0 THEN 1 ELSE 0 END) AS pos_count")
.where("deleted_at IS NULL")
.where(target_type: target_type, target_id: target_id)
.group("target_type, target_id")
.each do |r|
wilson_score = Review.ci_lower_bound(r.pos_count, r.review_count)
ReviewSummary.create!(
target_id: r.target_id,
target_type: r.target_type,
avg_rating: r.avg_rating,
wilson_score: wilson_score,
review_count: r.review_count
)
end
end
end
end
end