acts_as_votable 0.8.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 +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
|