ratyrate 1.2.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/.travis.yml +5 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +51 -0
- data/README.md +169 -0
- data/Rakefile +12 -0
- data/lib/generators/ratyrate/USAGE +0 -0
- data/lib/generators/ratyrate/ratyrate_generator.rb +56 -0
- data/lib/generators/ratyrate/templates/average_cache_migration.rb +17 -0
- data/lib/generators/ratyrate/templates/average_cache_model.rb +4 -0
- data/lib/generators/ratyrate/templates/big-star.png +0 -0
- data/lib/generators/ratyrate/templates/cache_migration.rb +19 -0
- data/lib/generators/ratyrate/templates/cache_model.rb +3 -0
- data/lib/generators/ratyrate/templates/cancel-off.png +0 -0
- data/lib/generators/ratyrate/templates/cancel-on.png +0 -0
- data/lib/generators/ratyrate/templates/jquery.raty.js +464 -0
- data/lib/generators/ratyrate/templates/mid-star.png +0 -0
- data/lib/generators/ratyrate/templates/migration.rb +20 -0
- data/lib/generators/ratyrate/templates/model.rb +7 -0
- data/lib/generators/ratyrate/templates/overall_average_migration.rb +16 -0
- data/lib/generators/ratyrate/templates/overall_average_model.rb +4 -0
- data/lib/generators/ratyrate/templates/rater_controller.rb +13 -0
- data/lib/generators/ratyrate/templates/ratyrate.js.erb +59 -0
- data/lib/generators/ratyrate/templates/star-half.png +0 -0
- data/lib/generators/ratyrate/templates/star-off.png +0 -0
- data/lib/generators/ratyrate/templates/star-on.png +0 -0
- data/lib/ratyrate/helpers.rb +144 -0
- data/lib/ratyrate/model.rb +153 -0
- data/lib/ratyrate/version.rb +3 -0
- data/lib/ratyrate.rb +7 -0
- data/ratyrate.gemspec +24 -0
- metadata +76 -0
@@ -0,0 +1,144 @@
|
|
1
|
+
module Helpers
|
2
|
+
def rating_for(rateable_obj, dimension=nil, options={})
|
3
|
+
|
4
|
+
cached_average = rateable_obj.average dimension
|
5
|
+
avg = cached_average ? cached_average.avg : 0
|
6
|
+
|
7
|
+
star = options[:star] || 5
|
8
|
+
enable_half = options[:enable_half] || true
|
9
|
+
half_show = options[:half_show] || true
|
10
|
+
star_path = options[:star_path] || "/assets"
|
11
|
+
star_on = options[:star_on] || "star-on.png"
|
12
|
+
star_off = options[:star_off] || "star-off.png"
|
13
|
+
star_half = options[:star_half] || "star-half.png"
|
14
|
+
cancel = options[:cancel] || false
|
15
|
+
cancel_place = options[:cancel_place] || "left"
|
16
|
+
cancel_hint = options[:cancel_hint] || "Cancel current rating!"
|
17
|
+
cancel_on = options[:cancel_on] || "cancel-on.png"
|
18
|
+
cancel_off = options[:cancel_off] || "cancel-off.png"
|
19
|
+
noRatedMsg = options[:noRatedMsg] || "I'am readOnly and I haven't rated yet!"
|
20
|
+
# round = options[:round] || { down: .26, full: .6, up: .76 }
|
21
|
+
space = options[:space] || false
|
22
|
+
single = options[:single] || false
|
23
|
+
target = options[:target] || ''
|
24
|
+
targetText = options[:targetText] || ''
|
25
|
+
targetType = options[:targetType] || 'hint'
|
26
|
+
targetFormat = options[:targetFormat] || '{score}'
|
27
|
+
targetScore = options[:targetScore] || ''
|
28
|
+
|
29
|
+
disable_after_rate = options[:disable_after_rate] && true
|
30
|
+
disable_after_rate = true if disable_after_rate == nil
|
31
|
+
|
32
|
+
if disable_after_rate
|
33
|
+
readonly = !(current_user && rateable_obj.can_rate?(current_user, dimension))
|
34
|
+
else
|
35
|
+
readonly = false
|
36
|
+
end
|
37
|
+
|
38
|
+
if options[:imdb_avg] && readonly
|
39
|
+
content_tag :div, '', :style => "background-image:url(/assets/mid-star.png);width:61px;height:57px;margin-top:10px;" do
|
40
|
+
content_tag :p, avg, :style => "position:relative;font-size:.8rem;text-align:center;line-height:60px;"
|
41
|
+
end
|
42
|
+
else
|
43
|
+
content_tag :div, '', "data-dimension" => dimension, :class => "star", "data-rating" => avg,
|
44
|
+
"data-id" => rateable_obj.id, "data-classname" => rateable_obj.class.name,
|
45
|
+
"data-disable-after-rate" => disable_after_rate,
|
46
|
+
"data-readonly" => readonly,
|
47
|
+
"data-enable-half" => enable_half,
|
48
|
+
"data-half-show" => half_show,
|
49
|
+
"data-star-count" => star,
|
50
|
+
"data-star-path" => star_path,
|
51
|
+
"data-star-on" => star_on,
|
52
|
+
"data-star-off" => star_off,
|
53
|
+
"data-star-half" => star_half,
|
54
|
+
"data-cancel" => cancel,
|
55
|
+
"data-cancel-place" => cancel_place,
|
56
|
+
"data-cancel-hint" => cancel_hint,
|
57
|
+
"data-cancel-on" => cancel_on,
|
58
|
+
"data-cancel-off" => cancel_off,
|
59
|
+
"data-no-rated-message" => noRatedMsg,
|
60
|
+
# "data-round" => round,
|
61
|
+
"data-space" => space,
|
62
|
+
"data-single" => single,
|
63
|
+
"data-target" => target,
|
64
|
+
"data-target-text" => targetText,
|
65
|
+
"data-target-type" => targetType,
|
66
|
+
"data-target-format" => targetFormat,
|
67
|
+
"data-target-score" => targetScore
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def imdb_style_rating_for(rateable_obj, user, options = {})
|
72
|
+
overall_avg = rateable_obj.overall_avg(user)
|
73
|
+
|
74
|
+
content_tag :div, '', :style => "background-image:url(/assets/big-star.png);width:81px;height:81px;margin-top:10px;" do
|
75
|
+
content_tag :p, overall_avg, :style => "position:relative;line-height:85px;text-align:center;"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def rating_for_user(rateable_obj, rating_user, dimension = nil, options = {})
|
80
|
+
@object = rateable_obj
|
81
|
+
@user = rating_user
|
82
|
+
@rating = Rate.find_by_rater_id_and_rateable_id_and_dimension(@user.id, @object.id, dimension)
|
83
|
+
stars = @rating ? @rating.stars : 0
|
84
|
+
|
85
|
+
star = options[:star] || 5
|
86
|
+
enable_half = options[:enable_half] || true
|
87
|
+
half_show = options[:half_show] || true
|
88
|
+
star_path = options[:star_path] || "/assets"
|
89
|
+
star_on = options[:star_on] || "star-on.png"
|
90
|
+
star_off = options[:star_off] || "star-off.png"
|
91
|
+
star_half = options[:star_half] || "star-half.png"
|
92
|
+
cancel = options[:cancel] || false
|
93
|
+
cancel_place = options[:cancel_place] || "left"
|
94
|
+
cancel_hint = options[:cancel_hint] || "Cancel current rating!"
|
95
|
+
cancel_on = options[:cancel_on] || "cancel-on.png"
|
96
|
+
cancel_off = options[:cancel_off] || "cancel-off.png"
|
97
|
+
noRatedMsg = options[:noRatedMsg] || "I'am readOnly and I haven't rated yet!"
|
98
|
+
# round = options[:round] || { down: .26, full: .6, up: .76 }
|
99
|
+
space = options[:space] || false
|
100
|
+
single = options[:single] || false
|
101
|
+
target = options[:target] || ''
|
102
|
+
targetText = options[:targetText] || ''
|
103
|
+
targetType = options[:targetType] || 'hint'
|
104
|
+
targetFormat = options[:targetFormat] || '{score}'
|
105
|
+
targetScore = options[:targetScore] || ''
|
106
|
+
|
107
|
+
disable_after_rate = options[:disable_after_rate] || false
|
108
|
+
|
109
|
+
readonly=false
|
110
|
+
if disable_after_rate
|
111
|
+
readonly = current_user.present? ? !rateable_obj.can_rate?(current_user.id, dimension) : true
|
112
|
+
end
|
113
|
+
|
114
|
+
content_tag :div, '', "data-dimension" => dimension, :class => "star", "data-rating" => stars,
|
115
|
+
"data-id" => rateable_obj.id, "data-classname" => rateable_obj.class.name,
|
116
|
+
"data-disable-after-rate" => disable_after_rate,
|
117
|
+
"data-readonly" => readonly,
|
118
|
+
"data-enable-half" => enable_half,
|
119
|
+
"data-half-show" => half_show,
|
120
|
+
"data-star-count" => stars,
|
121
|
+
"data-star-path" => star_path,
|
122
|
+
"data-star-on" => star_on,
|
123
|
+
"data-star-off" => star_off,
|
124
|
+
"data-star-half" => star_half,
|
125
|
+
"data-cancel" => cancel,
|
126
|
+
"data-cancel-place" => cancel_place,
|
127
|
+
"data-cancel-hint" => cancel_hint,
|
128
|
+
"data-cancel-on" => cancel_on,
|
129
|
+
"data-cancel-off" => cancel_off,
|
130
|
+
"data-no-rated-message" => noRatedMsg,
|
131
|
+
# "data-round" => round,
|
132
|
+
"data-space" => space,
|
133
|
+
"data-single" => single,
|
134
|
+
"data-target" => target,
|
135
|
+
"data-target-text" => targetText,
|
136
|
+
"data-target-format" => targetFormat,
|
137
|
+
"data-target-score" => targetScore
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
class ActionView::Base
|
143
|
+
include Helpers
|
144
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
module Ratyrate
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
def rate(stars, user, dimension=nil, dirichlet_method=false)
|
6
|
+
dimension = nil if dimension.blank?
|
7
|
+
|
8
|
+
if can_rate? user, dimension
|
9
|
+
rates(dimension).create! do |r|
|
10
|
+
r.stars = stars
|
11
|
+
r.rater = user
|
12
|
+
end
|
13
|
+
if dirichlet_method
|
14
|
+
update_rate_average_dirichlet(stars, dimension)
|
15
|
+
else
|
16
|
+
update_rate_average(stars, dimension)
|
17
|
+
end
|
18
|
+
else
|
19
|
+
update_current_rate(stars, user, dimension)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def update_rate_average_dirichlet(stars, dimension=nil)
|
24
|
+
## assumes 5 possible vote categories
|
25
|
+
dp = {1 => 1, 2 => 1, 3 => 1, 4 => 1, 5 => 1}
|
26
|
+
stars_group = Hash[rates(dimension).group(:stars).count.map{|k,v| [k.to_i,v] }]
|
27
|
+
posterior = dp.merge(stars_group){|key, a, b| a + b}
|
28
|
+
sum = posterior.map{ |i, v| v }.inject { |a, b| a + b }
|
29
|
+
davg = posterior.map{ |i, v| i * v }.inject { |a, b| a + b }.to_f / sum
|
30
|
+
|
31
|
+
if average(dimension).nil?
|
32
|
+
RatingCache.create! do |avg|
|
33
|
+
avg.cacheable_id = self.id
|
34
|
+
avg.cacheable_type = self.class.name
|
35
|
+
avg.qty = 1
|
36
|
+
avg.avg = davg
|
37
|
+
avg.dimension = dimension
|
38
|
+
end
|
39
|
+
else
|
40
|
+
a = average(dimension)
|
41
|
+
a.qty = rates(dimension).count
|
42
|
+
a.avg = davg
|
43
|
+
a.save!(validate: false)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def update_rate_average(stars, dimension=nil)
|
48
|
+
if average(dimension).nil?
|
49
|
+
RatingCache.create! do |avg|
|
50
|
+
avg.cacheable_id = self.id
|
51
|
+
avg.cacheable_type = self.class.name
|
52
|
+
avg.avg = stars
|
53
|
+
avg.qty = 1
|
54
|
+
avg.dimension = dimension
|
55
|
+
end
|
56
|
+
else
|
57
|
+
a = average(dimension)
|
58
|
+
a.qty = rates(dimension).count
|
59
|
+
a.avg = rates(dimension).average(:stars)
|
60
|
+
a.save!(validate: false)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def update_current_rate(stars, user, dimension)
|
65
|
+
current_rate = user.ratings_given.where(rater_id: user.id, rateable_id: self.id, dimension: dimension).take
|
66
|
+
current_rate.stars = stars
|
67
|
+
current_rate.save!(validate: false)
|
68
|
+
|
69
|
+
if rates(dimension).count > 1
|
70
|
+
update_rate_average(stars, dimension)
|
71
|
+
else # Set the avarage to the exact number of stars
|
72
|
+
a = average(dimension)
|
73
|
+
a.avg = stars
|
74
|
+
a.save!(validate: false)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def overall_avg(user)
|
79
|
+
# avg = OverallAverage.where(rateable_id: self.id)
|
80
|
+
# #FIXME: Fix the bug when the movie has no ratings
|
81
|
+
# unless avg.empty?
|
82
|
+
# return avg.take.avg unless avg.take.avg == 0
|
83
|
+
# else # calculate average, and save it
|
84
|
+
# dimensions_count = overall_score = 0
|
85
|
+
# user.ratings_given.select('DISTINCT dimension').each do |d|
|
86
|
+
# dimensions_count = dimensions_count + 1
|
87
|
+
# unless average(d.dimension).nil?
|
88
|
+
# overall_score = overall_score + average(d.dimension).avg
|
89
|
+
# end
|
90
|
+
# end
|
91
|
+
# overall_avg = (overall_score / dimensions_count).to_f.round(1)
|
92
|
+
# AverageCache.create! do |a|
|
93
|
+
# a.rater_id = user.id
|
94
|
+
# a.rateable_id = self.id
|
95
|
+
# a.avg = overall_avg
|
96
|
+
# end
|
97
|
+
# overall_avg
|
98
|
+
# end
|
99
|
+
end
|
100
|
+
|
101
|
+
# calculate the movie overall average rating for all users
|
102
|
+
def calculate_overall_average
|
103
|
+
end
|
104
|
+
|
105
|
+
def average(dimension=nil)
|
106
|
+
dimension ? self.send("#{dimension}_average") : rate_average_without_dimension
|
107
|
+
end
|
108
|
+
|
109
|
+
def can_rate?(user, dimension=nil)
|
110
|
+
user.ratings_given.where(dimension: dimension, rateable_id: id, rateable_type: self.class.name).size.zero?
|
111
|
+
end
|
112
|
+
|
113
|
+
def rates(dimension=nil)
|
114
|
+
dimension ? self.send("#{dimension}_rates") : rates_without_dimension
|
115
|
+
end
|
116
|
+
|
117
|
+
def raters(dimension=nil)
|
118
|
+
dimension ? self.send("#{dimension}_raters") : raters_without_dimension
|
119
|
+
end
|
120
|
+
|
121
|
+
module ClassMethods
|
122
|
+
|
123
|
+
def ratyrate_rater
|
124
|
+
has_many :ratings_given, :class_name => "Rate", :foreign_key => :rater_id
|
125
|
+
end
|
126
|
+
|
127
|
+
def ratyrate_rateable(*dimensions)
|
128
|
+
has_many :rates_without_dimension, -> { where dimension: nil}, :as => :rateable, :class_name => "Rate", :dependent => :destroy
|
129
|
+
has_many :raters_without_dimension, :through => :rates_without_dimension, :source => :rater
|
130
|
+
|
131
|
+
has_one :rate_average_without_dimension, -> { where dimension: nil}, :as => :cacheable,
|
132
|
+
:class_name => "RatingCache", :dependent => :destroy
|
133
|
+
|
134
|
+
dimensions.each do |dimension|
|
135
|
+
has_many "#{dimension}_rates".to_sym, -> {where dimension: dimension.to_s},
|
136
|
+
:dependent => :destroy,
|
137
|
+
:class_name => "Rate",
|
138
|
+
:as => :rateable
|
139
|
+
|
140
|
+
has_many "#{dimension}_raters".to_sym, :through => "#{dimension}_rates", :source => :rater
|
141
|
+
|
142
|
+
has_one "#{dimension}_average".to_sym, -> { where dimension: dimension.to_s },
|
143
|
+
:as => :cacheable, :class_name => "RatingCache",
|
144
|
+
:dependent => :destroy
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
class ActiveRecord::Base
|
152
|
+
include Ratyrate
|
153
|
+
end
|
data/lib/ratyrate.rb
ADDED
data/ratyrate.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "ratyrate/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "ratyrate"
|
7
|
+
s.version = Ratyrate::VERSION
|
8
|
+
s.authors = ["Islam Wazery"]
|
9
|
+
s.email = ["wazery@ubuntu.com"]
|
10
|
+
s.homepage = "http://github.com/wazery/ratyrate"
|
11
|
+
s.summary = %q{A Ruby Gem that provides the same functionality of jQuery Raty library, and adds IMDB style rating.}
|
12
|
+
s.description = %q{A Ruby Gem that provides the same functionality of jQuery Raty library, and adds IMDB style rating.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "ratyrate"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
# s.add_development_dependency "rspec"
|
23
|
+
# s.add_runtime_dependency "rest-client"
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ratyrate
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.2.0.alpha
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Islam Wazery
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-08-09 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: A Ruby Gem that provides the same functionality of jQuery Raty library,
|
14
|
+
and adds IMDB style rating.
|
15
|
+
email:
|
16
|
+
- wazery@ubuntu.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- ".gitignore"
|
22
|
+
- ".travis.yml"
|
23
|
+
- Gemfile
|
24
|
+
- Gemfile.lock
|
25
|
+
- README.md
|
26
|
+
- Rakefile
|
27
|
+
- lib/generators/ratyrate/USAGE
|
28
|
+
- lib/generators/ratyrate/ratyrate_generator.rb
|
29
|
+
- lib/generators/ratyrate/templates/average_cache_migration.rb
|
30
|
+
- lib/generators/ratyrate/templates/average_cache_model.rb
|
31
|
+
- lib/generators/ratyrate/templates/big-star.png
|
32
|
+
- lib/generators/ratyrate/templates/cache_migration.rb
|
33
|
+
- lib/generators/ratyrate/templates/cache_model.rb
|
34
|
+
- lib/generators/ratyrate/templates/cancel-off.png
|
35
|
+
- lib/generators/ratyrate/templates/cancel-on.png
|
36
|
+
- lib/generators/ratyrate/templates/jquery.raty.js
|
37
|
+
- lib/generators/ratyrate/templates/mid-star.png
|
38
|
+
- lib/generators/ratyrate/templates/migration.rb
|
39
|
+
- lib/generators/ratyrate/templates/model.rb
|
40
|
+
- lib/generators/ratyrate/templates/overall_average_migration.rb
|
41
|
+
- lib/generators/ratyrate/templates/overall_average_model.rb
|
42
|
+
- lib/generators/ratyrate/templates/rater_controller.rb
|
43
|
+
- lib/generators/ratyrate/templates/ratyrate.js.erb
|
44
|
+
- lib/generators/ratyrate/templates/star-half.png
|
45
|
+
- lib/generators/ratyrate/templates/star-off.png
|
46
|
+
- lib/generators/ratyrate/templates/star-on.png
|
47
|
+
- lib/ratyrate.rb
|
48
|
+
- lib/ratyrate/helpers.rb
|
49
|
+
- lib/ratyrate/model.rb
|
50
|
+
- lib/ratyrate/version.rb
|
51
|
+
- ratyrate.gemspec
|
52
|
+
homepage: http://github.com/wazery/ratyrate
|
53
|
+
licenses: []
|
54
|
+
metadata: {}
|
55
|
+
post_install_message:
|
56
|
+
rdoc_options: []
|
57
|
+
require_paths:
|
58
|
+
- lib
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 1.3.1
|
69
|
+
requirements: []
|
70
|
+
rubyforge_project: ratyrate
|
71
|
+
rubygems_version: 2.2.2
|
72
|
+
signing_key:
|
73
|
+
specification_version: 4
|
74
|
+
summary: A Ruby Gem that provides the same functionality of jQuery Raty library, and
|
75
|
+
adds IMDB style rating.
|
76
|
+
test_files: []
|