From 5f336a235113a9f5b4443121690bdba4fb6fae84 Mon Sep 17 00:00:00 2001 From: Denislav Naydenov Date: Fri, 1 Mar 2013 13:38:32 +0200 Subject: [PATCH 01/20] added option 'disable_after_rate' which makes the stars readOnly for the current user after successful rate --- lib/generators/letsrate/templates/letsrate.js | 63 +++++++++++-------- lib/letsrate/helpers.rb | 37 ++++++----- 2 files changed, 58 insertions(+), 42 deletions(-) diff --git a/lib/generators/letsrate/templates/letsrate.js b/lib/generators/letsrate/templates/letsrate.js index 901f29f..f2abb8d 100644 --- a/lib/generators/letsrate/templates/letsrate.js +++ b/lib/generators/letsrate/templates/letsrate.js @@ -1,27 +1,36 @@ -$.fn.raty.defaults.path = "/assets"; -$.fn.raty.defaults.half_show = true; - -$(function(){ - $(".star").raty({ - score: function(){ - return $(this).attr('data-rating') - }, - number: function() { - return $(this).attr('data-star-count') - }, - click: function(score, evt) { - $.post('<%= Rails.application.class.routes.url_helpers.rate_path %>', - { - score: score, - dimension: $(this).attr('data-dimension'), - id: $(this).attr('data-id'), - klass: $(this).attr('data-classname') - }, - function(data) { - if(data) { - // success code goes here ... - } - }); - } - }); -}); \ No newline at end of file +$.fn.raty.defaults.path = "/assets"; +$.fn.raty.defaults.half_show = true; + +$(function(){ + $(".star").each(function() { + var $readonly = ($(this).attr('data-readonly') == 'true'); + $(this).raty({ + score: function(){ + return $(this).attr('data-rating') + }, + number: function() { + return $(this).attr('data-star-count') + }, + readOnly: $readonly, + click: function(score, evt) { + var _this = this; + $.post('<%= Rails.application.class.routes.url_helpers.rate_path %>', + { + score: score, + dimension: $(this).attr('data-dimension'), + id: $(this).attr('data-id'), + klass: $(this).attr('data-classname') + }, + function(data) { + if(data) { + // success code goes here ... + + if ($(_this).attr('data-disable-after-rate') == 'true') { + $(_this).raty('set', { readOnly: true, score: score }); + } + } + }); + } + }); + }); +}); diff --git a/lib/letsrate/helpers.rb b/lib/letsrate/helpers.rb index 119046b..d849b92 100644 --- a/lib/letsrate/helpers.rb +++ b/lib/letsrate/helpers.rb @@ -1,29 +1,36 @@ -module Helpers - def rating_for(rateable_obj, dimension=nil, options={}) - +module Helpers + def rating_for(rateable_obj, dimension=nil, options={}) + if dimension.nil? klass = rateable_obj.average - else - klass = rateable_obj.average "#{dimension}" + else + klass = rateable_obj.average "#{dimension}" end - + if klass.nil? avg = 0 else avg = klass.avg end - + star = options[:star] || 5 - - content_tag :div, "", "data-dimension" => dimension, :class => "star", "data-rating" => avg, - "data-id" => rateable_obj.id, "data-classname" => rateable_obj.class.name, - "data-star-count" => star - - + + disable_after_rate = options[:disable_after_rate] || false + + readonly = false + if disable_after_rate + readonly = current_user.present? ? !rateable_obj.can_rate?(current_user.id, dimension) : true + end + + content_tag :div, '', "data-dimension" => dimension, :class => "star", "data-rating" => avg, + "data-id" => rateable_obj.id, "data-classname" => rateable_obj.class.name, + "data-disable-after-rate" => disable_after_rate, + "data-readonly" => readonly, + "data-star-count" => star end - + end class ActionView::Base include Helpers -end \ No newline at end of file +end From 024f8944fcdf892ee718509efca39950ff9e957c Mon Sep 17 00:00:00 2001 From: Klaus Trainer Date: Tue, 26 Mar 2013 18:52:41 +0100 Subject: [PATCH 02/20] Prevent eval things from happening --- lib/generators/letsrate/templates/rater_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/generators/letsrate/templates/rater_controller.rb b/lib/generators/letsrate/templates/rater_controller.rb index dc84c4b..5e66975 100644 --- a/lib/generators/letsrate/templates/rater_controller.rb +++ b/lib/generators/letsrate/templates/rater_controller.rb @@ -2,7 +2,7 @@ class RaterController < ApplicationController def create if current_user.present? - obj = eval "#{params[:klass]}.find(#{params[:id]})" + obj = params[:klass].classify.constantize.find(params[:id]) if params[:dimension].present? obj.rate params[:score].to_i, current_user.id, "#{params[:dimension]}" else From 11fe7ca2ca3d9d084627ce0893b649da83a87c42 Mon Sep 17 00:00:00 2001 From: cubecul Date: Sun, 9 Jun 2013 14:26:34 -0500 Subject: [PATCH 03/20] Display individual ratings Create rating_for_user, which displays rating from an individual review rather than the overall rating. --- lib/letsrate/helpers.rb | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/lib/letsrate/helpers.rb b/lib/letsrate/helpers.rb index d849b92..65eecb4 100644 --- a/lib/letsrate/helpers.rb +++ b/lib/letsrate/helpers.rb @@ -28,6 +28,26 @@ def rating_for(rateable_obj, dimension=nil, options={}) "data-readonly" => readonly, "data-star-count" => star end + + def rating_for_user(rateable_obj, rating_user, dimension = nil, options = {}) + @product = rateable_obj + @user = rating_user + @rating = Rate.find_by_rater_id_and_rateable_id_and_dimension(@user.id, @product.id, dimension) + stars = @rating.stars + + disable_after_rate = options[:disable_after_rate] || false + + readonly=false + if disable_after_rate + readonly = current_user.present? ? !rateable_obj.can_rate?(current_user.id, dimension) : true + end + + content_tag :div, '', "data-dimension" => dimension, :class => "star", "data-rating" => stars, + "data-id" => rateable_obj.id, "data-classname" => rateable_obj.class.name, + "data-disable-after-rate" => disable_after_rate, + "data-readonly" => readonly, + "data-star-count" => stars + end end From eb6e523193a72e8c7250cb14b15f22e85c386001 Mon Sep 17 00:00:00 2001 From: cubecul Date: Wed, 12 Jun 2013 09:35:33 -0500 Subject: [PATCH 04/20] Checks for existence of rating --- lib/letsrate/helpers.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/letsrate/helpers.rb b/lib/letsrate/helpers.rb index 65eecb4..9795453 100644 --- a/lib/letsrate/helpers.rb +++ b/lib/letsrate/helpers.rb @@ -30,10 +30,10 @@ def rating_for(rateable_obj, dimension=nil, options={}) end def rating_for_user(rateable_obj, rating_user, dimension = nil, options = {}) - @product = rateable_obj + @object = rateable_obj @user = rating_user - @rating = Rate.find_by_rater_id_and_rateable_id_and_dimension(@user.id, @product.id, dimension) - stars = @rating.stars + @rating = Rate.find_by_rater_id_and_rateable_id_and_dimension(@user.id, @object.id, dimension) + stars = @rating ? @rating.stars : 0 disable_after_rate = options[:disable_after_rate] || false From ce1f812ba1ec1f2b610748b2d4fa130a91fadf1f Mon Sep 17 00:00:00 2001 From: Anton Orel Date: Sun, 14 Jul 2013 14:27:27 +0400 Subject: [PATCH 05/20] Trailing spaces removed --- lib/letsrate/model.rb | 76 +++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/lib/letsrate/model.rb b/lib/letsrate/model.rb index 8dd319d..5b502a3 100644 --- a/lib/letsrate/model.rb +++ b/lib/letsrate/model.rb @@ -1,20 +1,20 @@ require 'active_support/concern' module Letsrate extend ActiveSupport::Concern - + def rate(stars, user_id, dimension=nil) if can_rate? user_id, dimension rates(dimension).build do |r| r.stars = stars r.rater_id = user_id - r.save! - end + r.save! + end update_rate_average(stars, dimension) else - raise "User has already rated." + raise "User has already rated." end - end - + end + def update_rate_average(stars, dimension=nil) if average(dimension).nil? RatingCache.create do |avg| @@ -24,32 +24,32 @@ def update_rate_average(stars, dimension=nil) avg.qty = 1 avg.dimension = dimension avg.save! - end + end else a = average(dimension) a.avg = (a.avg*a.qty + stars) / (a.qty+1) a.qty = a.qty + 1 a.save! - end - end - + end + end + def average(dimension=nil) if dimension.nil? self.send "rate_average_without_dimension" else self.send "#{dimension}_average" - end - end - + end + end + def can_rate?(user_id, dimension=nil) val = self.connection.select_value("select count(*) as cnt from rates where rateable_id=#{self.id} and rateable_type='#{self.class.name}' and rater_id=#{user_id} and dimension='#{dimension}'").to_i if val == 0 true else false - end - end - + end + end + def rates(dimension=nil) if dimension.nil? self.send "rates_without_dimension" @@ -57,45 +57,45 @@ def rates(dimension=nil) self.send "#{dimension}_rates" end end - + def raters(dimension=nil) if dimension.nil? self.send "raters_without_dimension" else self.send "#{dimension}_raters" - end + end end module ClassMethods - + def letsrate_rater - has_many :ratings_given, :class_name => "Rate", :foreign_key => :rater_id - end - + has_many :ratings_given, :class_name => "Rate", :foreign_key => :rater_id + end + def letsrate_rateable(*dimensions) has_many :rates_without_dimension, :as => :rateable, :class_name => "Rate", :dependent => :destroy, :conditions => {:dimension => nil} - has_many :raters_without_dimension, :through => :rates_without_dimension, :source => :rater - - has_one :rate_average_without_dimension, :as => :cacheable, :class_name => "RatingCache", + has_many :raters_without_dimension, :through => :rates_without_dimension, :source => :rater + + has_one :rate_average_without_dimension, :as => :cacheable, :class_name => "RatingCache", :dependent => :destroy, :conditions => {:dimension => nil} - - dimensions.each do |dimension| - has_many "#{dimension}_rates", :dependent => :destroy, - :conditions => {:dimension => dimension.to_s}, - :class_name => "Rate", + + dimensions.each do |dimension| + has_many "#{dimension}_rates", :dependent => :destroy, + :conditions => {:dimension => dimension.to_s}, + :class_name => "Rate", :as => :rateable - - has_many "#{dimension}_raters", :through => "#{dimension}_rates", :source => :rater - - has_one "#{dimension}_average", :as => :cacheable, :class_name => "RatingCache", + + has_many "#{dimension}_raters", :through => "#{dimension}_rates", :source => :rater + + has_one "#{dimension}_average", :as => :cacheable, :class_name => "RatingCache", :dependent => :destroy, :conditions => {:dimension => dimension.to_s} - end + end end end - -end + +end class ActiveRecord::Base include Letsrate -end \ No newline at end of file +end From b08a434c144bd1928d5ecbd1f68794ee0c4d183c Mon Sep 17 00:00:00 2001 From: Anton Orel Date: Sun, 14 Jul 2013 16:53:16 +0400 Subject: [PATCH 06/20] Code optimization --- .../letsrate/templates/rater_controller.rb | 27 +++++------ lib/letsrate/helpers.rb | 14 ++---- lib/letsrate/model.rb | 47 ++++++------------- 3 files changed, 29 insertions(+), 59 deletions(-) diff --git a/lib/generators/letsrate/templates/rater_controller.rb b/lib/generators/letsrate/templates/rater_controller.rb index 5e66975..7a4bd05 100644 --- a/lib/generators/letsrate/templates/rater_controller.rb +++ b/lib/generators/letsrate/templates/rater_controller.rb @@ -1,19 +1,14 @@ -class RaterController < ApplicationController - - def create - if current_user.present? +class RaterController < ApplicationController + + def create + if user_signed_in? obj = params[:klass].classify.constantize.find(params[:id]) - if params[:dimension].present? - obj.rate params[:score].to_i, current_user.id, "#{params[:dimension]}" - else - obj.rate params[:score].to_i, current_user.id - end - - render :json => true + obj.rate params[:score].to_i, current_user, params[:dimension] + + render :json => true else - render :json => false + render :json => false end - end - - -end \ No newline at end of file + end + +end diff --git a/lib/letsrate/helpers.rb b/lib/letsrate/helpers.rb index d849b92..247342b 100644 --- a/lib/letsrate/helpers.rb +++ b/lib/letsrate/helpers.rb @@ -1,17 +1,9 @@ module Helpers def rating_for(rateable_obj, dimension=nil, options={}) - if dimension.nil? - klass = rateable_obj.average - else - klass = rateable_obj.average "#{dimension}" - end + cached_average = rateable_obj.average dimension - if klass.nil? - avg = 0 - else - avg = klass.avg - end + avg = cached_average ? cached_average.avg : 0 star = options[:star] || 5 @@ -19,7 +11,7 @@ def rating_for(rateable_obj, dimension=nil, options={}) readonly = false if disable_after_rate - readonly = current_user.present? ? !rateable_obj.can_rate?(current_user.id, dimension) : true + readonly = current_user ? !rateable_obj.can_rate?(current_user, dimension) : true end content_tag :div, '', "data-dimension" => dimension, :class => "star", "data-rating" => avg, diff --git a/lib/letsrate/model.rb b/lib/letsrate/model.rb index 5b502a3..66cdfba 100644 --- a/lib/letsrate/model.rb +++ b/lib/letsrate/model.rb @@ -2,12 +2,13 @@ module Letsrate extend ActiveSupport::Concern - def rate(stars, user_id, dimension=nil) - if can_rate? user_id, dimension - rates(dimension).build do |r| + def rate(stars, user, dimension=nil) + dimension = nil if dimension.blank? + + if can_rate? user, dimension + rates(dimension).create! do |r| r.stars = stars - r.rater_id = user_id - r.save! + r.rater = user end update_rate_average(stars, dimension) else @@ -17,53 +18,35 @@ def rate(stars, user_id, dimension=nil) def update_rate_average(stars, dimension=nil) if average(dimension).nil? - RatingCache.create do |avg| + RatingCache.create! do |avg| avg.cacheable_id = self.id avg.cacheable_type = self.class.name avg.avg = stars avg.qty = 1 avg.dimension = dimension - avg.save! end else a = average(dimension) - a.avg = (a.avg*a.qty + stars) / (a.qty+1) - a.qty = a.qty + 1 - a.save! + a.qty = rates(dimension).count + a.avg = a.qty / raters(dimension).count + a.save!(validate: false) end end def average(dimension=nil) - if dimension.nil? - self.send "rate_average_without_dimension" - else - self.send "#{dimension}_average" - end + dimension ? self.send("#{dimension}_average") : rate_average_without_dimension end - def can_rate?(user_id, dimension=nil) - val = self.connection.select_value("select count(*) as cnt from rates where rateable_id=#{self.id} and rateable_type='#{self.class.name}' and rater_id=#{user_id} and dimension='#{dimension}'").to_i - if val == 0 - true - else - false - end + def can_rate?(user, dimension=nil) + user.ratings_given.where(dimension: dimension, rateable_id: id, rateable_type: self.class.name).size.zero? end def rates(dimension=nil) - if dimension.nil? - self.send "rates_without_dimension" - else - self.send "#{dimension}_rates" - end + dimension ? self.send("#{dimension}_rates") : rates_without_dimension end def raters(dimension=nil) - if dimension.nil? - self.send "raters_without_dimension" - else - self.send "#{dimension}_raters" - end + dimension ? self.send("#{dimension}_raters") : raters_without_dimension end module ClassMethods From 3e9fd8ffed77a6d1432fe1ae79a8d4c8dce5960c Mon Sep 17 00:00:00 2001 From: Anton Orel Date: Sun, 14 Jul 2013 20:31:04 +0400 Subject: [PATCH 07/20] Fixed readonly logic --- lib/letsrate/helpers.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/letsrate/helpers.rb b/lib/letsrate/helpers.rb index 247342b..9d0085d 100644 --- a/lib/letsrate/helpers.rb +++ b/lib/letsrate/helpers.rb @@ -9,10 +9,9 @@ def rating_for(rateable_obj, dimension=nil, options={}) disable_after_rate = options[:disable_after_rate] || false - readonly = false - if disable_after_rate - readonly = current_user ? !rateable_obj.can_rate?(current_user, dimension) : true - end + readonly = !(current_user && rateable_obj.can_rate?(current_user, dimension)) + + disable_after_rate = current_user && disable_after_rate content_tag :div, '', "data-dimension" => dimension, :class => "star", "data-rating" => avg, "data-id" => rateable_obj.id, "data-classname" => rateable_obj.class.name, From 31c8d615b76b37ec5f3b7022c5e1244c22682c3e Mon Sep 17 00:00:00 2001 From: Anton Orel Date: Sun, 14 Jul 2013 22:49:19 +0400 Subject: [PATCH 08/20] Reimplemented disable after rate option --- lib/generators/letsrate/letsrate_generator.rb | 26 +++++++------- lib/generators/letsrate/templates/letsrate.js | 36 ------------------- .../letsrate/templates/letsrate.js.coffee.erb | 36 +++++++++++++++++++ lib/letsrate/helpers.rb | 4 +-- 4 files changed, 50 insertions(+), 52 deletions(-) delete mode 100644 lib/generators/letsrate/templates/letsrate.js create mode 100644 lib/generators/letsrate/templates/letsrate.js.coffee.erb diff --git a/lib/generators/letsrate/letsrate_generator.rb b/lib/generators/letsrate/letsrate_generator.rb index ec35dab..a1677ee 100644 --- a/lib/generators/letsrate/letsrate_generator.rb +++ b/lib/generators/letsrate/letsrate_generator.rb @@ -2,28 +2,28 @@ require 'rails/generators/active_record' class LetsrateGenerator < ActiveRecord::Generators::Base include Rails::Generators::Migration - - source_root File.expand_path('../templates', __FILE__) - + + source_root File.expand_path('../templates', __FILE__) + desc "copying jquery.raty files to assets directory ..." def copying copy_file 'jquery.raty.js', 'app/assets/javascripts/jquery.raty.js' copy_file 'star-on.png', 'app/assets/images/star-on.png' copy_file 'star-off.png', 'app/assets/images/star-off.png' copy_file 'star-half.png', 'app/assets/images/star-half.png' - copy_file 'letsrate.js', 'app/assets/javascripts/letsrate.js.erb' + copy_file 'letsrate.js.cofee.erb', 'app/assets/javascripts/letsrate.js.coffee.erb' copy_file 'rater_controller.rb', 'app/controllers/rater_controller.rb' - end - + end + desc "model is creating..." - def create_model + def create_model model_file = File.join('app/models', "#{file_path}.rb") raise "User model (#{model_file}) must exits." unless File.exists?(model_file) class_collisions 'Rate' - template 'model.rb', File.join('app/models', "rate.rb") + template 'model.rb', File.join('app/models', "rate.rb") template 'cache_model.rb', File.join('app/models', "rating_cache.rb") - end - + end + def add_rate_path_to_route route "match '/rate' => 'rater#create', :as => 'rate'" end @@ -32,9 +32,9 @@ def add_rate_path_to_route def create_cacheable_migration migration_template "cache_migration.rb", "db/migrate/create_rating_caches.rb" end - + desc "migration is creating ..." def create_migration - migration_template "migration.rb", "db/migrate/create_rates.rb" + migration_template "migration.rb", "db/migrate/create_rates.rb" end -end \ No newline at end of file +end diff --git a/lib/generators/letsrate/templates/letsrate.js b/lib/generators/letsrate/templates/letsrate.js deleted file mode 100644 index f2abb8d..0000000 --- a/lib/generators/letsrate/templates/letsrate.js +++ /dev/null @@ -1,36 +0,0 @@ -$.fn.raty.defaults.path = "/assets"; -$.fn.raty.defaults.half_show = true; - -$(function(){ - $(".star").each(function() { - var $readonly = ($(this).attr('data-readonly') == 'true'); - $(this).raty({ - score: function(){ - return $(this).attr('data-rating') - }, - number: function() { - return $(this).attr('data-star-count') - }, - readOnly: $readonly, - click: function(score, evt) { - var _this = this; - $.post('<%= Rails.application.class.routes.url_helpers.rate_path %>', - { - score: score, - dimension: $(this).attr('data-dimension'), - id: $(this).attr('data-id'), - klass: $(this).attr('data-classname') - }, - function(data) { - if(data) { - // success code goes here ... - - if ($(_this).attr('data-disable-after-rate') == 'true') { - $(_this).raty('set', { readOnly: true, score: score }); - } - } - }); - } - }); - }); -}); diff --git a/lib/generators/letsrate/templates/letsrate.js.coffee.erb b/lib/generators/letsrate/templates/letsrate.js.coffee.erb new file mode 100644 index 0000000..d564335 --- /dev/null +++ b/lib/generators/letsrate/templates/letsrate.js.coffee.erb @@ -0,0 +1,36 @@ +$.fn.raty.defaults.path = "/assets" +$.fn.raty.defaults.half_show = true +$ -> + $(".star").css opacity: "0.35" + $(".star").hover (-> + $(this).css opacity: "1" + ), -> + $(this).css opacity: "0.35" + + $(".star").raty + half: true, + readOnly: -> + $(this).data("readonly") == 'true' + + score: -> + $(this).data "rating" + + number: -> + $(this).data "star-count" + + click: (score, evt) -> + el = $(this) + + $.post "<%= Rails.application.class.routes.url_helpers.rate_path %>", + + score: score + dimension: $(this).data("dimension") + id: $(this).data("id") + klass: $(this).data("classname") + , (data) -> + if el.attr('data-disable-after-rate') == 'true' + el.raty('readOnly', true) + + data + + undefined diff --git a/lib/letsrate/helpers.rb b/lib/letsrate/helpers.rb index 9d0085d..1122c17 100644 --- a/lib/letsrate/helpers.rb +++ b/lib/letsrate/helpers.rb @@ -7,12 +7,10 @@ def rating_for(rateable_obj, dimension=nil, options={}) star = options[:star] || 5 - disable_after_rate = options[:disable_after_rate] || false + disable_after_rate = options[:disable_after_rate] || true readonly = !(current_user && rateable_obj.can_rate?(current_user, dimension)) - disable_after_rate = current_user && disable_after_rate - content_tag :div, '', "data-dimension" => dimension, :class => "star", "data-rating" => avg, "data-id" => rateable_obj.id, "data-classname" => rateable_obj.class.name, "data-disable-after-rate" => disable_after_rate, From d675cdab2cdbe17a75851f07941129e5f76b3e70 Mon Sep 17 00:00:00 2001 From: Anton Orel Date: Sun, 14 Jul 2013 23:34:54 +0400 Subject: [PATCH 09/20] Fixed calculation of average --- lib/letsrate/model.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/letsrate/model.rb b/lib/letsrate/model.rb index 66cdfba..4df81b0 100644 --- a/lib/letsrate/model.rb +++ b/lib/letsrate/model.rb @@ -28,7 +28,7 @@ def update_rate_average(stars, dimension=nil) else a = average(dimension) a.qty = rates(dimension).count - a.avg = a.qty / raters(dimension).count + a.avg = rates(dimension).average(:stars) a.save!(validate: false) end end From 7835ec039163703432aa957574a26c039f1efff1 Mon Sep 17 00:00:00 2001 From: Denisse Date: Wed, 14 Aug 2013 10:30:21 -0400 Subject: [PATCH 10/20] [FEATURE] Add average calculation method Based on Dirichlet prior probability distribution Sponsored by: CentronetMarketing, MovingDirectory --- lib/letsrate/model.rb | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/lib/letsrate/model.rb b/lib/letsrate/model.rb index 4df81b0..094d916 100644 --- a/lib/letsrate/model.rb +++ b/lib/letsrate/model.rb @@ -2,7 +2,7 @@ module Letsrate extend ActiveSupport::Concern - def rate(stars, user, dimension=nil) + def rate(stars, user, dimension=nil, dirichlet_method=false) dimension = nil if dimension.blank? if can_rate? user, dimension @@ -10,12 +10,40 @@ def rate(stars, user, dimension=nil) r.stars = stars r.rater = user end - update_rate_average(stars, dimension) + if dirichlet_method + update_rate_average_dirichlet(stars, dimension) + else + update_rate_average(stars, dimension) + end else raise "User has already rated." 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 + else + a = average(dimension) + a.qty = rates(dimension).count + a.avg = davg + a.save!(validate: false) + end + end + def update_rate_average(stars, dimension=nil) if average(dimension).nil? RatingCache.create! do |avg| From c682fff6d7da8a13e7fd4a7324c36b4c44aa0e8e Mon Sep 17 00:00:00 2001 From: Tommy Back Date: Tue, 19 Nov 2013 14:00:12 +0100 Subject: [PATCH 11/20] Fixed broken acossiations in Rails 4. --- lib/letsrate/model.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/letsrate/model.rb b/lib/letsrate/model.rb index 4df81b0..703592f 100644 --- a/lib/letsrate/model.rb +++ b/lib/letsrate/model.rb @@ -64,15 +64,15 @@ def letsrate_rateable(*dimensions) dimensions.each do |dimension| - has_many "#{dimension}_rates", :dependent => :destroy, - :conditions => {:dimension => dimension.to_s}, - :class_name => "Rate", - :as => :rateable + has_many "#{dimension}_rates".to_sym, :dependent => :destroy, + :conditions => {:dimension => dimension.to_s}, + :class_name => "Rate", + :as => :rateable - has_many "#{dimension}_raters", :through => "#{dimension}_rates", :source => :rater + has_many "#{dimension}_raters".to_sym, :through => "#{dimension}_rates", :source => :rater - has_one "#{dimension}_average", :as => :cacheable, :class_name => "RatingCache", - :dependent => :destroy, :conditions => {:dimension => dimension.to_s} + has_one "#{dimension}_average".to_sym, :as => :cacheable, :class_name => "RatingCache", + :dependent => :destroy, :conditions => {:dimension => dimension.to_s} end end end From da3243d500df6c34e23fc908d1e198e87997bc0a Mon Sep 17 00:00:00 2001 From: Murat GUZEL Date: Tue, 31 Dec 2013 12:05:09 +0200 Subject: [PATCH 12/20] rails 4 implementation --- lib/generators/letsrate/letsrate_generator.rb | 2 +- .../letsrate/templates/cache_migration.rb | 8 +++---- .../letsrate/templates/cache_model.rb | 2 +- .../letsrate/templates/jquery.raty.js | 10 ++++----- .../letsrate/templates/migration.rb | 6 +++--- lib/generators/letsrate/templates/model.rb | 6 +++--- lib/letsrate/model.rb | 21 ++++++++++--------- 7 files changed, 28 insertions(+), 27 deletions(-) diff --git a/lib/generators/letsrate/letsrate_generator.rb b/lib/generators/letsrate/letsrate_generator.rb index a1677ee..7312411 100644 --- a/lib/generators/letsrate/letsrate_generator.rb +++ b/lib/generators/letsrate/letsrate_generator.rb @@ -25,7 +25,7 @@ def create_model end def add_rate_path_to_route - route "match '/rate' => 'rater#create', :as => 'rate'" + route "post '/rate' => 'rater#create', :as => 'rate'" end desc "cacheable rating average migration is creating ..." diff --git a/lib/generators/letsrate/templates/cache_migration.rb b/lib/generators/letsrate/templates/cache_migration.rb index db29d55..8eb063a 100644 --- a/lib/generators/letsrate/templates/cache_migration.rb +++ b/lib/generators/letsrate/templates/cache_migration.rb @@ -1,9 +1,9 @@ class CreateRatingCaches < ActiveRecord::Migration - + def self.up create_table :rating_caches do |t| t.belongs_to :cacheable, :polymorphic => true - t.float :avg, :null => false + t.float :avg, :null => false t.integer :qty, :null => false t.string :dimension t.timestamps @@ -14,6 +14,6 @@ def self.up def self.down drop_table :rating_caches - end - + end + end \ No newline at end of file diff --git a/lib/generators/letsrate/templates/cache_model.rb b/lib/generators/letsrate/templates/cache_model.rb index 74d9e0a..1a2b2eb 100644 --- a/lib/generators/letsrate/templates/cache_model.rb +++ b/lib/generators/letsrate/templates/cache_model.rb @@ -1,3 +1,3 @@ class RatingCache < ActiveRecord::Base - belongs_to :cacheable, :polymorphic => true + belongs_to :cacheable, :polymorphic => true end \ No newline at end of file diff --git a/lib/generators/letsrate/templates/jquery.raty.js b/lib/generators/letsrate/templates/jquery.raty.js index 53d369b..26f53bf 100644 --- a/lib/generators/letsrate/templates/jquery.raty.js +++ b/lib/generators/letsrate/templates/jquery.raty.js @@ -27,7 +27,7 @@ return this.each(function() { var self = this, $this = $(self).empty(); - + self.opt = $.extend(true, {}, $.fn.raty.defaults, settings); $this.data('settings', self.opt); @@ -47,7 +47,7 @@ } if (self.opt.score) { - self.opt.score = methods.between(self.opt.score, 0, self.opt.number); + self.opt.score = methods.between(self.opt.score, 0, self.opt.number); } for (var i = 1; i <= self.opt.number; i++) { @@ -71,7 +71,7 @@ } if (self.opt.iconRange) { - methods.fill.call(self, self.opt.score); + methods.fill.call(self, self.opt.score); } methods.setTarget.call(self, self.opt.score, self.opt.targetKeep); @@ -186,7 +186,7 @@ }); }, cancel: function(isClick) { return $(this).each(function() { - var self = this, + var self = this, $this = $(self); if ($this.data('readonly') === true) { @@ -424,7 +424,7 @@ return methods.init.apply(this, arguments); } else { $.error('Method ' + method + ' does not exist!'); - } + } }; $.fn.raty.defaults = { diff --git a/lib/generators/letsrate/templates/migration.rb b/lib/generators/letsrate/templates/migration.rb index 20aca0d..a15dc84 100644 --- a/lib/generators/letsrate/templates/migration.rb +++ b/lib/generators/letsrate/templates/migration.rb @@ -1,5 +1,5 @@ class CreateRates < ActiveRecord::Migration - + def self.up create_table :rates do |t| t.belongs_to :rater @@ -15,6 +15,6 @@ def self.up def self.down drop_table :rates - end - + end + end \ No newline at end of file diff --git a/lib/generators/letsrate/templates/model.rb b/lib/generators/letsrate/templates/model.rb index 6ffa934..fd148e2 100644 --- a/lib/generators/letsrate/templates/model.rb +++ b/lib/generators/letsrate/templates/model.rb @@ -1,7 +1,7 @@ class Rate < ActiveRecord::Base belongs_to :rater, :class_name => "<%= file_name.classify %>" belongs_to :rateable, :polymorphic => true - - attr_accessible :rate, :dimension - + + #attr_accessible :rate, :dimension + end \ No newline at end of file diff --git a/lib/letsrate/model.rb b/lib/letsrate/model.rb index 68f0539..4ae1e5b 100644 --- a/lib/letsrate/model.rb +++ b/lib/letsrate/model.rb @@ -10,7 +10,7 @@ def rate(stars, user, dimension=nil, dirichlet_method=false) r.stars = stars r.rater = user end - if dirichlet_method + if dirichlet_method update_rate_average_dirichlet(stars, dimension) else update_rate_average(stars, dimension) @@ -27,7 +27,7 @@ def update_rate_average_dirichlet(stars, dimension=nil) 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 @@ -43,7 +43,7 @@ def update_rate_average_dirichlet(stars, dimension=nil) a.save!(validate: false) end end - + def update_rate_average(stars, dimension=nil) if average(dimension).nil? RatingCache.create! do |avg| @@ -84,23 +84,24 @@ def letsrate_rater end def letsrate_rateable(*dimensions) - has_many :rates_without_dimension, :as => :rateable, :class_name => "Rate", :dependent => :destroy, :conditions => {:dimension => nil} + has_many :rates_without_dimension, -> { where dimension: nil}, :as => :rateable, :class_name => "Rate", :dependent => :destroy has_many :raters_without_dimension, :through => :rates_without_dimension, :source => :rater - has_one :rate_average_without_dimension, :as => :cacheable, :class_name => "RatingCache", - :dependent => :destroy, :conditions => {:dimension => nil} + has_one :rate_average_without_dimension, -> { where dimension: nil}, :as => :cacheable, + :class_name => "RatingCache", :dependent => :destroy dimensions.each do |dimension| - has_many "#{dimension}_rates".to_sym, :dependent => :destroy, - :conditions => {:dimension => dimension.to_s}, + has_many "#{dimension}_rates".to_sym, -> {where dimension: dimension.to_s}, + :dependent => :destroy, :class_name => "Rate", :as => :rateable has_many "#{dimension}_raters".to_sym, :through => "#{dimension}_rates", :source => :rater - has_one "#{dimension}_average".to_sym, :as => :cacheable, :class_name => "RatingCache", - :dependent => :destroy, :conditions => {:dimension => dimension.to_s} + has_one "#{dimension}_average".to_sym, -> { where dimension: dimension.to_s }, + :as => :cacheable, :class_name => "RatingCache", + :dependent => :destroy end end end From 7e360403435d5023d0bfc06fced82b32a20306e2 Mon Sep 17 00:00:00 2001 From: Murat GUZEL Date: Tue, 31 Dec 2013 13:42:24 +0200 Subject: [PATCH 13/20] coffee script name is changed --- lib/generators/letsrate/letsrate_generator.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/generators/letsrate/letsrate_generator.rb b/lib/generators/letsrate/letsrate_generator.rb index 7312411..d5a2c2d 100644 --- a/lib/generators/letsrate/letsrate_generator.rb +++ b/lib/generators/letsrate/letsrate_generator.rb @@ -11,7 +11,7 @@ def copying copy_file 'star-on.png', 'app/assets/images/star-on.png' copy_file 'star-off.png', 'app/assets/images/star-off.png' copy_file 'star-half.png', 'app/assets/images/star-half.png' - copy_file 'letsrate.js.cofee.erb', 'app/assets/javascripts/letsrate.js.coffee.erb' + copy_file 'letsrate.js.coffee.erb', 'app/assets/javascripts/letsrate.js.coffee.erb' copy_file 'rater_controller.rb', 'app/controllers/rater_controller.rb' end From cf5922404e024f23fe22e7c518161be94c244f94 Mon Sep 17 00:00:00 2001 From: Murat GUZEL Date: Thu, 2 Jan 2014 09:54:44 +0200 Subject: [PATCH 14/20] letsrate.js.erb is changed --- .../letsrate/templates/letsrate.js.coffee.erb | 36 ------------------- .../letsrate/templates/letsrate.js.erb | 36 +++++++++++++++++++ lib/letsrate/helpers.rb | 6 ++-- 3 files changed, 39 insertions(+), 39 deletions(-) delete mode 100644 lib/generators/letsrate/templates/letsrate.js.coffee.erb create mode 100644 lib/generators/letsrate/templates/letsrate.js.erb diff --git a/lib/generators/letsrate/templates/letsrate.js.coffee.erb b/lib/generators/letsrate/templates/letsrate.js.coffee.erb deleted file mode 100644 index d564335..0000000 --- a/lib/generators/letsrate/templates/letsrate.js.coffee.erb +++ /dev/null @@ -1,36 +0,0 @@ -$.fn.raty.defaults.path = "/assets" -$.fn.raty.defaults.half_show = true -$ -> - $(".star").css opacity: "0.35" - $(".star").hover (-> - $(this).css opacity: "1" - ), -> - $(this).css opacity: "0.35" - - $(".star").raty - half: true, - readOnly: -> - $(this).data("readonly") == 'true' - - score: -> - $(this).data "rating" - - number: -> - $(this).data "star-count" - - click: (score, evt) -> - el = $(this) - - $.post "<%= Rails.application.class.routes.url_helpers.rate_path %>", - - score: score - dimension: $(this).data("dimension") - id: $(this).data("id") - klass: $(this).data("classname") - , (data) -> - if el.attr('data-disable-after-rate') == 'true' - el.raty('readOnly', true) - - data - - undefined diff --git a/lib/generators/letsrate/templates/letsrate.js.erb b/lib/generators/letsrate/templates/letsrate.js.erb new file mode 100644 index 0000000..83a4ff8 --- /dev/null +++ b/lib/generators/letsrate/templates/letsrate.js.erb @@ -0,0 +1,36 @@ +$.fn.raty.defaults.path = "/assets"; +$.fn.raty.defaults.half_show = true; + +$(function(){ + $(".star").each(function() { + var $readonly = ($(this).attr('data-readonly') == 'true'); + $(this).raty({ + score: function(){ + return $(this).attr('data-rating') + }, + number: function() { + return $(this).attr('data-star-count') + }, + readOnly: $readonly, + click: function(score, evt) { + var _this = this; + $.post('<%= Rails.application.class.routes.url_helpers.rate_path %>', + { + score: score, + dimension: $(this).attr('data-dimension'), + id: $(this).attr('data-id'), + klass: $(this).attr('data-classname') + }, + function(data) { + if(data) { + // success code goes here ... + + if ($(_this).attr('data-disable-after-rate') == 'true') { + $(_this).raty('set', { readOnly: true, score: score }); + } + } + }); + } + }); + }); +}); \ No newline at end of file diff --git a/lib/letsrate/helpers.rb b/lib/letsrate/helpers.rb index fd74fdd..c2130a0 100644 --- a/lib/letsrate/helpers.rb +++ b/lib/letsrate/helpers.rb @@ -17,7 +17,7 @@ def rating_for(rateable_obj, dimension=nil, options={}) "data-readonly" => readonly, "data-star-count" => star end - + def rating_for_user(rateable_obj, rating_user, dimension = nil, options = {}) @object = rateable_obj @user = rating_user @@ -25,12 +25,12 @@ def rating_for_user(rateable_obj, rating_user, dimension = nil, options = {}) stars = @rating ? @rating.stars : 0 disable_after_rate = options[:disable_after_rate] || false - + readonly=false if disable_after_rate readonly = current_user.present? ? !rateable_obj.can_rate?(current_user.id, dimension) : true end - + content_tag :div, '', "data-dimension" => dimension, :class => "star", "data-rating" => stars, "data-id" => rateable_obj.id, "data-classname" => rateable_obj.class.name, "data-disable-after-rate" => disable_after_rate, From 3174378fd8f60ab82c69a8cf05e8e8f215b16313 Mon Sep 17 00:00:00 2001 From: Murat GUZEL Date: Thu, 2 Jan 2014 10:04:12 +0200 Subject: [PATCH 15/20] generator is changed --- lib/generators/letsrate/letsrate_generator.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/generators/letsrate/letsrate_generator.rb b/lib/generators/letsrate/letsrate_generator.rb index d5a2c2d..825aef6 100644 --- a/lib/generators/letsrate/letsrate_generator.rb +++ b/lib/generators/letsrate/letsrate_generator.rb @@ -11,7 +11,7 @@ def copying copy_file 'star-on.png', 'app/assets/images/star-on.png' copy_file 'star-off.png', 'app/assets/images/star-off.png' copy_file 'star-half.png', 'app/assets/images/star-half.png' - copy_file 'letsrate.js.coffee.erb', 'app/assets/javascripts/letsrate.js.coffee.erb' + copy_file 'letsrate.js.erb', 'app/assets/javascripts/letsrate.js.erb' copy_file 'rater_controller.rb', 'app/controllers/rater_controller.rb' end From 0cf0e5d7a60e49196854d170cc8978a3e0648cc5 Mon Sep 17 00:00:00 2001 From: Murat GUZEL Date: Thu, 2 Jan 2014 10:40:40 +0200 Subject: [PATCH 16/20] readme --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index db582d0..e9d049e 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,12 @@ Speed : <%= rating_for @car, "engine", :star => 7 %> Speed : <%= rating_for @car, "price" %> ``` +You can use the rating_for_user helper method to show the star rating for the user. + +```erb +Speed : <%= rating_for_user @car, current_user, "speed", :star => 10 %> +``` + ## Feedback If you find bugs please open a ticket at [https://github.com/muratguzel/letsrate/issues](https://github.com/muratguzel/letsrate/issues) From 4c7049e86f1718501fe4da22f1292176d1ed3fab Mon Sep 17 00:00:00 2001 From: Murat GUZEL Date: Thu, 2 Jan 2014 10:48:42 +0200 Subject: [PATCH 17/20] 1.0.9 --- .travis.yml | 5 +-- Gemfile | 2 +- Gemfile.lock | 77 +++++++++++++++++------------------------ lib/letsrate/version.rb | 2 +- 4 files changed, 36 insertions(+), 50 deletions(-) diff --git a/.travis.yml b/.travis.yml index bd227bb..64cb262 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,8 @@ language: ruby -rvm: +rvm: - "1.9.2" - - "1.9.3" + - "1.9.3" + - "2.0.0" - jruby-19mode # JRuby in 1.9 mode - rbx-18mode - rbx-19mode diff --git a/Gemfile b/Gemfile index 7c23576..64b3d4d 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,4 @@ -source "http://rubygems.org" +source "http://rubygems.org" gem 'jquery-rails' diff --git a/Gemfile.lock b/Gemfile.lock index 9a4df5a..3180bfa 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,60 +1,45 @@ PATH remote: . specs: - letsrate (1.0.8) + letsrate (1.0.9) GEM remote: http://rubygems.org/ specs: - actionpack (3.2.2) - activemodel (= 3.2.2) - activesupport (= 3.2.2) - builder (~> 3.0.0) + actionpack (4.0.2) + activesupport (= 4.0.2) + builder (~> 3.1.0) erubis (~> 2.7.0) - journey (~> 1.0.1) - rack (~> 1.4.0) - rack-cache (~> 1.1) - rack-test (~> 0.6.1) - sprockets (~> 2.1.2) - activemodel (3.2.2) - activesupport (= 3.2.2) - builder (~> 3.0.0) - activesupport (3.2.2) - i18n (~> 0.6) - multi_json (~> 1.0) - builder (3.0.0) + rack (~> 1.5.2) + rack-test (~> 0.6.2) + activesupport (4.0.2) + i18n (~> 0.6, >= 0.6.4) + minitest (~> 4.2) + multi_json (~> 1.3) + thread_safe (~> 0.1) + tzinfo (~> 0.3.37) + atomic (1.1.14) + builder (3.1.4) erubis (2.7.0) - hike (1.2.1) - i18n (0.6.0) - journey (1.0.3) - jquery-rails (2.0.1) - railties (< 5.0, >= 3.2.0) - thor (~> 0.14) - json (1.6.5) - multi_json (1.1.0) - rack (1.4.1) - rack-cache (1.2) - rack (>= 0.4) - rack-ssl (1.3.2) - rack - rack-test (0.6.1) + i18n (0.6.9) + jquery-rails (3.0.4) + railties (>= 3.0, < 5.0) + thor (>= 0.14, < 2.0) + minitest (4.7.5) + multi_json (1.8.2) + rack (1.5.2) + rack-test (0.6.2) rack (>= 1.0) - railties (3.2.2) - actionpack (= 3.2.2) - activesupport (= 3.2.2) - rack-ssl (~> 1.3.2) + railties (4.0.2) + actionpack (= 4.0.2) + activesupport (= 4.0.2) rake (>= 0.8.7) - rdoc (~> 3.4) - thor (~> 0.14.6) - rake (0.9.2.2) - rdoc (3.12) - json (~> 1.4) - sprockets (2.1.2) - hike (~> 1.2) - rack (~> 1.0) - tilt (!= 1.3.0, ~> 1.1) - thor (0.14.6) - tilt (1.3.3) + thor (>= 0.18.1, < 2.0) + rake (10.1.1) + thor (0.18.1) + thread_safe (0.1.3) + atomic + tzinfo (0.3.38) PLATFORMS ruby diff --git a/lib/letsrate/version.rb b/lib/letsrate/version.rb index 6425c87..eed8328 100644 --- a/lib/letsrate/version.rb +++ b/lib/letsrate/version.rb @@ -1,3 +1,3 @@ module Letsrate - VERSION = "1.0.8" + VERSION = "1.0.9" end \ No newline at end of file From dcafe1cba46781dcfbfccdedc21f1cae47027497 Mon Sep 17 00:00:00 2001 From: Murat GUZEL Date: Thu, 2 Jan 2014 11:03:10 +0200 Subject: [PATCH 18/20] jruby is removed --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 64cb262..53bca8b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,6 @@ rvm: - "1.9.2" - "1.9.3" - "2.0.0" - - jruby-19mode # JRuby in 1.9 mode - rbx-18mode - rbx-19mode # uncomment this line if your project needs to run something other than `rake`: From 39b7e3bc427e2949a3fddd720d5f14a7b6f2b837 Mon Sep 17 00:00:00 2001 From: James Naadjie Date: Tue, 13 May 2014 20:14:31 -0400 Subject: [PATCH 19/20] create_migration method def changed to create_letsrate_migration to avoid collision with rails create_migration method --- lib/generators/letsrate/letsrate_generator.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/generators/letsrate/letsrate_generator.rb b/lib/generators/letsrate/letsrate_generator.rb index 825aef6..c9bd0eb 100644 --- a/lib/generators/letsrate/letsrate_generator.rb +++ b/lib/generators/letsrate/letsrate_generator.rb @@ -34,7 +34,7 @@ def create_cacheable_migration end desc "migration is creating ..." - def create_migration + def create_letsrate_migration migration_template "migration.rb", "db/migrate/create_rates.rb" end end From b6b5087ba1d9774974016619f88b4068ead28c50 Mon Sep 17 00:00:00 2001 From: Lan Nguyen Date: Mon, 2 Jun 2014 21:54:20 +0700 Subject: [PATCH 20/20] Add rerate --- lib/letsrate/model.rb | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/letsrate/model.rb b/lib/letsrate/model.rb index 4ae1e5b..d1ab93e 100644 --- a/lib/letsrate/model.rb +++ b/lib/letsrate/model.rb @@ -10,13 +10,16 @@ def rate(stars, user, dimension=nil, dirichlet_method=false) r.stars = stars r.rater = user end - if dirichlet_method - update_rate_average_dirichlet(stars, dimension) - else - update_rate_average(stars, dimension) - end else - raise "User has already rated." + previous_rate = rates(dimension).where(:rater_id => user_id).first + previous_rate.stars = stars + previous_rate.save! + end + + if dirichlet_method + update_rate_average_dirichlet(stars, dimension) + else + update_rate_average(stars, dimension) end end