voteable_mongoid 0.7.2 → 0.7.3
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.
- data/.rvmrc +2 -0
- data/CHANGELOG.rdoc +8 -2
- data/README.rdoc +20 -8
- data/TODO +1 -1
- data/lib/voteable_mongoid/version.rb +1 -1
- data/lib/voteable_mongoid/voteable/voting.rb +48 -34
- data/lib/voteable_mongoid/voteable.rb +93 -55
- data/lib/voteable_mongoid/voter.rb +71 -68
- data/spec/models/category.rb +8 -0
- data/spec/models/comment.rb +6 -4
- data/spec/models/post.rb +7 -2
- data/spec/spec_helper.rb +1 -0
- data/spec/voteable_mongoid/tasks_spec.rb +33 -0
- data/spec/voteable_mongoid/voteable_spec.rb +104 -38
- data/spec/voteable_mongoid/voter_spec.rb +7 -7
- data/voteable_mongoid.gemspec +1 -0
- metadata +19 -5
data/.rvmrc
ADDED
data/CHANGELOG.rdoc
CHANGED
@@ -1,10 +1,16 @@
|
|
1
|
+
== 0.7.3
|
2
|
+
* Add :return_votee => true option to vote function to warranty always return voteable object
|
3
|
+
* Add Voteable.voted?, Voteable.up_voted?, Voteable.down_voted?
|
4
|
+
* Update parent for ManyToMany relationship
|
5
|
+
* Refactor
|
6
|
+
|
1
7
|
== 0.7.2
|
2
8
|
* Use Collection#find_and_modify to retrieve updated votes data and parent_ids (don't need an extra query to get parent_ids)
|
3
9
|
|
4
10
|
== 0.7.1
|
5
|
-
* Refactor & cleanup source code
|
6
|
-
* Better doc
|
7
11
|
* Add votee#voted_by?(voter or voter_id)
|
12
|
+
* Better doc
|
13
|
+
* Refactor & cleanup source code
|
8
14
|
|
9
15
|
== 0.7.0
|
10
16
|
* Use readable field names (up, down, up_count, down_count, count, point) instead of very short field names (u, d, uc, dc, c, p)
|
data/README.rdoc
CHANGED
@@ -3,7 +3,9 @@
|
|
3
3
|
Voteable Mongoid allows you to make your Mongoid::Document objects voteable (up or down).
|
4
4
|
For instance, in a forum, a user can vote up (or down) on a post or a comment.
|
5
5
|
|
6
|
-
|
6
|
+
Initial idea is based on http://cookbook.mongodb.org/patterns/votes
|
7
|
+
|
8
|
+
Voteable Mongoid is built for speed. It uses only one database request per collection to validate data, update data, and get updated data.
|
7
9
|
|
8
10
|
Sample app at https://github.com/vinova/simple_qa
|
9
11
|
|
@@ -30,7 +32,7 @@ post.rb
|
|
30
32
|
# set points for each vote
|
31
33
|
voteable self, :up => +1, :down => -1
|
32
34
|
|
33
|
-
|
35
|
+
has_many :comments
|
34
36
|
end
|
35
37
|
|
36
38
|
comment.rb
|
@@ -41,7 +43,7 @@ comment.rb
|
|
41
43
|
include Mongoid::Document
|
42
44
|
include Mongoid::Voteable
|
43
45
|
|
44
|
-
|
46
|
+
belongs_to :post
|
45
47
|
|
46
48
|
voteable self, :up => +1, :down => -3
|
47
49
|
|
@@ -59,11 +61,12 @@ user.rb
|
|
59
61
|
=== Making a vote
|
60
62
|
|
61
63
|
@user.vote(@post, :up)
|
62
|
-
|
64
|
+
|
65
|
+
Is equivalent to
|
63
66
|
@user.vote(:votee => @post, :value => :up)
|
64
67
|
@post.vote(:voter => @user, :value => :up)
|
65
68
|
|
66
|
-
|
69
|
+
In case you don't need to init voter and / or votee objects you can
|
67
70
|
@user.vote(:votee_type => 'Post', :votee_id => post_id, :value => :down)
|
68
71
|
@post.vote(:voter_id => user_id, :value => :up)
|
69
72
|
Post.vote(:voter_id => user_id, :votee_id => post_id, :value => :up)
|
@@ -72,10 +75,19 @@ user.rb
|
|
72
75
|
|
73
76
|
@user.unvote(@comment)
|
74
77
|
|
75
|
-
=== If have
|
78
|
+
=== If have voter_id, votee_id and vote value you don't need to init voter and votee objects (suitable for API calls)
|
79
|
+
|
80
|
+
New vote
|
81
|
+
Post.vote(:voter_id => user_id, :votee_id => post_id, :value => :up)
|
76
82
|
|
83
|
+
Re-vote
|
77
84
|
Post.vote(:voter_id => user_id, :votee_id => post_id, :value => :up, :revote => true)
|
85
|
+
|
86
|
+
Un-vote
|
78
87
|
Post.vote(:voter_id => user_id, :votee_id => post_id, :value => :up, :unvote => true)
|
88
|
+
|
89
|
+
In-case you need updated voteable object, add :return_votee => true
|
90
|
+
votee = Post.vote(:voter_id => user_id, :votee_id => post_id, :value => :up, :return_votee => true)
|
79
91
|
|
80
92
|
=== Getting vote_value
|
81
93
|
|
@@ -126,8 +138,8 @@ Ruby
|
|
126
138
|
|
127
139
|
== Credits
|
128
140
|
|
129
|
-
* Alex
|
130
|
-
* Stefan
|
141
|
+
* Alex Nguyen (alex@vinova.sg) - Author
|
142
|
+
* Stefan Nguyen (stefan@vinova.sg) - Unvoting
|
131
143
|
|
132
144
|
Copyright (c) 2010-2011 Vinova Pte Ltd (http://vinova.sg)
|
133
145
|
|
@@ -10,28 +10,25 @@ module Mongoid
|
|
10
10
|
# - :votee_id: the votee document id
|
11
11
|
# - :voter_id: the voter document id
|
12
12
|
# - :value: :up or :down
|
13
|
-
# - :revote: change
|
14
|
-
# - :unvote:
|
13
|
+
# - :revote: if true change vote vote from :up to :down and vise versa
|
14
|
+
# - :unvote: if true undo the voting
|
15
|
+
# - :return: if true always return updated voteable object
|
16
|
+
#
|
17
|
+
# @return [votes, false, nil]
|
15
18
|
def vote(options)
|
16
|
-
options
|
17
|
-
options[:votee_id] ||= options[:votee].id
|
18
|
-
options[:votee_id] = BSON::ObjectId(options[:votee_id]) if options[:votee_id].is_a?(String)
|
19
|
-
options[:voter_id] = BSON::ObjectId(options[:voter_id]) if options[:voter_id].is_a?(String)
|
20
|
-
options[:value] = options[:value].to_sym
|
19
|
+
validate_and_normalize_vote_options(options)
|
21
20
|
options[:voteable] = VOTEABLE[name][name]
|
22
21
|
|
23
|
-
update_parents = options[:voteable][:update_parents]
|
24
|
-
|
25
22
|
if options[:voteable]
|
26
23
|
query, update = if options[:revote]
|
27
|
-
|
24
|
+
revote_query_and_update(options)
|
28
25
|
elsif options[:unvote]
|
29
|
-
|
26
|
+
unvote_query_and_update(options)
|
30
27
|
else
|
31
|
-
|
28
|
+
new_vote_query_and_update(options)
|
32
29
|
end
|
33
30
|
|
34
|
-
if options[:votee] ||
|
31
|
+
if options[:voteable][:update_parents] || options[:votee] || options[:return_votee]
|
35
32
|
# If votee exits or need to update parent
|
36
33
|
# use Collection#find_and_modify to retrieve updated votes data and parent_ids
|
37
34
|
begin
|
@@ -42,9 +39,11 @@ module Mongoid
|
|
42
39
|
)
|
43
40
|
# Update new votes data
|
44
41
|
options[:votee].write_attribute('votes', doc['votes']) if options[:votee]
|
45
|
-
update_parent_votes(doc, options) if update_parents
|
42
|
+
update_parent_votes(doc, options) if options[:voteable][:update_parents]
|
43
|
+
return options[:votee] || new(doc)
|
46
44
|
rescue
|
47
45
|
# Don't update parents if operation fail or no matching object found
|
46
|
+
return false
|
48
47
|
end
|
49
48
|
else
|
50
49
|
# Just update and don't care the result
|
@@ -55,7 +54,14 @@ module Mongoid
|
|
55
54
|
|
56
55
|
|
57
56
|
private
|
58
|
-
def
|
57
|
+
def validate_and_normalize_vote_options(options)
|
58
|
+
options.symbolize_keys!
|
59
|
+
options[:votee_id] = BSON::ObjectId(options[:votee_id]) if options[:votee_id].is_a?(String)
|
60
|
+
options[:voter_id] = BSON::ObjectId(options[:voter_id]) if options[:voter_id].is_a?(String)
|
61
|
+
options[:value] &&= options[:value].to_sym
|
62
|
+
end
|
63
|
+
|
64
|
+
def new_vote_query_and_update(options)
|
59
65
|
if options[:value] == :up
|
60
66
|
positive_voter_ids = 'votes.up'
|
61
67
|
positive_votes_count = 'votes.up_count'
|
@@ -80,7 +86,7 @@ module Mongoid
|
|
80
86
|
end
|
81
87
|
|
82
88
|
|
83
|
-
def
|
89
|
+
def revote_query_and_update(options)
|
84
90
|
if options[:value] == :up
|
85
91
|
positive_voter_ids = 'votes.up'
|
86
92
|
negative_voter_ids = 'votes.down'
|
@@ -113,7 +119,7 @@ module Mongoid
|
|
113
119
|
end
|
114
120
|
|
115
121
|
|
116
|
-
def
|
122
|
+
def unvote_query_and_update(options)
|
117
123
|
if options[:value] == :up
|
118
124
|
positive_voter_ids = 'votes.up'
|
119
125
|
negative_voter_ids = 'votes.down'
|
@@ -142,28 +148,36 @@ module Mongoid
|
|
142
148
|
|
143
149
|
|
144
150
|
def update_parent_votes(doc, options)
|
145
|
-
value = options[:value]
|
146
|
-
votee ||= options[:votee]
|
147
|
-
|
148
151
|
VOTEABLE[name].each do |class_name, voteable|
|
149
|
-
# For other class in VOTEABLE options, if
|
150
|
-
|
151
|
-
|
152
|
-
next unless foreign_key_value = doc[relation_metadata.foreign_key.to_s]
|
152
|
+
# For other class in VOTEABLE options, if has relationship with current class
|
153
|
+
relation_metadata = relations.find{ |x, r| r.class_name == class_name }.try(:last)
|
154
|
+
next unless relation_metadata.present?
|
153
155
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
156
|
+
# If cannot find current votee foreign_key value for that class
|
157
|
+
foreign_key_value = doc[relation_metadata.foreign_key.to_s]
|
158
|
+
next unless foreign_key_value.present?
|
159
|
+
|
160
|
+
if relation_metadata.relation == Mongoid::Relations::Referenced::In
|
161
|
+
class_name.constantize.collection.update(
|
162
|
+
{ '_id' => foreign_key_value },
|
163
|
+
{ '$inc' => parent_inc_options(voteable, options) }
|
164
|
+
)
|
165
|
+
elsif relation_metadata.relation == Mongoid::Relations::Referenced::ManyToMany
|
166
|
+
class_name.constantize.collection.update(
|
167
|
+
{ '_id' => { '$in' => foreign_key_value } },
|
168
|
+
{ '$inc' => parent_inc_options(voteable, options) },
|
169
|
+
{ :multi => true }
|
170
|
+
)
|
171
|
+
end
|
158
172
|
end
|
159
173
|
end
|
160
174
|
|
161
175
|
|
162
|
-
def parent_inc_options(
|
176
|
+
def parent_inc_options(voteable, options)
|
163
177
|
inc_options = {}
|
164
178
|
|
165
179
|
if options[:revote]
|
166
|
-
if value == :up
|
180
|
+
if options[:value] == :up
|
167
181
|
inc_options['votes.point'] = voteable[:up] - voteable[:down]
|
168
182
|
unless voteable[:update_counters] == false
|
169
183
|
inc_options['votes.up_count'] = +1
|
@@ -178,10 +192,10 @@ module Mongoid
|
|
178
192
|
end
|
179
193
|
|
180
194
|
elsif options[:unvote]
|
181
|
-
inc_options['votes.point'] = -voteable[value]
|
195
|
+
inc_options['votes.point'] = -voteable[options[:value]]
|
182
196
|
unless voteable[:update_counters] == false
|
183
197
|
inc_options['votes.count'] = -1
|
184
|
-
if value == :up
|
198
|
+
if options[:value] == :up
|
185
199
|
inc_options['votes.up_count'] = -1
|
186
200
|
else
|
187
201
|
inc_options['votes.down_count'] = -1
|
@@ -189,10 +203,10 @@ module Mongoid
|
|
189
203
|
end
|
190
204
|
|
191
205
|
else # new vote
|
192
|
-
inc_options['votes.point'] = voteable[value]
|
206
|
+
inc_options['votes.point'] = voteable[options[:value]]
|
193
207
|
unless voteable[:update_counters] == false
|
194
208
|
inc_options['votes.count'] = +1
|
195
|
-
if value == :up
|
209
|
+
if options[:value] == :up
|
196
210
|
inc_options['votes.up_count'] = +1
|
197
211
|
else
|
198
212
|
inc_options['votes.down_count'] = +1
|
@@ -6,8 +6,8 @@ module Mongoid
|
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
8
|
included do
|
9
|
-
include Document
|
10
|
-
include Voting
|
9
|
+
include ::Mongoid::Document
|
10
|
+
include ::Mongoid::Voteable::Voting
|
11
11
|
|
12
12
|
field :votes, :type => Votes
|
13
13
|
|
@@ -50,70 +50,108 @@ module Mongoid
|
|
50
50
|
VOTEABLE[name][name][:update_parents] = true
|
51
51
|
end
|
52
52
|
end
|
53
|
+
|
54
|
+
# Check if voter_id do a vote on votee_id
|
55
|
+
#
|
56
|
+
# @param [Hash] options a hash containings:
|
57
|
+
# - :votee_id: the votee document id
|
58
|
+
# - :voter_id: the voter document id
|
59
|
+
#
|
60
|
+
# @return [true, false]
|
61
|
+
def voted?(options)
|
62
|
+
validate_and_normalize_vote_options(options)
|
63
|
+
up_voted?(options) || down_voted?(options)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Check if voter_id do an up vote on votee_id
|
67
|
+
#
|
68
|
+
# @param [Hash] options a hash containings:
|
69
|
+
# - :votee_id: the votee document id
|
70
|
+
# - :voter_id: the voter document id
|
71
|
+
#
|
72
|
+
# @return [true, false]
|
73
|
+
def up_voted?(options)
|
74
|
+
validate_and_normalize_vote_options(options)
|
75
|
+
up_voted_by(options[:voter_id]).where(:_id => options[:votee_id]).count == 1
|
76
|
+
end
|
77
|
+
|
78
|
+
# Check if voter_id do a down vote on votee_id
|
79
|
+
#
|
80
|
+
# @param [Hash] options a hash containings:
|
81
|
+
# - :votee_id: the votee document id
|
82
|
+
# - :voter_id: the voter document id
|
83
|
+
#
|
84
|
+
# @return [true, false]
|
85
|
+
def down_voted?(options)
|
86
|
+
validate_and_normalize_vote_options(options)
|
87
|
+
down_voted_by(options[:voter_id]).where(:_id => options[:votee_id]).count == 1
|
88
|
+
end
|
53
89
|
end
|
54
90
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
options
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
if options[:unvote]
|
68
|
-
options[:value] ||= vote_value(options[:voter_id])
|
69
|
-
else
|
70
|
-
options[:revote] ||= vote_value(options[:voter_id]).present?
|
71
|
-
end
|
91
|
+
module InstanceMethods
|
92
|
+
# Make a vote on this votee
|
93
|
+
#
|
94
|
+
# @param [Hash] options a hash containings:
|
95
|
+
# - :voter_id: the voter document id
|
96
|
+
# - :value: vote :up or vote :down
|
97
|
+
# - :revote: change from vote up to vote down
|
98
|
+
# - :unvote: unvote the vote value (:up or :down)
|
99
|
+
def vote(options)
|
100
|
+
options[:votee_id] = id
|
101
|
+
options[:votee] = self
|
102
|
+
options[:voter_id] ||= options[:voter].id
|
72
103
|
|
73
|
-
|
74
|
-
|
104
|
+
if options[:unvote]
|
105
|
+
options[:value] ||= vote_value(options[:voter_id])
|
106
|
+
else
|
107
|
+
options[:revote] ||= vote_value(options[:voter_id]).present?
|
108
|
+
end
|
75
109
|
|
76
|
-
|
77
|
-
|
78
|
-
# @param [Mongoid Object, BSON::ObjectId] voter is Mongoid object or the id of the voter who made the vote
|
79
|
-
def vote_value(voter)
|
80
|
-
voter_id = voter.is_a?(BSON::ObjectId) ? voter : voter.id
|
81
|
-
return :up if up_voter_ids.include?(voter_id)
|
82
|
-
return :down if down_voter_ids.include?(voter_id)
|
83
|
-
end
|
110
|
+
self.class.vote(options)
|
111
|
+
end
|
84
112
|
|
85
|
-
|
86
|
-
|
87
|
-
|
113
|
+
# Get a voted value on this votee
|
114
|
+
#
|
115
|
+
# @param [Mongoid Object, BSON::ObjectId] voter is Mongoid object or the id of the voter who made the vote
|
116
|
+
def vote_value(voter)
|
117
|
+
voter_id = voter.is_a?(BSON::ObjectId) ? voter : voter.id
|
118
|
+
return :up if up_voter_ids.include?(voter_id)
|
119
|
+
return :down if down_voter_ids.include?(voter_id)
|
120
|
+
end
|
121
|
+
|
122
|
+
def voted_by?(voter)
|
123
|
+
!!vote_value(voter)
|
124
|
+
end
|
88
125
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
126
|
+
# Array of up voter ids
|
127
|
+
def up_voter_ids
|
128
|
+
votes.try(:[], 'up') || []
|
129
|
+
end
|
93
130
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
131
|
+
# Array of down voter ids
|
132
|
+
def down_voter_ids
|
133
|
+
votes.try(:[], 'down') || []
|
134
|
+
end
|
98
135
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
136
|
+
# Get the number of up votes
|
137
|
+
def up_votes_count
|
138
|
+
votes.try(:[], 'up_count') || 0
|
139
|
+
end
|
103
140
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
141
|
+
# Get the number of down votes
|
142
|
+
def down_votes_count
|
143
|
+
votes.try(:[], 'down_count') || 0
|
144
|
+
end
|
108
145
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
146
|
+
# Get the number of votes
|
147
|
+
def votes_count
|
148
|
+
votes.try(:[], 'count') || 0
|
149
|
+
end
|
113
150
|
|
114
|
-
|
115
|
-
|
116
|
-
|
151
|
+
# Get the votes point
|
152
|
+
def votes_point
|
153
|
+
votes.try(:[], 'point') || 0
|
154
|
+
end
|
117
155
|
end
|
118
156
|
|
119
157
|
end
|
@@ -1,86 +1,89 @@
|
|
1
1
|
module Mongoid
|
2
2
|
module Voter
|
3
3
|
extend ActiveSupport::Concern
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
votee = options[:votee]
|
15
|
-
if votee
|
16
|
-
votee_class = votee.class
|
17
|
-
votee_id = votee.id
|
4
|
+
|
5
|
+
module InstanceMethods
|
6
|
+
# Check to see if this voter voted on the votee or not
|
7
|
+
#
|
8
|
+
# @param [Hash, Object] options the hash containing the votee, or the votee itself
|
9
|
+
# @return [true, false] true if voted, false otherwise
|
10
|
+
def voted?(options)
|
11
|
+
unless options.is_a?(Hash)
|
12
|
+
votee_class = options.class
|
13
|
+
votee_id = options.id
|
18
14
|
else
|
19
|
-
|
20
|
-
|
15
|
+
votee = options[:votee]
|
16
|
+
if votee
|
17
|
+
votee_class = votee.class
|
18
|
+
votee_id = votee.id
|
19
|
+
else
|
20
|
+
votee_class = options[:votee_type].classify.constantize
|
21
|
+
votee_id = options[:votee_id]
|
22
|
+
end
|
21
23
|
end
|
22
|
-
end
|
23
24
|
|
24
|
-
|
25
|
-
|
25
|
+
votee_class.voted?(:voter_id => id, :votee_id => votee_id)
|
26
|
+
end
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
28
|
+
# Get the voted value on a votee
|
29
|
+
#
|
30
|
+
# @param (see #voted?)
|
31
|
+
# @return [Symbol, nil] :up or :down or nil if not voted
|
32
|
+
def vote_value(options)
|
33
|
+
votee = unless options.is_a?(Hash)
|
34
|
+
options
|
35
|
+
else
|
36
|
+
options[:votee] || options[:votee_type].classify.constantize.only(:votes).where(
|
37
|
+
:_id => options[:votee_id]
|
38
|
+
).first
|
39
|
+
end
|
40
|
+
votee.vote_value(_id)
|
38
41
|
end
|
39
|
-
votee.vote_value(_id)
|
40
|
-
end
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
43
|
+
# Cancel the vote on a votee
|
44
|
+
#
|
45
|
+
# @param [Object] votee the votee to be unvoted
|
46
|
+
def unvote(options)
|
47
|
+
unless options.is_a?(Hash)
|
48
|
+
options = { :votee => options }
|
49
|
+
end
|
50
|
+
options[:unvote] = true
|
51
|
+
options[:revote] = false
|
52
|
+
vote(options)
|
48
53
|
end
|
49
|
-
options[:unvote] = true
|
50
|
-
options[:revote] = false
|
51
|
-
vote(options)
|
52
|
-
end
|
53
54
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
55
|
+
# Vote on a votee
|
56
|
+
#
|
57
|
+
# @param (see #voted?)
|
58
|
+
# @param [:up, :down] vote_value vote up or vote down, nil to unvote
|
59
|
+
def vote(options, value = nil)
|
60
|
+
if options.is_a?(Hash)
|
61
|
+
votee = options[:votee]
|
62
|
+
else
|
63
|
+
votee = options
|
64
|
+
options = { :votee => votee, :value => value }
|
65
|
+
end
|
65
66
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
67
|
+
if votee
|
68
|
+
options[:votee_id] = votee.id
|
69
|
+
votee_class = votee.class
|
70
|
+
else
|
71
|
+
votee_class = options[:votee_type].classify.constantize
|
72
|
+
end
|
72
73
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
74
|
+
if options[:value].nil?
|
75
|
+
options[:unvote] = true
|
76
|
+
options[:value] = vote_value(options)
|
77
|
+
else
|
78
|
+
options[:revote] = options.has_key?(:revote) ? !options[:revote].blank? : voted?(options)
|
79
|
+
end
|
79
80
|
|
80
|
-
|
81
|
-
|
81
|
+
options[:voter] = self
|
82
|
+
options[:voter_id] = id
|
82
83
|
|
83
|
-
|
84
|
+
( votee || votee_class ).vote(options)
|
85
|
+
end
|
84
86
|
end
|
87
|
+
|
85
88
|
end
|
86
89
|
end
|
data/spec/models/comment.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
require 'post'
|
2
2
|
|
3
3
|
class Comment
|
4
|
-
include Mongoid::Document
|
5
4
|
include Mongoid::Voteable
|
6
|
-
|
7
|
-
|
5
|
+
include Mongoid::Document
|
6
|
+
|
7
|
+
field :content
|
8
|
+
|
9
|
+
belongs_to :post
|
8
10
|
|
9
11
|
voteable self, :up => +1, :down => -3
|
10
|
-
voteable Post, :up => +2, :down => -1
|
12
|
+
voteable Post, :up => +2, :down => -1
|
11
13
|
end
|
data/spec/models/post.rb
CHANGED
@@ -2,7 +2,12 @@ class Post
|
|
2
2
|
include Mongoid::Document
|
3
3
|
include Mongoid::Voteable
|
4
4
|
|
5
|
-
|
5
|
+
field :title
|
6
|
+
field :content
|
6
7
|
|
7
|
-
|
8
|
+
has_and_belongs_to_many :categories
|
9
|
+
has_many :comments
|
10
|
+
|
11
|
+
voteable self, :up => +1, :down => -1
|
12
|
+
voteable Category, :up => +3, :down => -5, :update_counters => false
|
8
13
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -0,0 +1,33 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Mongoid::Voteable::Tasks do
|
4
|
+
describe 'Mongoid::Voteable::Tasks.init_stats' do
|
5
|
+
before :all do
|
6
|
+
@post1 = Post.create!
|
7
|
+
@post2 = Post.create!
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'after create votes has default value' do
|
11
|
+
@post1.votes.should == Mongoid::Voteable::Votes::DEFAULT_ATTRIBUTES
|
12
|
+
@post2.votes.should == Mongoid::Voteable::Votes::DEFAULT_ATTRIBUTES
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'reset votes data' do
|
16
|
+
@post1.votes = nil
|
17
|
+
@post1.save
|
18
|
+
|
19
|
+
@post2.votes = nil
|
20
|
+
@post2.save
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'init_stats recover votes default value' do
|
24
|
+
Mongoid::Voteable::Tasks.init_stats
|
25
|
+
|
26
|
+
@post1.reload
|
27
|
+
@post2.reload
|
28
|
+
|
29
|
+
@post1.votes.should == Mongoid::Voteable::Votes::DEFAULT_ATTRIBUTES
|
30
|
+
@post2.votes.should == Mongoid::Voteable::Votes::DEFAULT_ATTRIBUTES
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -1,17 +1,34 @@
|
|
1
|
-
require
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
2
|
|
3
3
|
describe Mongoid::Voteable do
|
4
4
|
before :all do
|
5
|
+
@category1 = Category.create!(:name => 'xyz')
|
6
|
+
@category2 = Category.create!(:name => 'abc')
|
7
|
+
|
5
8
|
@post1 = Post.create!
|
6
9
|
@post2 = Post.create!
|
7
10
|
|
11
|
+
@post1.categories << @category1
|
12
|
+
@category2.posts << @post1
|
13
|
+
|
8
14
|
@comment = @post2.comments.create!
|
15
|
+
|
9
16
|
@user1 = User.create!
|
10
17
|
@user2 = User.create!
|
11
18
|
end
|
12
19
|
|
13
20
|
context "just created" do
|
14
|
-
it '
|
21
|
+
it 'votes_count, up_votes_count, down_votes_count, votes_point should be zero' do
|
22
|
+
@category1.up_votes_count.should == 0
|
23
|
+
@category1.down_votes_count.should == 0
|
24
|
+
@category1.votes_count.should == 0
|
25
|
+
@category1.votes_point.should == 0
|
26
|
+
|
27
|
+
@category2.up_votes_count.should == 0
|
28
|
+
@category2.down_votes_count.should == 0
|
29
|
+
@category2.votes_count.should == 0
|
30
|
+
@category2.votes_point.should == 0
|
31
|
+
|
15
32
|
@post1.up_votes_count.should == 0
|
16
33
|
@post1.down_votes_count.should == 0
|
17
34
|
@post1.votes_count.should == 0
|
@@ -21,49 +38,51 @@ describe Mongoid::Voteable do
|
|
21
38
|
@post2.down_votes_count.should == 0
|
22
39
|
@post2.votes_count.should == 0
|
23
40
|
@post2.votes_point.should == 0
|
41
|
+
|
42
|
+
@comment.up_votes_count.should == 0
|
43
|
+
@comment.down_votes_count.should == 0
|
44
|
+
@comment.votes_count.should == 0
|
45
|
+
@comment.votes_point.should == 0
|
24
46
|
end
|
25
47
|
|
26
|
-
it '
|
48
|
+
it 'up_voter_ids, down_voter_ids should be empty' do
|
49
|
+
@category1.up_voter_ids.should be_empty
|
50
|
+
@category1.down_voter_ids.should be_empty
|
51
|
+
|
52
|
+
@category2.up_voter_ids.should be_empty
|
53
|
+
@category2.down_voter_ids.should be_empty
|
54
|
+
|
27
55
|
@post1.up_voter_ids.should be_empty
|
28
56
|
@post1.down_voter_ids.should be_empty
|
29
57
|
|
30
58
|
@post2.up_voter_ids.should be_empty
|
31
59
|
@post2.down_voter_ids.should be_empty
|
60
|
+
|
61
|
+
@comment.up_voter_ids.should be_empty
|
62
|
+
@comment.down_voter_ids.should be_empty
|
32
63
|
end
|
33
64
|
|
34
|
-
it '
|
65
|
+
it 'voted by voter should be empty' do
|
66
|
+
Category.voted_by(@user1).should be_empty
|
67
|
+
Category.voted_by(@user2).should be_empty
|
68
|
+
|
35
69
|
Post.voted_by(@user1).should be_empty
|
36
70
|
Post.voted_by(@user2).should be_empty
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'test init stats' do
|
40
|
-
@post1.votes.should == Mongoid::Voteable::Votes::DEFAULT_ATTRIBUTES
|
41
|
-
@post2.votes.should == Mongoid::Voteable::Votes::DEFAULT_ATTRIBUTES
|
42
|
-
|
43
|
-
@post1.votes = nil
|
44
|
-
@post1.save
|
45
|
-
|
46
|
-
@post2.votes = nil
|
47
|
-
@post2.save
|
48
71
|
|
49
|
-
|
50
|
-
|
51
|
-
@post1.reload
|
52
|
-
@post2.reload
|
53
|
-
|
54
|
-
@post1.votes.should == Mongoid::Voteable::Votes::DEFAULT_ATTRIBUTES
|
55
|
-
@post2.votes.should == Mongoid::Voteable::Votes::DEFAULT_ATTRIBUTES
|
72
|
+
Comment.voted_by(@user1).should be_empty
|
73
|
+
Comment.voted_by(@user2).should be_empty
|
56
74
|
end
|
57
|
-
|
58
|
-
it 'revote has no effect' do
|
75
|
+
|
76
|
+
it 'revote post1 has no effect' do
|
59
77
|
@post1.vote(:revote => true, :voter => @user1, :value => 'up')
|
60
|
-
@post1.reload
|
61
78
|
|
62
79
|
@post1.up_votes_count.should == 0
|
63
80
|
@post1.down_votes_count.should == 0
|
64
81
|
@post1.votes_count.should == 0
|
65
82
|
@post1.votes_point.should == 0
|
66
|
-
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'revote post2 has no effect' do
|
67
86
|
Post.vote(:revote => true, :votee_id => @post2.id, :voter_id => @user2.id, :value => :down)
|
68
87
|
@post2.reload
|
69
88
|
|
@@ -76,10 +95,24 @@ describe Mongoid::Voteable do
|
|
76
95
|
|
77
96
|
context 'user1 vote up post1 the first time' do
|
78
97
|
before :all do
|
79
|
-
|
98
|
+
@return = @post1.vote(:voter_id => @user1.id, :value => :up, :return_votee => true)
|
80
99
|
end
|
81
100
|
|
82
|
-
it '' do
|
101
|
+
it 'validates return post' do
|
102
|
+
@return.votes.should == {
|
103
|
+
'up' => [@user1.id],
|
104
|
+
'down' => [],
|
105
|
+
'up_count' => 1,
|
106
|
+
'down_count' => 0,
|
107
|
+
'count' => 1,
|
108
|
+
'point' => 1
|
109
|
+
}
|
110
|
+
|
111
|
+
@return.should_not be_new_record
|
112
|
+
@return.should be_is_a(Post)
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'validates' do
|
83
116
|
@post1.up_votes_count.should == 1
|
84
117
|
@post1.down_votes_count.should == 0
|
85
118
|
@post1.votes_count.should == 1
|
@@ -92,6 +125,18 @@ describe Mongoid::Voteable do
|
|
92
125
|
|
93
126
|
Post.voted_by(@user1).to_a.should == [ @post1 ]
|
94
127
|
Post.voted_by(@user2).to_a.should be_empty
|
128
|
+
|
129
|
+
@category1.reload
|
130
|
+
@category1.up_votes_count.should == 0
|
131
|
+
@category1.down_votes_count.should == 0
|
132
|
+
@category1.votes_count.should == 0
|
133
|
+
@category1.votes_point.should == 3
|
134
|
+
|
135
|
+
@category2.reload
|
136
|
+
@category2.up_votes_count.should == 0
|
137
|
+
@category2.down_votes_count.should == 0
|
138
|
+
@category2.votes_count.should == 0
|
139
|
+
@category2.votes_point.should == 3
|
95
140
|
end
|
96
141
|
|
97
142
|
it 'user1 vote post1 has no effect' do
|
@@ -113,18 +158,39 @@ describe Mongoid::Voteable do
|
|
113
158
|
@post1.reload
|
114
159
|
end
|
115
160
|
|
116
|
-
it '' do
|
161
|
+
it 'post1 up_votes_count is the same' do
|
117
162
|
@post1.up_votes_count.should == 1
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'post1 vote_value on user1 is the same' do
|
166
|
+
@post1.vote_value(@user1.id).should == :up
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'down_votes_count, votes_count, and votes_point changed' do
|
118
170
|
@post1.down_votes_count.should == 1
|
119
171
|
@post1.votes_count.should == 2
|
120
172
|
@post1.votes_point.should == 0
|
121
|
-
|
122
|
-
@post1.vote_value(@user1.id).should == :up
|
123
173
|
@post1.vote_value(@user2.id).should == :down
|
124
|
-
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'posts voted_by user1, user2 is post1 only' do
|
125
177
|
Post.voted_by(@user1).to_a.should == [ @post1 ]
|
126
178
|
Post.voted_by(@user2).to_a.should == [ @post1 ]
|
127
179
|
end
|
180
|
+
|
181
|
+
it 'categories votes' do
|
182
|
+
@category1.reload
|
183
|
+
@category1.up_votes_count.should == 0
|
184
|
+
@category1.down_votes_count.should == 0
|
185
|
+
@category1.votes_count.should == 0
|
186
|
+
@category1.votes_point.should == -2
|
187
|
+
|
188
|
+
@category2.reload
|
189
|
+
@category2.up_votes_count.should == 0
|
190
|
+
@category2.down_votes_count.should == 0
|
191
|
+
@category2.votes_count.should == 0
|
192
|
+
@category2.votes_point.should == -2
|
193
|
+
end
|
128
194
|
end
|
129
195
|
|
130
196
|
context 'user1 change vote on post1 from up to down' do
|
@@ -134,7 +200,7 @@ describe Mongoid::Voteable do
|
|
134
200
|
@post1.reload
|
135
201
|
end
|
136
202
|
|
137
|
-
it '' do
|
203
|
+
it 'validates' do
|
138
204
|
@post1.up_votes_count.should == 0
|
139
205
|
@post1.down_votes_count.should == 2
|
140
206
|
@post1.votes_count.should == 2
|
@@ -153,7 +219,7 @@ describe Mongoid::Voteable do
|
|
153
219
|
@post2.vote(:voter_id => @user1.id, :value => :down)
|
154
220
|
end
|
155
221
|
|
156
|
-
it '' do
|
222
|
+
it 'validates' do
|
157
223
|
@post2.up_votes_count.should == 0
|
158
224
|
@post2.down_votes_count.should == 1
|
159
225
|
@post2.votes_count.should == 1
|
@@ -173,7 +239,7 @@ describe Mongoid::Voteable do
|
|
173
239
|
@post2.reload
|
174
240
|
end
|
175
241
|
|
176
|
-
it '' do
|
242
|
+
it 'validates' do
|
177
243
|
@post2.up_votes_count.should == 1
|
178
244
|
@post2.down_votes_count.should == 0
|
179
245
|
@post2.votes_count.should == 1
|
@@ -194,7 +260,7 @@ describe Mongoid::Voteable do
|
|
194
260
|
@post2.reload
|
195
261
|
end
|
196
262
|
|
197
|
-
it '' do
|
263
|
+
it 'validates' do
|
198
264
|
@post2.up_votes_count.should == 2
|
199
265
|
@post2.down_votes_count.should == 0
|
200
266
|
@post2.votes_count.should == 2
|
@@ -215,7 +281,7 @@ describe Mongoid::Voteable do
|
|
215
281
|
@post2.reload
|
216
282
|
end
|
217
283
|
|
218
|
-
it '' do
|
284
|
+
it 'validates' do
|
219
285
|
@post2.up_votes_count.should == 1
|
220
286
|
@post2.down_votes_count.should == 1
|
221
287
|
@post2.votes_count.should == 2
|
@@ -249,7 +315,7 @@ describe Mongoid::Voteable do
|
|
249
315
|
@post1.reload
|
250
316
|
end
|
251
317
|
|
252
|
-
it
|
318
|
+
it 'validates' do
|
253
319
|
@post1.up_votes_count.should == 0
|
254
320
|
@post1.down_votes_count.should == 1
|
255
321
|
@post1.votes_count.should == 1
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
2
|
|
3
3
|
describe Mongoid::Voter do
|
4
4
|
before :all do
|
@@ -10,7 +10,7 @@ describe Mongoid::Voter do
|
|
10
10
|
end
|
11
11
|
|
12
12
|
context "just created" do
|
13
|
-
it '' do
|
13
|
+
it 'validates' do
|
14
14
|
Post.voted_by(@user1).should be_empty
|
15
15
|
Post.up_voted_by(@user1).should be_empty
|
16
16
|
Post.down_voted_by(@user1).should be_empty
|
@@ -39,7 +39,7 @@ describe Mongoid::Voter do
|
|
39
39
|
@post1.reload
|
40
40
|
end
|
41
41
|
|
42
|
-
it '' do
|
42
|
+
it 'validates' do
|
43
43
|
@post1.votes_count.should == 1
|
44
44
|
@post1.votes_point.should == 1
|
45
45
|
|
@@ -72,7 +72,7 @@ describe Mongoid::Voter do
|
|
72
72
|
@post1.reload
|
73
73
|
end
|
74
74
|
|
75
|
-
it '' do
|
75
|
+
it 'validates' do
|
76
76
|
@post1.votes_count.should == 2
|
77
77
|
@post1.votes_point.should == 0
|
78
78
|
|
@@ -92,7 +92,7 @@ describe Mongoid::Voter do
|
|
92
92
|
@post1.reload
|
93
93
|
end
|
94
94
|
|
95
|
-
it '' do
|
95
|
+
it 'validates' do
|
96
96
|
@post1.votes_count.should == 2
|
97
97
|
@post1.votes_point.should == -2
|
98
98
|
|
@@ -110,7 +110,7 @@ describe Mongoid::Voter do
|
|
110
110
|
@post2.reload
|
111
111
|
end
|
112
112
|
|
113
|
-
it '' do
|
113
|
+
it 'validates' do
|
114
114
|
@post2.votes_count.should == 1
|
115
115
|
@post2.votes_point.should == -1
|
116
116
|
|
@@ -127,7 +127,7 @@ describe Mongoid::Voter do
|
|
127
127
|
@post2.reload
|
128
128
|
end
|
129
129
|
|
130
|
-
it '' do
|
130
|
+
it 'validates' do
|
131
131
|
@post2.votes_count.should == 1
|
132
132
|
@post2.votes_point.should == 1
|
133
133
|
|
data/voteable_mongoid.gemspec
CHANGED
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: voteable_mongoid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.7.
|
5
|
+
version: 0.7.3
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Alex Nguyen
|
@@ -10,8 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-04-
|
14
|
-
default_executable:
|
13
|
+
date: 2011-04-24 00:00:00 Z
|
15
14
|
dependencies:
|
16
15
|
- !ruby/object:Gem::Dependency
|
17
16
|
name: mongoid
|
@@ -35,6 +34,17 @@ dependencies:
|
|
35
34
|
version: "0"
|
36
35
|
type: :development
|
37
36
|
version_requirements: *id002
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: bson_ext
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
type: :development
|
47
|
+
version_requirements: *id003
|
38
48
|
description: Add Up / Down Voting for Mongoid (built for speed by using one Mongodb update-in-place for each collection when provided enough information)
|
39
49
|
email:
|
40
50
|
- alex@vinova.sg
|
@@ -46,6 +56,7 @@ extra_rdoc_files: []
|
|
46
56
|
|
47
57
|
files:
|
48
58
|
- .gitignore
|
59
|
+
- .rvmrc
|
49
60
|
- .watchr
|
50
61
|
- CHANGELOG.rdoc
|
51
62
|
- Gemfile
|
@@ -62,14 +73,15 @@ files:
|
|
62
73
|
- lib/voteable_mongoid/voteable/voting.rb
|
63
74
|
- lib/voteable_mongoid/voter.rb
|
64
75
|
- spec/.rspec
|
76
|
+
- spec/models/category.rb
|
65
77
|
- spec/models/comment.rb
|
66
78
|
- spec/models/post.rb
|
67
79
|
- spec/models/user.rb
|
68
80
|
- spec/spec_helper.rb
|
81
|
+
- spec/voteable_mongoid/tasks_spec.rb
|
69
82
|
- spec/voteable_mongoid/voteable_spec.rb
|
70
83
|
- spec/voteable_mongoid/voter_spec.rb
|
71
84
|
- voteable_mongoid.gemspec
|
72
|
-
has_rdoc: true
|
73
85
|
homepage: https://github.com/vinova/voteable_mongoid
|
74
86
|
licenses: []
|
75
87
|
|
@@ -93,14 +105,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
93
105
|
requirements: []
|
94
106
|
|
95
107
|
rubyforge_project: voteable_mongoid
|
96
|
-
rubygems_version: 1.
|
108
|
+
rubygems_version: 1.7.2
|
97
109
|
signing_key:
|
98
110
|
specification_version: 3
|
99
111
|
summary: Add Up / Down Voting for Mongoid
|
100
112
|
test_files:
|
113
|
+
- spec/models/category.rb
|
101
114
|
- spec/models/comment.rb
|
102
115
|
- spec/models/post.rb
|
103
116
|
- spec/models/user.rb
|
104
117
|
- spec/spec_helper.rb
|
118
|
+
- spec/voteable_mongoid/tasks_spec.rb
|
105
119
|
- spec/voteable_mongoid/voteable_spec.rb
|
106
120
|
- spec/voteable_mongoid/voter_spec.rb
|