acts_as_votable 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +9 -1
- data/README.markdown +64 -41
- data/lib/acts_as_votable/version.rb +1 -1
- data/lib/acts_as_votable/votable.rb +31 -30
- data/lib/acts_as_votable/voter.rb +6 -6
- data/lib/generators/acts_as_votable/migration/migration_generator.rb +2 -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 +11 -0
- data/spec/votable_spec.rb +6 -420
- data/spec/votable_voter_spec.rb +20 -0
- data/spec/voter_spec.rb +6 -295
- metadata +13 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7b8402806ab189425b71b1d24d2081123e6bffc1
|
4
|
+
data.tar.gz: 48de253feb1e0df3ef42cd798faaaf8f91f36b47
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7189eeb6505d6394bb090d58618d23ee13e36e6512f0416a15bf984c489e0775952680b748cadc054bd4948260184ac4a457ef6dee3b34f279561245adb2213e
|
7
|
+
data.tar.gz: 0fd78166628e72e3c77b8b5c8b8ba0028aa3069afb217816324c470ce6cc0c5a809431fcf47a800e440bbcb49020778e54f6f082698321357ded582081f488b0
|
data/.travis.yml
CHANGED
@@ -4,14 +4,22 @@ rvm:
|
|
4
4
|
- 1.9.2
|
5
5
|
- 1.9.3
|
6
6
|
- 2.0.0
|
7
|
+
- 2.1.0
|
7
8
|
env:
|
8
9
|
- "RAILS_VERSION=3.0.0"
|
9
10
|
- "RAILS_VERSION=3.1.0"
|
10
11
|
- "RAILS_VERSION=3.2.0"
|
11
12
|
- "RAILS_VERSION=4.0.0"
|
13
|
+
- "RAILS_VERSION=4.1.0"
|
12
14
|
matrix:
|
13
15
|
exclude:
|
14
16
|
- rvm: 1.8.7
|
15
17
|
env: "RAILS_VERSION=4.0.0"
|
16
18
|
- rvm: 1.9.2
|
17
|
-
env: "RAILS_VERSION=4.0.0"
|
19
|
+
env: "RAILS_VERSION=4.0.0"
|
20
|
+
- rvm: 1.8.7
|
21
|
+
env: "RAILS_VERSION=4.1.0"
|
22
|
+
- rvm: 1.9.2
|
23
|
+
env: "RAILS_VERSION=4.1.0"
|
24
|
+
- rvm: 1.9.3
|
25
|
+
env: "RAILS_VERSION=4.1.0"
|
data/README.markdown
CHANGED
@@ -13,12 +13,19 @@ The main goals of this gem are:
|
|
13
13
|
|
14
14
|
## Installation
|
15
15
|
|
16
|
-
###
|
16
|
+
### Supported Ruby and Rails versions
|
17
|
+
|
18
|
+
* Ruby 1.8.7, 1.9.2, 1.9.3
|
19
|
+
* Ruby 2.0.0, 2.1.0
|
20
|
+
* Rails 3.0, 3.1, 3.2
|
21
|
+
* Rails 4.0, 4.1+
|
22
|
+
|
23
|
+
### Install
|
17
24
|
|
18
25
|
Just add the following to your Gemfile.
|
19
26
|
|
20
27
|
```ruby
|
21
|
-
gem 'acts_as_votable', '~> 0.
|
28
|
+
gem 'acts_as_votable', '~> 0.9.0'
|
22
29
|
```
|
23
30
|
|
24
31
|
And follow that up with a ``bundle install``.
|
@@ -48,7 +55,7 @@ end
|
|
48
55
|
@post.save
|
49
56
|
|
50
57
|
@post.liked_by @user
|
51
|
-
@post.
|
58
|
+
@post.votes_for.size # => 1
|
52
59
|
```
|
53
60
|
|
54
61
|
### Like/Dislike Yes/No Up/Down
|
@@ -59,9 +66,9 @@ more natural calls are the first few examples.
|
|
59
66
|
```ruby
|
60
67
|
@post.liked_by @user1
|
61
68
|
@post.downvote_from @user2
|
62
|
-
@post.
|
63
|
-
@post.
|
64
|
-
@post.
|
69
|
+
@post.vote_by :voter => @user3
|
70
|
+
@post.vote_by :voter => @user4, :vote => 'bad'
|
71
|
+
@post.vote_by :voter => @user5, :vote => 'like'
|
65
72
|
```
|
66
73
|
|
67
74
|
By default all votes are positive, so `@user3` has cast a 'good' vote for `@post`.
|
@@ -80,26 +87,26 @@ Revisiting the previous example of code.
|
|
80
87
|
```ruby
|
81
88
|
# positive votes
|
82
89
|
@post.liked_by @user1
|
83
|
-
@post.
|
84
|
-
@post.
|
90
|
+
@post.vote_by :voter => @user3
|
91
|
+
@post.vote_by :voter => @user5, :vote => 'like'
|
85
92
|
|
86
93
|
# negative votes
|
87
94
|
@post.downvote_from @user2
|
88
|
-
@post.
|
95
|
+
@post.vote_by :voter => @user2, :vote => 'bad'
|
89
96
|
|
90
97
|
# tally them up!
|
91
|
-
@post.
|
92
|
-
@post.
|
93
|
-
@post.
|
94
|
-
@post.
|
95
|
-
@post.
|
98
|
+
@post.votes_for.size # => 5
|
99
|
+
@post.get_likes.size # => 3
|
100
|
+
@post.get_upvotes.size # => 3
|
101
|
+
@post.get_dislikes.size # => 2
|
102
|
+
@post.get_downvotes.size # => 2
|
96
103
|
```
|
97
104
|
|
98
105
|
Active Record scopes are provided to make life easier.
|
99
106
|
|
100
107
|
```ruby
|
101
|
-
@post.
|
102
|
-
@post.
|
108
|
+
@post.votes_for.up.by_type(User)
|
109
|
+
@post.votes_for.down
|
103
110
|
@user1.votes.up
|
104
111
|
@user1.votes.down
|
105
112
|
@user1.votes.up.by_type(Post)
|
@@ -109,8 +116,8 @@ Once scoping is complete, you can also trigger a get for the
|
|
109
116
|
voter/votable
|
110
117
|
|
111
118
|
```ruby
|
112
|
-
@post.
|
113
|
-
@post.
|
119
|
+
@post.votes_for.up.by_type(User).voters
|
120
|
+
@post.votes_for.down.by_type(User).voters
|
114
121
|
|
115
122
|
@user.votes.up.for_type(Post).votables
|
116
123
|
@user.votes.up.votables
|
@@ -135,28 +142,28 @@ You can add an scope to your vote
|
|
135
142
|
```ruby
|
136
143
|
# positive votes
|
137
144
|
@post.liked_by @user1, :vote_scope => 'rank'
|
138
|
-
@post.
|
139
|
-
@post.
|
145
|
+
@post.vote_by :voter => @user3, :vote_scope => 'rank'
|
146
|
+
@post.vote_by :voter => @user5, :vote => 'like', :vote_scope => 'rank'
|
140
147
|
|
141
148
|
# negative votes
|
142
149
|
@post.downvote_from @user2, :vote_scope => 'rank'
|
143
|
-
@post.
|
150
|
+
@post.vote_by :voter => @user2, :vote => 'bad', :vote_scope => 'rank'
|
144
151
|
|
145
152
|
# tally them up!
|
146
|
-
@post.
|
147
|
-
@post.
|
148
|
-
@post.
|
149
|
-
@post.
|
150
|
-
@post.
|
153
|
+
@post.find_votes_for(:vote_scope => 'rank').size # => 5
|
154
|
+
@post.get_likes(:vote_scope => 'rank').size # => 3
|
155
|
+
@post.get_upvotes(:vote_scope => 'rank').size # => 3
|
156
|
+
@post.get_dislikes(:vote_scope => 'rank').size # => 2
|
157
|
+
@post.get_downvotes(:vote_scope => 'rank').size # => 2
|
151
158
|
|
152
159
|
# votable model can be voted under different scopes
|
153
160
|
# by the same user
|
154
|
-
@post.
|
155
|
-
@post.
|
161
|
+
@post.vote_by :voter => @user1, :vote_scope => 'week'
|
162
|
+
@post.vote_by :voter => @user1, :vote_scope => 'month'
|
156
163
|
|
157
|
-
@post.
|
158
|
-
@post.
|
159
|
-
@post.
|
164
|
+
@post.votes_for.size # => 2
|
165
|
+
@post.find_votes_for(:vote_scope => 'week').size # => 1
|
166
|
+
@post.find_votes_for(:vote_scope => 'month').size # => 1
|
160
167
|
```
|
161
168
|
### Adding weights to your votes
|
162
169
|
|
@@ -165,19 +172,19 @@ You can add weight to your vote. The default value is 1.
|
|
165
172
|
```ruby
|
166
173
|
# positive votes
|
167
174
|
@post.liked_by @user1, :vote_weight => 1
|
168
|
-
@post.
|
169
|
-
@post.
|
175
|
+
@post.vote_by :voter => @user3, :vote_weight => 2
|
176
|
+
@post.vote_by :voter => @user5, :vote => 'like', :vote_scope => 'rank', :vote_weight => 3
|
170
177
|
|
171
178
|
# negative votes
|
172
179
|
@post.downvote_from @user2, :vote_scope => 'rank', :vote_weight => 1
|
173
|
-
@post.
|
180
|
+
@post.vote_by :voter => @user2, :vote => 'bad', :vote_scope => 'rank', :vote_weight => 3
|
174
181
|
|
175
182
|
# tally them up!
|
176
|
-
@post.
|
177
|
-
@post.
|
178
|
-
@post.
|
179
|
-
@post.
|
180
|
-
@post.
|
183
|
+
@post.find_votes_for(:vote_scope => 'rank').sum(:vote_weight) # => 6
|
184
|
+
@post.get_likes(:vote_scope => 'rank').sum(:vote_weight) # => 6
|
185
|
+
@post.get_upvotes(:vote_scope => 'rank').sum(:vote_weight) # => 6
|
186
|
+
@post.get_dislikes(:vote_scope => 'rank').sum(:vote_weight) # => 4
|
187
|
+
@post.get_downvotes(:vote_scope => 'rank').sum(:vote_weight) # => 4
|
181
188
|
```
|
182
189
|
|
183
190
|
### The Voter
|
@@ -292,7 +299,7 @@ To permit duplicates entries of a same voter, use option duplicate. Also notice
|
|
292
299
|
will limit some other methods that didn't deal with multiples votes, in this case, the last vote will be considered.
|
293
300
|
|
294
301
|
```ruby
|
295
|
-
@hat.
|
302
|
+
@hat.vote_by voter: @user, :duplicate => true
|
296
303
|
```
|
297
304
|
|
298
305
|
## Caching
|
@@ -338,6 +345,23 @@ They can be run with:
|
|
338
345
|
rake spec
|
339
346
|
```
|
340
347
|
|
348
|
+
## Changes
|
349
|
+
|
350
|
+
### Fixes for votable voter model
|
351
|
+
|
352
|
+
In version 0.8.0, there is bugs for a model that is both votable and voter.
|
353
|
+
Some name-conflicting methods are renamed:
|
354
|
+
+ Renamed Votable.votes to votes_for
|
355
|
+
+ Renamed Votable.vote to vote_by,
|
356
|
+
+ Removed Votable.vote_by alias (was an alias for :vote_up)
|
357
|
+
+ Renamed Votable.unvote_for to unvote_by
|
358
|
+
+ Renamed Votable.find_votes to find_votes_for
|
359
|
+
+ Renamed Votable.up_votes to get_upvotes
|
360
|
+
+ and its aliases :get_true_votes, :get_ups, :get_upvotes, :get_likes, :get_positives, :get_for_votes
|
361
|
+
+ Renamed Votable.down_votes to get_downvotes
|
362
|
+
+ and its aliases :get_false_votes, :get_downs, :get_downvotes, :get_dislikes, :get_negatives
|
363
|
+
|
364
|
+
|
341
365
|
## License
|
342
366
|
|
343
367
|
Acts as votable is released under the [MIT
|
@@ -352,7 +376,6 @@ License](http://www.opensource.org/licenses/MIT).
|
|
352
376
|
that the user likes, while `@user.likes @model` will cast a vote for @model by
|
353
377
|
@user.
|
354
378
|
|
355
|
-
- Need to test a model that is votable as well as a voter
|
356
379
|
|
357
380
|
- The aliased methods are referred to by using the terms 'up/down' and/or
|
358
381
|
'true/false'. Need to come up with guidelines for naming these methods.
|
@@ -11,7 +11,7 @@ module ActsAsVotable
|
|
11
11
|
aliases = {
|
12
12
|
|
13
13
|
:vote_up => [
|
14
|
-
:up_by, :upvote_by, :like_by, :liked_by,
|
14
|
+
:up_by, :upvote_by, :like_by, :liked_by,
|
15
15
|
:up_from, :upvote_from, :upvote_by, :like_from, :liked_from, :vote_from
|
16
16
|
],
|
17
17
|
|
@@ -20,20 +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
|
-
:
|
30
|
+
:unvote_by => [
|
31
31
|
:unvote_up, :unvote_down, :unliked_by, :undisliked_by
|
32
32
|
]
|
33
33
|
}
|
34
34
|
|
35
35
|
base.class_eval do
|
36
|
-
has_many :
|
36
|
+
has_many :votes_for, :class_name => 'ActsAsVotable::Vote', :as => :votable, :dependent => :destroy do
|
37
37
|
def voters
|
38
38
|
includes(:voter).map(&:voter)
|
39
39
|
end
|
@@ -62,7 +62,7 @@ module ActsAsVotable
|
|
62
62
|
end
|
63
63
|
|
64
64
|
# voting
|
65
|
-
def
|
65
|
+
def vote_by args = {}
|
66
66
|
|
67
67
|
options = {
|
68
68
|
:vote => true,
|
@@ -76,7 +76,7 @@ module ActsAsVotable
|
|
76
76
|
end
|
77
77
|
|
78
78
|
# find the vote
|
79
|
-
_votes_ =
|
79
|
+
_votes_ = find_votes_for({
|
80
80
|
:voter_id => options[:voter].id,
|
81
81
|
:vote_scope => options[:vote_scope],
|
82
82
|
:voter_type => options[:voter].class.name
|
@@ -89,8 +89,6 @@ module ActsAsVotable
|
|
89
89
|
:voter => options[:voter],
|
90
90
|
:vote_scope => options[:vote_scope]
|
91
91
|
)
|
92
|
-
#Allowing for a vote_weight to be associated with every vote. Could change with every voter object
|
93
|
-
vote.vote_weight = options.fetch(:vote_weight, 1).to_i
|
94
92
|
else
|
95
93
|
# this voter is potentially changing his vote
|
96
94
|
vote = _votes_.last
|
@@ -100,6 +98,9 @@ module ActsAsVotable
|
|
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
106
|
update_cached_votes options[:vote_scope]
|
@@ -113,25 +114,25 @@ 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
121
|
update_cached_votes args[:vote_scope]
|
121
|
-
self.vote_registered = false if
|
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]
|
131
132
|
end
|
132
133
|
|
133
|
-
def
|
134
|
-
self.unvote :voter => voter, :vote_scope => options[:vote_scope] #Does not need vote_weight since the
|
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
|
135
136
|
end
|
136
137
|
|
137
138
|
def scope_cache_field field, vote_scope
|
@@ -154,7 +155,7 @@ module ActsAsVotable
|
|
154
155
|
"cached_scoped_#{vote_scope}_votes_score="
|
155
156
|
when :cached_votes_score
|
156
157
|
"cached_scoped_#{vote_scope}_votes_score"
|
157
|
-
when :
|
158
|
+
when :cached_weighted_score
|
158
159
|
"cached_weighted_#{vote_scope}_score"
|
159
160
|
when :cached_weighted_score=
|
160
161
|
"cached_weighted_#{vote_scope}_score="
|
@@ -224,16 +225,16 @@ module ActsAsVotable
|
|
224
225
|
|
225
226
|
|
226
227
|
# results
|
227
|
-
def
|
228
|
-
|
228
|
+
def find_votes_for extra_conditions = {}
|
229
|
+
votes_for.where(extra_conditions)
|
229
230
|
end
|
230
231
|
|
231
|
-
def
|
232
|
-
|
232
|
+
def get_up_votes options={}
|
233
|
+
find_votes_for(:vote_flag => true, :vote_scope => options[:vote_scope])
|
233
234
|
end
|
234
235
|
|
235
|
-
def
|
236
|
-
|
236
|
+
def get_down_votes options={}
|
237
|
+
find_votes_for(:vote_flag => false, :vote_scope => options[:vote_scope])
|
237
238
|
end
|
238
239
|
|
239
240
|
|
@@ -242,35 +243,35 @@ module ActsAsVotable
|
|
242
243
|
if !skip_cache && self.respond_to?(scope_cache_field :cached_votes_total, vote_scope)
|
243
244
|
return self.send(scope_cache_field :cached_votes_total, vote_scope)
|
244
245
|
end
|
245
|
-
|
246
|
+
find_votes_for(:vote_scope => vote_scope).count
|
246
247
|
end
|
247
248
|
|
248
249
|
def count_votes_up skip_cache = false, vote_scope = nil
|
249
250
|
if !skip_cache && self.respond_to?(scope_cache_field :cached_votes_up, vote_scope)
|
250
251
|
return self.send(scope_cache_field :cached_votes_up, vote_scope)
|
251
252
|
end
|
252
|
-
|
253
|
+
get_up_votes(:vote_scope => vote_scope).count
|
253
254
|
end
|
254
255
|
|
255
256
|
def count_votes_down skip_cache = false, vote_scope = nil
|
256
257
|
if !skip_cache && self.respond_to?(scope_cache_field :cached_votes_down, vote_scope)
|
257
258
|
return self.send(scope_cache_field :cached_votes_down, vote_scope)
|
258
259
|
end
|
259
|
-
|
260
|
+
get_down_votes(:vote_scope => vote_scope).count
|
260
261
|
end
|
261
262
|
|
262
263
|
def weighted_score skip_cache = false, vote_scope = nil
|
263
264
|
if !skip_cache && self.respond_to?(scope_cache_field :cached_weighted_score, vote_scope)
|
264
265
|
return self.send(scope_cache_field :cached_weighted_score, vote_scope)
|
265
266
|
end
|
266
|
-
ups =
|
267
|
-
downs =
|
267
|
+
ups = get_up_votes(:vote_scope => vote_scope).sum(:vote_weight)
|
268
|
+
downs = get_down_votes(:vote_scope => vote_scope).sum(:vote_weight)
|
268
269
|
ups - downs
|
269
270
|
end
|
270
271
|
|
271
272
|
# voters
|
272
273
|
def voted_on_by? voter
|
273
|
-
votes =
|
274
|
+
votes = find_votes_for :voter_id => voter.id, :voter_type => voter.class.name
|
274
275
|
votes.count > 0
|
275
276
|
end
|
276
277
|
|
@@ -36,7 +36,7 @@ module ActsAsVotable
|
|
36
36
|
|
37
37
|
# voting
|
38
38
|
def vote args
|
39
|
-
args[:votable].
|
39
|
+
args[:votable].vote_by args.merge({:voter => self})
|
40
40
|
end
|
41
41
|
|
42
42
|
def vote_up_for model=nil, args={}
|
@@ -47,8 +47,8 @@ module ActsAsVotable
|
|
47
47
|
vote :votable => model, :vote_scope => args[:vote_scope], :vote => false
|
48
48
|
end
|
49
49
|
|
50
|
-
def unvote_for model
|
51
|
-
model.unvote :voter => self
|
50
|
+
def unvote_for model, args={}
|
51
|
+
model.unvote :voter => self, :vote_scope => args[:vote_scope]
|
52
52
|
end
|
53
53
|
|
54
54
|
# results
|
@@ -120,15 +120,15 @@ module ActsAsVotable
|
|
120
120
|
end
|
121
121
|
|
122
122
|
def get_voted klass, extra_conditions = {}
|
123
|
-
klass.joins(:
|
123
|
+
klass.joins(:votes_for).merge find_votes(extra_conditions)
|
124
124
|
end
|
125
125
|
|
126
126
|
def get_up_voted klass
|
127
|
-
klass.joins(:
|
127
|
+
klass.joins(:votes_for).merge find_up_votes
|
128
128
|
end
|
129
129
|
|
130
130
|
def get_down_voted klass
|
131
|
-
klass.joins(:
|
131
|
+
klass.joins(:votes_for).merge find_down_votes
|
132
132
|
end
|
133
133
|
end
|
134
134
|
end
|