rs_voteable_mongo 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.watchr +23 -0
- data/CHANGELOG.rdoc +87 -0
- data/Gemfile +4 -0
- data/README.rdoc +212 -0
- data/Rakefile +10 -0
- data/TODO +17 -0
- data/lib/rs_votable_mongo.rb +1 -0
- data/lib/voteable_mongo/helpers.rb +18 -0
- data/lib/voteable_mongo/integrations/mongoid.rb +31 -0
- data/lib/voteable_mongo/railtie.rb +19 -0
- data/lib/voteable_mongo/railties/database.rake +18 -0
- data/lib/voteable_mongo/tasks.rb +152 -0
- data/lib/voteable_mongo/version.rb +3 -0
- data/lib/voteable_mongo/voteable.rb +203 -0
- data/lib/voteable_mongo/voter.rb +91 -0
- data/lib/voteable_mongo/voting.rb +214 -0
- data/lib/voteable_mongo.rb +8 -0
- data/spec/.rspec +1 -0
- data/spec/mongoid/models/category.rb +10 -0
- data/spec/mongoid/models/comment.rb +13 -0
- data/spec/mongoid/models/post.rb +17 -0
- data/spec/mongoid/models/user.rb +4 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/voteable_mongo/tasks_spec.rb +34 -0
- data/spec/voteable_mongo/voteable_spec.rb +436 -0
- data/spec/voteable_mongo/voter_spec.rb +150 -0
- data/voteable_mongo.gemspec +24 -0
- metadata +118 -0
@@ -0,0 +1,203 @@
|
|
1
|
+
require 'voteable_mongo/voting'
|
2
|
+
require 'voteable_mongo/integrations/mongoid'
|
3
|
+
|
4
|
+
module Mongo
|
5
|
+
module Voteable
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
DEFAULT_VOTES = {
|
9
|
+
'up' => [],
|
10
|
+
'down' => [],
|
11
|
+
'up_count' => 0,
|
12
|
+
'down_count' => 0,
|
13
|
+
'count' => 0,
|
14
|
+
'point' => 0
|
15
|
+
}
|
16
|
+
|
17
|
+
included do
|
18
|
+
include Mongo::Voteable::Voting
|
19
|
+
|
20
|
+
if defined?(Mongoid) && defined?(field)
|
21
|
+
include Mongo::Voteable::Integrations::Mongoid
|
22
|
+
elsif defined?(MongoMapper)
|
23
|
+
include Mongo::Voteable::Integrations::MongoMapper
|
24
|
+
end
|
25
|
+
|
26
|
+
scope :voted_by, lambda { |voter|
|
27
|
+
voter_id = Helpers.get_mongo_id(voter)
|
28
|
+
where('$or' => [{ 'votes.up' => voter_id }, { 'votes.down' => voter_id }])
|
29
|
+
}
|
30
|
+
|
31
|
+
scope :up_voted_by, lambda { |voter|
|
32
|
+
voter_id = Helpers.get_mongo_id(voter)
|
33
|
+
where('votes.up' => voter_id)
|
34
|
+
}
|
35
|
+
|
36
|
+
scope :down_voted_by, lambda { |voter|
|
37
|
+
voter_id = Helpers.get_mongo_id(voter)
|
38
|
+
where('votes.down' => voter_id)
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
# How many points should be assigned for each up or down vote and other options
|
43
|
+
# This hash should manipulated using voteable method
|
44
|
+
VOTEABLE = {}
|
45
|
+
|
46
|
+
module ClassMethods
|
47
|
+
# Set vote point for each up (down) vote on an object of this class
|
48
|
+
#
|
49
|
+
# @param [Hash] options a hash containings:
|
50
|
+
#
|
51
|
+
# voteable self, :up => +1, :down => -3
|
52
|
+
# voteable Post, :up => +2, :down => -1, :update_counters => false # skip counter update
|
53
|
+
def voteable(klass = self, options = nil)
|
54
|
+
VOTEABLE[name] ||= {}
|
55
|
+
VOTEABLE[name][klass.name] ||= options
|
56
|
+
if klass == self
|
57
|
+
if options[:index] == true
|
58
|
+
create_voteable_indexes
|
59
|
+
end
|
60
|
+
else
|
61
|
+
VOTEABLE[name][name][:update_parents] ||= true
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Check if voter_id do a vote on votee_id
|
66
|
+
#
|
67
|
+
# @param [Hash] options a hash containings:
|
68
|
+
# - :votee_id: the votee document id
|
69
|
+
# - :voter_id: the voter document id
|
70
|
+
#
|
71
|
+
# @return [true, false]
|
72
|
+
def voted?(options)
|
73
|
+
validate_and_normalize_vote_options(options)
|
74
|
+
up_voted?(options) || down_voted?(options)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Check if voter_id do an up vote on votee_id
|
78
|
+
#
|
79
|
+
# @param [Hash] options a hash containings:
|
80
|
+
# - :votee_id: the votee document id
|
81
|
+
# - :voter_id: the voter document id
|
82
|
+
#
|
83
|
+
# @return [true, false]
|
84
|
+
def up_voted?(options)
|
85
|
+
validate_and_normalize_vote_options(options)
|
86
|
+
up_voted_by(options[:voter_id]).where(:_id => options[:votee_id]).count == 1
|
87
|
+
end
|
88
|
+
|
89
|
+
# Check if voter_id do a down vote on votee_id
|
90
|
+
#
|
91
|
+
# @param [Hash] options a hash containings:
|
92
|
+
# - :votee_id: the votee document id
|
93
|
+
# - :voter_id: the voter document id
|
94
|
+
#
|
95
|
+
# @return [true, false]
|
96
|
+
def down_voted?(options)
|
97
|
+
validate_and_normalize_vote_options(options)
|
98
|
+
down_voted_by(options[:voter_id]).where(:_id => options[:votee_id]).count == 1
|
99
|
+
end
|
100
|
+
|
101
|
+
def create_voteable_indexes
|
102
|
+
# Compound index _id and voters.up, _id and voters.down
|
103
|
+
# to make up_voted_by, down_voted_by, voted_by scopes and voting faster
|
104
|
+
# Should run in background since it introduce new index value and
|
105
|
+
# while waiting to build, the system can use _id for voting
|
106
|
+
# http://www.mongodb.org/display/DOCS/Indexing+as+a+Background+Operation
|
107
|
+
voteable_index({'votes.up' => 1, '_id' => 1}, {unique: true})
|
108
|
+
voteable_index({'votes.down' => 1, '_id' => 1}, {unique: true})
|
109
|
+
|
110
|
+
# Index counters and point for desc ordering
|
111
|
+
voteable_index({'votes.up_count' => -1})
|
112
|
+
voteable_index({'votes.down_count' => -1})
|
113
|
+
voteable_index({'votes.count' => -1})
|
114
|
+
voteable_index({'votes.point' => -1})
|
115
|
+
create_indexes
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Make a vote on this votee
|
120
|
+
#
|
121
|
+
# @param [Hash] options a hash containings:
|
122
|
+
# - :voter_id: the voter document id
|
123
|
+
# - :value: vote :up or vote :down
|
124
|
+
# - :revote: change from vote up to vote down
|
125
|
+
# - :unvote: unvote the vote value (:up or :down)
|
126
|
+
def vote(options)
|
127
|
+
options[:votee_id] = id
|
128
|
+
options[:votee] = self
|
129
|
+
options[:voter_id] ||= options[:voter].id
|
130
|
+
|
131
|
+
if options[:unvote]
|
132
|
+
options[:value] ||= vote_value(options[:voter_id])
|
133
|
+
else
|
134
|
+
options[:revote] ||= vote_value(options[:voter_id]).present?
|
135
|
+
end
|
136
|
+
|
137
|
+
self.class.vote(options)
|
138
|
+
end
|
139
|
+
|
140
|
+
# Get a voted value on this votee
|
141
|
+
#
|
142
|
+
# @param voter is object or the id of the voter who made the vote
|
143
|
+
def vote_value(voter)
|
144
|
+
voter_id = Helpers.get_mongo_id(voter)
|
145
|
+
return :up if up_voter_ids.include?(voter_id)
|
146
|
+
return :down if down_voter_ids.include?(voter_id)
|
147
|
+
end
|
148
|
+
|
149
|
+
def voted_by?(voter)
|
150
|
+
!!vote_value(voter)
|
151
|
+
end
|
152
|
+
|
153
|
+
# Array of up voter ids
|
154
|
+
def up_voter_ids
|
155
|
+
votes.try(:[], 'up') || []
|
156
|
+
end
|
157
|
+
|
158
|
+
# Array of down voter ids
|
159
|
+
def down_voter_ids
|
160
|
+
votes.try(:[], 'down') || []
|
161
|
+
end
|
162
|
+
|
163
|
+
# Array of voter ids
|
164
|
+
def voter_ids
|
165
|
+
up_voter_ids + down_voter_ids
|
166
|
+
end
|
167
|
+
|
168
|
+
# Get the number of up votes
|
169
|
+
def up_votes_count
|
170
|
+
votes.try(:[], 'up_count') || 0
|
171
|
+
end
|
172
|
+
|
173
|
+
# Get the number of down votes
|
174
|
+
def down_votes_count
|
175
|
+
votes.try(:[], 'down_count') || 0
|
176
|
+
end
|
177
|
+
|
178
|
+
# Get the number of votes
|
179
|
+
def votes_count
|
180
|
+
votes.try(:[], 'count') || 0
|
181
|
+
end
|
182
|
+
|
183
|
+
# Get the votes point
|
184
|
+
def votes_point
|
185
|
+
votes.try(:[], 'point') || 0
|
186
|
+
end
|
187
|
+
|
188
|
+
# Get up voters
|
189
|
+
def up_voters(klass)
|
190
|
+
klass.where(:_id => { '$in' => up_voter_ids })
|
191
|
+
end
|
192
|
+
|
193
|
+
# Get down voters
|
194
|
+
def down_voters(klass)
|
195
|
+
klass.where(:_id => { '$in' => down_voter_ids })
|
196
|
+
end
|
197
|
+
|
198
|
+
# Get voters
|
199
|
+
def voters(klass)
|
200
|
+
klass.where(:_id => { '$in' => voter_ids })
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Mongo
|
2
|
+
module Voter
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
scope :up_voted_for, lambda { |votee| where(:_id => { '$in' => votee.up_voter_ids }) }
|
7
|
+
scope :down_voted_for, lambda { |votee| where(:_id => { '$in' => votee.down_voter_ids }) }
|
8
|
+
scope :voted_for, lambda { |votee| where(:_id => { '$in' => votee.voter_ids }) }
|
9
|
+
end
|
10
|
+
|
11
|
+
# Check to see if this voter voted on the votee or not
|
12
|
+
#
|
13
|
+
# @param [Hash, Object] options the hash containing the votee, or the votee itself
|
14
|
+
# @return [true, false] true if voted, false otherwise
|
15
|
+
def voted?(options)
|
16
|
+
unless options.is_a?(Hash)
|
17
|
+
votee_class = options.class
|
18
|
+
votee_id = options.id
|
19
|
+
else
|
20
|
+
votee = options[:votee]
|
21
|
+
if votee
|
22
|
+
votee_class = votee.class
|
23
|
+
votee_id = votee.id
|
24
|
+
else
|
25
|
+
votee_class = options[:votee_class]
|
26
|
+
votee_id = options[:votee_id]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
votee_class.voted?(:voter_id => id, :votee_id => votee_id)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Get the voted value on a votee
|
34
|
+
#
|
35
|
+
# @param (see #voted?)
|
36
|
+
# @return [Symbol, nil] :up or :down or nil if not voted
|
37
|
+
def vote_value(options)
|
38
|
+
votee = unless options.is_a?(Hash)
|
39
|
+
options
|
40
|
+
else
|
41
|
+
options[:votee] || options[:votee_class].find(options[:votee_id])
|
42
|
+
end
|
43
|
+
votee.vote_value(_id)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Cancel the vote on a votee
|
47
|
+
#
|
48
|
+
# @param [Object] votee the votee to be unvoted
|
49
|
+
def unvote(options)
|
50
|
+
unless options.is_a?(Hash)
|
51
|
+
options = { :votee => options }
|
52
|
+
end
|
53
|
+
options[:unvote] = true
|
54
|
+
options[:revote] = false
|
55
|
+
vote(options)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Vote on a votee
|
59
|
+
#
|
60
|
+
# @param (see #voted?)
|
61
|
+
# @param [:up, :down] vote_value vote up or vote down, nil to unvote
|
62
|
+
def vote(options, value = nil)
|
63
|
+
if options.is_a?(Hash)
|
64
|
+
votee = options[:votee]
|
65
|
+
else
|
66
|
+
votee = options
|
67
|
+
options = { :votee => votee, :value => value }
|
68
|
+
end
|
69
|
+
|
70
|
+
if votee
|
71
|
+
options[:votee_id] = votee.id
|
72
|
+
votee_class = votee.class
|
73
|
+
else
|
74
|
+
votee_class = options[:votee_class]
|
75
|
+
end
|
76
|
+
|
77
|
+
if options[:value].nil?
|
78
|
+
options[:unvote] = true
|
79
|
+
options[:value] = vote_value(options)
|
80
|
+
else
|
81
|
+
options[:revote] = options.has_key?(:revote) ? !options[:revote].blank? : voted?(options)
|
82
|
+
end
|
83
|
+
|
84
|
+
options[:voter] = self
|
85
|
+
options[:voter_id] = id
|
86
|
+
|
87
|
+
(votee || votee_class).vote(options)
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,214 @@
|
|
1
|
+
module Mongo
|
2
|
+
module Voteable
|
3
|
+
module Voting
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
# Make a vote on an object of this class
|
8
|
+
#
|
9
|
+
# @param [Hash] options a hash containings:
|
10
|
+
# - :votee_id: the votee document id
|
11
|
+
# - :voter_id: the voter document id
|
12
|
+
# - :value: :up or :down
|
13
|
+
# - :revote: if true change vote vote from :up to :down and vise versa
|
14
|
+
# - :unvote: if true undo the voting
|
15
|
+
#
|
16
|
+
# @return [votee, false]
|
17
|
+
def vote(options)
|
18
|
+
validate_and_normalize_vote_options(options)
|
19
|
+
options[:voteable] = VOTEABLE[name][name]
|
20
|
+
|
21
|
+
if options[:voteable]
|
22
|
+
query, update = if options[:revote]
|
23
|
+
revote_query_and_update(options)
|
24
|
+
elsif options[:unvote]
|
25
|
+
unvote_query_and_update(options)
|
26
|
+
else
|
27
|
+
new_vote_query_and_update(options)
|
28
|
+
end
|
29
|
+
|
30
|
+
# http://www.mongodb.org/display/DOCS/findAndModify+Command
|
31
|
+
begin
|
32
|
+
doc = where(query).find_and_modify(
|
33
|
+
update,
|
34
|
+
:new => true
|
35
|
+
)
|
36
|
+
rescue Moped::Errors::OperationFailure
|
37
|
+
doc = nil
|
38
|
+
end
|
39
|
+
|
40
|
+
if doc
|
41
|
+
update_parent_votes(doc, options) if options[:voteable][:update_parents]
|
42
|
+
# Update new votes data
|
43
|
+
options[:votee].write_attribute('votes', doc['votes']) if options[:votee]
|
44
|
+
options[:votee] || new(doc.as_document)
|
45
|
+
else
|
46
|
+
false
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
private
|
53
|
+
def validate_and_normalize_vote_options(options)
|
54
|
+
options.symbolize_keys!
|
55
|
+
options[:votee_id] = Helpers.try_to_convert_string_to_object_id(options[:votee_id])
|
56
|
+
options[:voter_id] = Helpers.try_to_convert_string_to_object_id(options[:voter_id])
|
57
|
+
options[:value] &&= options[:value].to_sym
|
58
|
+
end
|
59
|
+
|
60
|
+
def new_vote_query_and_update(options)
|
61
|
+
if options[:value] == :up
|
62
|
+
positive_voter_ids = 'votes.up'
|
63
|
+
positive_votes_count = 'votes.up_count'
|
64
|
+
else
|
65
|
+
positive_voter_ids = 'votes.down'
|
66
|
+
positive_votes_count = 'votes.down_count'
|
67
|
+
end
|
68
|
+
|
69
|
+
return {
|
70
|
+
# Validate voter_id did not vote for votee_id yet
|
71
|
+
:_id => options[:votee_id],
|
72
|
+
'votes.up' => { '$ne' => options[:voter_id] },
|
73
|
+
'votes.down' => { '$ne' => options[:voter_id] }
|
74
|
+
}, {
|
75
|
+
# then update
|
76
|
+
'$push' => { positive_voter_ids => options[:voter_id] },
|
77
|
+
'$inc' => {
|
78
|
+
'votes.count' => +1,
|
79
|
+
positive_votes_count => +1,
|
80
|
+
'votes.point' => options[:voteable][options[:value]]
|
81
|
+
}
|
82
|
+
}
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
def revote_query_and_update(options)
|
87
|
+
if options[:value] == :up
|
88
|
+
positive_voter_ids = 'votes.up'
|
89
|
+
negative_voter_ids = 'votes.down'
|
90
|
+
positive_votes_count = 'votes.up_count'
|
91
|
+
negative_votes_count = 'votes.down_count'
|
92
|
+
point_delta = options[:voteable][:up] - options[:voteable][:down]
|
93
|
+
else
|
94
|
+
positive_voter_ids = 'votes.down'
|
95
|
+
negative_voter_ids = 'votes.up'
|
96
|
+
positive_votes_count = 'votes.down_count'
|
97
|
+
negative_votes_count = 'votes.up_count'
|
98
|
+
point_delta = -options[:voteable][:up] + options[:voteable][:down]
|
99
|
+
end
|
100
|
+
|
101
|
+
return {
|
102
|
+
# Validate voter_id did a vote with value for votee_id
|
103
|
+
:_id => options[:votee_id],
|
104
|
+
# Can skip $ne validation since creating a new vote
|
105
|
+
# already warranty that a voter can vote one only
|
106
|
+
# positive_voter_ids => { '$ne' => options[:voter_id] },
|
107
|
+
negative_voter_ids => options[:voter_id]
|
108
|
+
}, {
|
109
|
+
# then update
|
110
|
+
'$pull' => { negative_voter_ids => options[:voter_id] },
|
111
|
+
'$push' => { positive_voter_ids => options[:voter_id] },
|
112
|
+
'$inc' => {
|
113
|
+
positive_votes_count => +1,
|
114
|
+
negative_votes_count => -1,
|
115
|
+
'votes.point' => point_delta
|
116
|
+
}
|
117
|
+
}
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
def unvote_query_and_update(options)
|
122
|
+
if options[:value] == :up
|
123
|
+
positive_voter_ids = 'votes.up'
|
124
|
+
negative_voter_ids = 'votes.down'
|
125
|
+
positive_votes_count = 'votes.up_count'
|
126
|
+
else
|
127
|
+
positive_voter_ids = 'votes.down'
|
128
|
+
negative_voter_ids = 'votes.up'
|
129
|
+
positive_votes_count = 'votes.down_count'
|
130
|
+
end
|
131
|
+
|
132
|
+
return {
|
133
|
+
:_id => options[:votee_id],
|
134
|
+
# Validate if voter_id did a vote with value for votee_id
|
135
|
+
# Can skip $ne validation since creating a new vote
|
136
|
+
# already warranty that a voter can vote one only
|
137
|
+
# negative_voter_ids => { '$ne' => options[:voter_id] },
|
138
|
+
positive_voter_ids => options[:voter_id]
|
139
|
+
}, {
|
140
|
+
# then update
|
141
|
+
'$pull' => { positive_voter_ids => options[:voter_id] },
|
142
|
+
'$inc' => {
|
143
|
+
positive_votes_count => -1,
|
144
|
+
'votes.count' => -1,
|
145
|
+
'votes.point' => - options[:voteable][options[:value]]
|
146
|
+
}
|
147
|
+
}
|
148
|
+
end
|
149
|
+
|
150
|
+
|
151
|
+
def update_parent_votes(doc, options)
|
152
|
+
VOTEABLE[name].each do |class_name, voteable|
|
153
|
+
|
154
|
+
if metadata = voteable_relation(class_name)
|
155
|
+
|
156
|
+
if (parent_id = doc[voteable_foreign_key(metadata)]).present?
|
157
|
+
parent_ids = parent_id.is_a?(Array) ? parent_id : [ parent_id ]
|
158
|
+
class_name.constantize.collection.find({'_id' => {'$in' => parent_ids}}).update_all(
|
159
|
+
{ '$inc' => parent_inc_options(voteable, options) },
|
160
|
+
)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
|
167
|
+
def parent_inc_options(voteable, options)
|
168
|
+
inc_options = {}
|
169
|
+
|
170
|
+
if options[:revote]
|
171
|
+
if options[:value] == :up
|
172
|
+
inc_options['votes.point'] = voteable[:up] - voteable[:down]
|
173
|
+
unless voteable[:update_counters] == false
|
174
|
+
inc_options['votes.up_count'] = +1
|
175
|
+
inc_options['votes.down_count'] = -1
|
176
|
+
end
|
177
|
+
else
|
178
|
+
inc_options['votes.point'] = -voteable[:up] + voteable[:down]
|
179
|
+
unless voteable[:update_counters] == false
|
180
|
+
inc_options['votes.up_count'] = -1
|
181
|
+
inc_options['votes.down_count'] = +1
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
elsif options[:unvote]
|
186
|
+
inc_options['votes.point'] = -voteable[options[:value]]
|
187
|
+
unless voteable[:update_counters] == false
|
188
|
+
inc_options['votes.count'] = -1
|
189
|
+
if options[:value] == :up
|
190
|
+
inc_options['votes.up_count'] = -1
|
191
|
+
else
|
192
|
+
inc_options['votes.down_count'] = -1
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
else # new vote
|
197
|
+
inc_options['votes.point'] = voteable[options[:value]]
|
198
|
+
unless voteable[:update_counters] == false
|
199
|
+
inc_options['votes.count'] = +1
|
200
|
+
if options[:value] == :up
|
201
|
+
inc_options['votes.up_count'] = +1
|
202
|
+
else
|
203
|
+
inc_options['votes.down_count'] = +1
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
inc_options
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
data/spec/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color --debugger
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'category')
|
2
|
+
|
3
|
+
class Post
|
4
|
+
include Mongoid::Document
|
5
|
+
include Mongo::Voteable
|
6
|
+
|
7
|
+
field :title
|
8
|
+
field :content
|
9
|
+
|
10
|
+
has_and_belongs_to_many :categories
|
11
|
+
has_many :comments
|
12
|
+
|
13
|
+
field :_id, type: String, default: -> { title }
|
14
|
+
|
15
|
+
voteable self, :up => +1, :down => -1, :index => true
|
16
|
+
voteable Category, :up => +3, :down => -5, :update_counters => false
|
17
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
Bundler.setup
|
4
|
+
|
5
|
+
require 'mongoid'
|
6
|
+
models_folder = File.join(File.dirname(__FILE__), 'mongoid/models')
|
7
|
+
Mongoid.configure do |config|
|
8
|
+
name = 'voteable_mongo_test'
|
9
|
+
host = 'localhost'
|
10
|
+
config.connect_to(name)
|
11
|
+
end
|
12
|
+
|
13
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
14
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
15
|
+
|
16
|
+
|
17
|
+
require 'voteable_mongo'
|
18
|
+
require 'rspec'
|
19
|
+
require 'rspec/autorun'
|
20
|
+
|
21
|
+
Dir[ File.join(models_folder, '*.rb') ].each { |file|
|
22
|
+
require file
|
23
|
+
file_name = File.basename(file).sub('.rb', '')
|
24
|
+
klass = file_name.classify.constantize
|
25
|
+
begin
|
26
|
+
klass.collection.drop
|
27
|
+
rescue Exception => e
|
28
|
+
print e.message
|
29
|
+
end
|
30
|
+
}
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Mongo::Voteable::Tasks do
|
4
|
+
describe 'Mongo::Voteable::Tasks.init_stats' do
|
5
|
+
before :all do
|
6
|
+
@post1 = Post.create!(:title => 'post1')
|
7
|
+
@post2 = Post.create!(:title => 'post2')
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'after create votes has default value' do
|
11
|
+
@post1.votes.should == ::Mongo::Voteable::DEFAULT_VOTES
|
12
|
+
@post2.votes.should == ::Mongo::Voteable::DEFAULT_VOTES
|
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
|
+
::Mongo::Voteable::Tasks.init_stats
|
25
|
+
::Mongo::Voteable::Tasks.migrate_old_votes
|
26
|
+
|
27
|
+
@post1.reload
|
28
|
+
@post2.reload
|
29
|
+
|
30
|
+
@post1.votes.should == ::Mongo::Voteable::DEFAULT_VOTES
|
31
|
+
@post2.votes.should == ::Mongo::Voteable::DEFAULT_VOTES
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|