voteable_mongoid 0.7.2 → 0.7.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|