acts_as_votable 0.5.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.travis.yml +25 -0
- data/Gemfile +14 -1
- data/README.markdown +243 -143
- data/Rakefile +8 -0
- data/acts_as_votable.gemspec +1 -6
- data/lib/acts_as_votable/extenders/controller.rb +19 -0
- data/lib/acts_as_votable/version.rb +1 -1
- data/lib/acts_as_votable/votable.rb +118 -44
- data/lib/acts_as_votable/vote.rb +8 -6
- data/lib/acts_as_votable/voter.rb +19 -20
- data/lib/acts_as_votable.rb +5 -0
- data/lib/generators/acts_as_votable/migration/migration_generator.rb +2 -2
- data/lib/generators/acts_as_votable/migration/templates/active_record/migration.rb +6 -2
- data/spec/shared_example/votable_model_spec.rb +393 -0
- data/spec/shared_example/voter_model_spec.rb +279 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/votable_spec.rb +6 -277
- data/spec/votable_voter_spec.rb +20 -0
- data/spec/voter_spec.rb +6 -289
- metadata +21 -42
- data/Gemfile.lock +0 -104
@@ -6,13 +6,13 @@ module ActsAsVotable
|
|
6
6
|
include Helpers::Words
|
7
7
|
|
8
8
|
def self.included base
|
9
|
-
|
10
|
-
# allow the user to define these himself
|
9
|
+
|
10
|
+
# allow the user to define these himself
|
11
11
|
aliases = {
|
12
12
|
|
13
13
|
:vote_up => [
|
14
|
-
:up_by, :upvote_by, :like_by, :liked_by,
|
15
|
-
:up_from, :upvote_from, :upvote_by, :like_from, :liked_from, :vote_from
|
14
|
+
:up_by, :upvote_by, :like_by, :liked_by,
|
15
|
+
:up_from, :upvote_from, :upvote_by, :like_from, :liked_from, :vote_from
|
16
16
|
],
|
17
17
|
|
18
18
|
:vote_down => [
|
@@ -20,22 +20,20 @@ module ActsAsVotable
|
|
20
20
|
:down_from, :downvote_from, :downvote_by, :dislike_by, :disliked_by
|
21
21
|
],
|
22
22
|
|
23
|
-
:
|
24
|
-
:
|
23
|
+
:get_up_votes => [
|
24
|
+
:get_true_votes, :get_ups, :get_upvotes, :get_likes, :get_positives, :get_for_votes,
|
25
25
|
],
|
26
26
|
|
27
|
-
:
|
28
|
-
:
|
27
|
+
:get_down_votes => [
|
28
|
+
:get_false_votes, :get_downs, :get_downvotes, :get_dislikes, :get_negatives
|
29
29
|
],
|
30
|
-
:
|
31
|
-
:unliked_by, :undisliked_by
|
30
|
+
:unvote_by => [
|
31
|
+
:unvote_up, :unvote_down, :unliked_by, :undisliked_by
|
32
32
|
]
|
33
33
|
}
|
34
34
|
|
35
35
|
base.class_eval do
|
36
|
-
|
37
|
-
belongs_to :votable, :polymorphic => true
|
38
|
-
has_many :votes, :class_name => "ActsAsVotable::Vote", :as => :votable do
|
36
|
+
has_many :votes_for, :class_name => 'ActsAsVotable::Vote', :as => :votable, :dependent => :destroy do
|
39
37
|
def voters
|
40
38
|
includes(:voter).map(&:voter)
|
41
39
|
end
|
@@ -64,7 +62,7 @@ module ActsAsVotable
|
|
64
62
|
end
|
65
63
|
|
66
64
|
# voting
|
67
|
-
def
|
65
|
+
def vote_by args = {}
|
68
66
|
|
69
67
|
options = {
|
70
68
|
:vote => true,
|
@@ -78,13 +76,13 @@ module ActsAsVotable
|
|
78
76
|
end
|
79
77
|
|
80
78
|
# find the vote
|
81
|
-
_votes_ =
|
79
|
+
_votes_ = find_votes_for({
|
82
80
|
:voter_id => options[:voter].id,
|
83
81
|
:vote_scope => options[:vote_scope],
|
84
82
|
:voter_type => options[:voter].class.name
|
85
83
|
})
|
86
84
|
|
87
|
-
if _votes_.count == 0
|
85
|
+
if _votes_.count == 0 or options[:duplicate]
|
88
86
|
# this voter has never voted
|
89
87
|
vote = ActsAsVotable::Vote.new(
|
90
88
|
:votable => self,
|
@@ -93,16 +91,19 @@ module ActsAsVotable
|
|
93
91
|
)
|
94
92
|
else
|
95
93
|
# this voter is potentially changing his vote
|
96
|
-
vote = _votes_.
|
94
|
+
vote = _votes_.last
|
97
95
|
end
|
98
96
|
|
99
97
|
last_update = vote.updated_at
|
100
98
|
|
101
99
|
vote.vote_flag = votable_words.meaning_of(options[:vote])
|
102
100
|
|
101
|
+
#Allowing for a vote_weight to be associated with every vote. Could change with every voter object
|
102
|
+
vote.vote_weight = (options[:vote_weight].to_i if options[:vote_weight].present?) || 1
|
103
|
+
|
103
104
|
if vote.save
|
104
105
|
self.vote_registered = true if last_update != vote.updated_at
|
105
|
-
update_cached_votes
|
106
|
+
update_cached_votes options[:vote_scope]
|
106
107
|
return true
|
107
108
|
else
|
108
109
|
self.vote_registered = false
|
@@ -113,25 +114,56 @@ module ActsAsVotable
|
|
113
114
|
|
114
115
|
def unvote args = {}
|
115
116
|
return false if args[:voter].nil?
|
116
|
-
_votes_ =
|
117
|
+
_votes_ = find_votes_for(:voter_id => args[:voter].id, :vote_scope => args[:vote_scope], :voter_type => args[:voter].class.name)
|
117
118
|
|
118
119
|
return true if _votes_.size == 0
|
119
120
|
_votes_.each(&:destroy)
|
120
|
-
update_cached_votes
|
121
|
-
self.vote_registered = false if
|
121
|
+
update_cached_votes args[:vote_scope]
|
122
|
+
self.vote_registered = false if votes_for.count == 0
|
122
123
|
return true
|
123
124
|
end
|
124
125
|
|
125
126
|
def vote_up voter, options={}
|
126
|
-
self.
|
127
|
+
self.vote_by :voter => voter, :vote => true, :vote_scope => options[:vote_scope], :vote_weight => options[:vote_weight]
|
127
128
|
end
|
128
129
|
|
129
130
|
def vote_down voter, options={}
|
130
|
-
self.
|
131
|
+
self.vote_by :voter => voter, :vote => false, :vote_scope => options[:vote_scope], :vote_weight => options[:vote_weight]
|
132
|
+
end
|
133
|
+
|
134
|
+
def unvote_by voter, options = {}
|
135
|
+
self.unvote :voter => voter, :vote_scope => options[:vote_scope] #Does not need vote_weight since the votes_for are anyway getting destroyed
|
136
|
+
end
|
137
|
+
|
138
|
+
def scope_cache_field field, vote_scope
|
139
|
+
return field if vote_scope.nil?
|
140
|
+
|
141
|
+
case field
|
142
|
+
when :cached_votes_total=
|
143
|
+
"cached_scoped_#{vote_scope}_votes_total="
|
144
|
+
when :cached_votes_total
|
145
|
+
"cached_scoped_#{vote_scope}_votes_total"
|
146
|
+
when :cached_votes_up=
|
147
|
+
"cached_scoped_#{vote_scope}_votes_up="
|
148
|
+
when :cached_votes_up
|
149
|
+
"cached_scoped_#{vote_scope}_votes_up"
|
150
|
+
when :cached_votes_down=
|
151
|
+
"cached_scoped_#{vote_scope}_votes_down="
|
152
|
+
when :cached_votes_down
|
153
|
+
"cached_scoped_#{vote_scope}_votes_down"
|
154
|
+
when :cached_votes_score=
|
155
|
+
"cached_scoped_#{vote_scope}_votes_score="
|
156
|
+
when :cached_votes_score
|
157
|
+
"cached_scoped_#{vote_scope}_votes_score"
|
158
|
+
when :cached_weighted_score
|
159
|
+
"cached_weighted_#{vote_scope}_score"
|
160
|
+
when :cached_weighted_score=
|
161
|
+
"cached_weighted_#{vote_scope}_score="
|
162
|
+
end
|
131
163
|
end
|
132
164
|
|
133
165
|
# caching
|
134
|
-
def update_cached_votes
|
166
|
+
def update_cached_votes vote_scope = nil
|
135
167
|
|
136
168
|
updates = {}
|
137
169
|
|
@@ -154,50 +186,92 @@ module ActsAsVotable
|
|
154
186
|
)
|
155
187
|
end
|
156
188
|
|
157
|
-
self.
|
189
|
+
if self.respond_to?(:cached_weighted_score=)
|
190
|
+
updates[:cached_weighted_score] = weighted_score(true)
|
191
|
+
end
|
192
|
+
|
193
|
+
if vote_scope
|
194
|
+
if self.respond_to?(scope_cache_field :cached_votes_total=, vote_scope)
|
195
|
+
updates[scope_cache_field :cached_votes_total, vote_scope] = count_votes_total(true, vote_scope)
|
196
|
+
end
|
197
|
+
|
198
|
+
if self.respond_to?(scope_cache_field :cached_votes_up=, vote_scope)
|
199
|
+
updates[scope_cache_field :cached_votes_up, vote_scope] = count_votes_up(true, vote_scope)
|
200
|
+
end
|
201
|
+
|
202
|
+
if self.respond_to?(scope_cache_field :cached_votes_down=, vote_scope)
|
203
|
+
updates[scope_cache_field :cached_votes_down, vote_scope] = count_votes_down(true, vote_scope)
|
204
|
+
end
|
205
|
+
|
206
|
+
if self.respond_to?(scope_cache_field :cached_weighted_score=, vote_scope)
|
207
|
+
updates[scope_cache_field :cached_weighted_score, vote_scope] = weighted_score(true, vote_scope)
|
208
|
+
end
|
209
|
+
|
210
|
+
if self.respond_to?(scope_cache_field :cached_votes_score=, vote_scope)
|
211
|
+
updates[scope_cache_field :cached_votes_score, vote_scope] = (
|
212
|
+
(updates[scope_cache_field :cached_votes_up, vote_scope] || count_votes_up(true, vote_scope)) -
|
213
|
+
(updates[scope_cache_field :cached_votes_down, vote_scope] || count_votes_down(true, vote_scope))
|
214
|
+
)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
if (::ActiveRecord::VERSION::MAJOR == 3) && (::ActiveRecord::VERSION::MINOR != 0)
|
219
|
+
self.update_attributes(updates, :without_protection => true) if updates.size > 0
|
220
|
+
else
|
221
|
+
self.update_attributes(updates) if updates.size > 0
|
222
|
+
end
|
158
223
|
|
159
224
|
end
|
160
225
|
|
161
226
|
|
162
227
|
# results
|
163
|
-
def
|
164
|
-
|
228
|
+
def find_votes_for extra_conditions = {}
|
229
|
+
votes_for.where(extra_conditions)
|
165
230
|
end
|
166
231
|
|
167
|
-
def
|
168
|
-
|
232
|
+
def get_up_votes options={}
|
233
|
+
find_votes_for(:vote_flag => true, :vote_scope => options[:vote_scope])
|
169
234
|
end
|
170
235
|
|
171
|
-
def
|
172
|
-
|
236
|
+
def get_down_votes options={}
|
237
|
+
find_votes_for(:vote_flag => false, :vote_scope => options[:vote_scope])
|
173
238
|
end
|
174
239
|
|
175
240
|
|
176
241
|
# counting
|
177
|
-
def count_votes_total skip_cache = false
|
178
|
-
if !skip_cache && self.respond_to?(:cached_votes_total)
|
179
|
-
return self.send(:cached_votes_total)
|
242
|
+
def count_votes_total skip_cache = false, vote_scope = nil
|
243
|
+
if !skip_cache && self.respond_to?(scope_cache_field :cached_votes_total, vote_scope)
|
244
|
+
return self.send(scope_cache_field :cached_votes_total, vote_scope)
|
245
|
+
end
|
246
|
+
find_votes_for(:vote_scope => vote_scope).count
|
247
|
+
end
|
248
|
+
|
249
|
+
def count_votes_up skip_cache = false, vote_scope = nil
|
250
|
+
if !skip_cache && self.respond_to?(scope_cache_field :cached_votes_up, vote_scope)
|
251
|
+
return self.send(scope_cache_field :cached_votes_up, vote_scope)
|
180
252
|
end
|
181
|
-
|
253
|
+
get_up_votes(:vote_scope => vote_scope).count
|
182
254
|
end
|
183
255
|
|
184
|
-
def
|
185
|
-
if !skip_cache && self.respond_to?(:
|
186
|
-
return self.send(:
|
256
|
+
def count_votes_down skip_cache = false, vote_scope = nil
|
257
|
+
if !skip_cache && self.respond_to?(scope_cache_field :cached_votes_down, vote_scope)
|
258
|
+
return self.send(scope_cache_field :cached_votes_down, vote_scope)
|
187
259
|
end
|
188
|
-
|
260
|
+
get_down_votes(:vote_scope => vote_scope).count
|
189
261
|
end
|
190
262
|
|
191
|
-
def
|
192
|
-
if !skip_cache && self.respond_to?(:
|
193
|
-
return self.send(:
|
263
|
+
def weighted_score skip_cache = false, vote_scope = nil
|
264
|
+
if !skip_cache && self.respond_to?(scope_cache_field :cached_weighted_score, vote_scope)
|
265
|
+
return self.send(scope_cache_field :cached_weighted_score, vote_scope)
|
194
266
|
end
|
195
|
-
|
267
|
+
ups = get_up_votes(:vote_scope => vote_scope).sum(:vote_weight)
|
268
|
+
downs = get_down_votes(:vote_scope => vote_scope).sum(:vote_weight)
|
269
|
+
ups - downs
|
196
270
|
end
|
197
271
|
|
198
272
|
# voters
|
199
273
|
def voted_on_by? voter
|
200
|
-
votes =
|
274
|
+
votes = find_votes_for :voter_id => voter.id, :voter_type => voter.class.name
|
201
275
|
votes.count > 0
|
202
276
|
end
|
203
277
|
|
data/lib/acts_as_votable/vote.rb
CHANGED
@@ -5,16 +5,18 @@ module ActsAsVotable
|
|
5
5
|
|
6
6
|
include Helpers::Words
|
7
7
|
|
8
|
-
|
9
|
-
:
|
10
|
-
|
11
|
-
|
8
|
+
if ::ActiveRecord::VERSION::MAJOR < 4
|
9
|
+
attr_accessible :votable_id, :votable_type,
|
10
|
+
:voter_id, :voter_type,
|
11
|
+
:votable, :voter,
|
12
|
+
:vote_flag, :vote_scope
|
13
|
+
end
|
12
14
|
|
13
15
|
belongs_to :votable, :polymorphic => true
|
14
16
|
belongs_to :voter, :polymorphic => true
|
15
17
|
|
16
|
-
scope :up, where(:vote_flag => true)
|
17
|
-
scope :down, where(:vote_flag => false)
|
18
|
+
scope :up, lambda{ where(:vote_flag => true) }
|
19
|
+
scope :down, lambda{ where(:vote_flag => false) }
|
18
20
|
scope :for_type, lambda{ |klass| where(:votable_type => klass) }
|
19
21
|
scope :by_type, lambda{ |klass| where(:voter_type => klass) }
|
20
22
|
|
@@ -5,17 +5,20 @@ module ActsAsVotable
|
|
5
5
|
|
6
6
|
# allow user to define these
|
7
7
|
aliases = {
|
8
|
-
:vote_up_for
|
9
|
-
:vote_down_for
|
10
|
-
:unvote_for
|
8
|
+
:vote_up_for => [:likes, :upvotes, :up_votes],
|
9
|
+
:vote_down_for => [:dislikes, :downvotes, :down_votes],
|
10
|
+
:unvote_for => [:unlike, :undislike],
|
11
|
+
:voted_on? => [:voted_for?],
|
11
12
|
:voted_up_on? => [:voted_up_for?, :liked?],
|
12
|
-
:voted_down_on? => [:voted_down_for?, :disliked?]
|
13
|
+
:voted_down_on? => [:voted_down_for?, :disliked?],
|
14
|
+
:voted_as_when_voting_on => [:voted_as_when_voted_on, :voted_as_when_voting_for, :voted_as_when_voted_for],
|
15
|
+
:find_up_voted_items => [:find_liked_items],
|
16
|
+
:find_down_voted_items => [:find_disliked_items]
|
13
17
|
}
|
14
18
|
|
15
19
|
base.class_eval do
|
16
20
|
|
17
|
-
|
18
|
-
has_many :votes, :class_name => "ActsAsVotable::Vote", :as => :voter do
|
21
|
+
has_many :votes, :class_name => 'ActsAsVotable::Vote', :as => :voter, :dependent => :destroy do
|
19
22
|
def votables
|
20
23
|
includes(:votable).map(&:votable)
|
21
24
|
end
|
@@ -33,7 +36,7 @@ module ActsAsVotable
|
|
33
36
|
|
34
37
|
# voting
|
35
38
|
def vote args
|
36
|
-
args[:votable].
|
39
|
+
args[:votable].vote_by args.merge({:voter => self})
|
37
40
|
end
|
38
41
|
|
39
42
|
def vote_up_for model=nil, args={}
|
@@ -44,8 +47,8 @@ module ActsAsVotable
|
|
44
47
|
vote :votable => model, :vote_scope => args[:vote_scope], :vote => false
|
45
48
|
end
|
46
49
|
|
47
|
-
def unvote_for model
|
48
|
-
model.unvote :voter => self
|
50
|
+
def unvote_for model, args={}
|
51
|
+
model.unvote :voter => self, :vote_scope => args[:vote_scope]
|
49
52
|
end
|
50
53
|
|
51
54
|
# results
|
@@ -66,15 +69,13 @@ module ActsAsVotable
|
|
66
69
|
:vote_scope => args[:vote_scope], :vote_flag => false)
|
67
70
|
votes.size > 0
|
68
71
|
end
|
69
|
-
alias :voted_down_for? :voted_down_on?
|
70
72
|
|
71
73
|
def voted_as_when_voting_on votable, args={}
|
72
|
-
|
73
|
-
:vote_scope => args[:vote_scope])
|
74
|
-
return nil
|
75
|
-
return
|
74
|
+
vote = find_votes(:votable_id => votable.id, :votable_type => votable.class.name,
|
75
|
+
:vote_scope => args[:vote_scope]).select(:vote_flag).last
|
76
|
+
return nil unless vote
|
77
|
+
return vote.vote_flag
|
76
78
|
end
|
77
|
-
alias :voted_as_when_voted_for :voted_as_when_voting_on
|
78
79
|
|
79
80
|
def find_votes extra_conditions = {}
|
80
81
|
votes.where(extra_conditions)
|
@@ -113,23 +114,21 @@ module ActsAsVotable
|
|
113
114
|
def find_up_voted_items extra_conditions = {}
|
114
115
|
find_voted_items extra_conditions.merge(:vote_flag => true)
|
115
116
|
end
|
116
|
-
alias_method :find_liked_items, :find_up_voted_items
|
117
117
|
|
118
118
|
def find_down_voted_items extra_conditions = {}
|
119
119
|
find_voted_items extra_conditions.merge(:vote_flag => false)
|
120
120
|
end
|
121
|
-
alias_method :find_disliked_items, :find_down_voted_items
|
122
121
|
|
123
122
|
def get_voted klass, extra_conditions = {}
|
124
|
-
klass.joins(:
|
123
|
+
klass.joins(:votes_for).merge find_votes(extra_conditions)
|
125
124
|
end
|
126
125
|
|
127
126
|
def get_up_voted klass
|
128
|
-
klass.joins(:
|
127
|
+
klass.joins(:votes_for).merge find_up_votes
|
129
128
|
end
|
130
129
|
|
131
130
|
def get_down_voted klass
|
132
|
-
klass.joins(:
|
131
|
+
klass.joins(:votes_for).merge find_down_votes
|
133
132
|
end
|
134
133
|
end
|
135
134
|
end
|
data/lib/acts_as_votable.rb
CHANGED
@@ -24,8 +24,8 @@ module ActsAsVotable
|
|
24
24
|
|
25
25
|
def create_migration_file
|
26
26
|
if self.class.orm_has_migration?
|
27
|
-
migration_template 'migration.rb', 'db/migrate/acts_as_votable_migration'
|
27
|
+
migration_template 'migration.rb', 'db/migrate/acts_as_votable_migration.rb'
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
31
|
-
end
|
31
|
+
end
|
@@ -7,12 +7,16 @@ class ActsAsVotableMigration < ActiveRecord::Migration
|
|
7
7
|
|
8
8
|
t.boolean :vote_flag
|
9
9
|
t.string :vote_scope
|
10
|
+
t.integer :vote_weight
|
10
11
|
|
11
12
|
t.timestamps
|
12
13
|
end
|
13
14
|
|
14
|
-
|
15
|
-
|
15
|
+
if ActiveRecord::VERSION::MAJOR < 4
|
16
|
+
add_index :votes, [:votable_id, :votable_type]
|
17
|
+
add_index :votes, [:voter_id, :voter_type]
|
18
|
+
end
|
19
|
+
|
16
20
|
add_index :votes, [:voter_id, :voter_type, :vote_scope]
|
17
21
|
add_index :votes, [:votable_id, :votable_type, :vote_scope]
|
18
22
|
end
|