Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

anonymous votes

  • Loading branch information...
commit e9f8afae29e6b5e6e1e9f51fb53aab83f556dd80 1 parent c8b2a95
@angelim authored
View
1  .rspec
@@ -0,0 +1 @@
+--color
View
5 .rvmrc
@@ -1,2 +1,3 @@
-rvm_gemset_create_on_use_flag=1
-rvm use 1.9.2@voteable
+# rvm_gemset_create_on_use_flag=1
+# rvm use 1.9.2@voteable
+rvm ruby-head
View
5 TODO
@@ -15,3 +15,8 @@
* Refactor specs
* More test cases for Tasks module
+
+----- angelim
+
+* Allow customizations of votes field name
+* Votes on embedded documents
View
17 lib/voteable_mongo/tasks.rb
@@ -50,12 +50,16 @@ def self.migrate_old_votes_for(klass, voteable)
up_count = up_voter_ids.size
down_count = down_voter_ids.size
+ faceless_up_count = votes['faceless_up_count']
+ faceless_down_count = votes['faceless_down_count']
klass.collection.update({ :_id => doc.id }, {
'$set' => {
'votes' => {
'up' => up_voter_ids,
'down' => down_voter_ids,
+ 'faceless_up_count' => faceless_up_count,
+ 'faceless_down_count' => faceless_down_count,
'up_count' => up_count,
'down_count' => down_count,
'count' => up_count + down_count,
@@ -89,11 +93,16 @@ def self.remake_stats_for_all_voteable_classes(log)
def self.remake_stats_for(doc, voteable)
up_count = doc.up_voter_ids.length
down_count = doc.down_voter_ids.length
+ faceless_up_count = doc.faceless_up_count
+ faceless_down_count = doc.faceless_down_count
+
doc.update_attributes(
'votes' => {
'up' => doc.up_voter_ids,
'down' => doc.down_voter_ids,
'up_count' => up_count,
+ 'faceless_up_count' => faceless_up_count,
+ 'faceless_down_count' => faceless_down_count,
'down_count' => down_count,
'count' => up_count + down_count,
'point' => voteable[:up].to_i*up_count + voteable[:down].to_i*down_count
@@ -125,18 +134,22 @@ def self.update_parent_stats_for(doc, parent_class, foreign_key, voteable)
if parent_id
up_count = doc.up_voter_ids.length
down_count = doc.down_voter_ids.length
+ faceless_up_count = doc.faceless_up_count
+ faceless_down_count = doc.faceless_down_count
return if up_count == 0 && down_count == 0
inc_options = {
- 'votes.point' => voteable[:up].to_i*up_count + voteable[:down].to_i*down_count
+ 'votes.point' => voteable[:up].to_i*(up_count+faceless_up_count) + voteable[:down].to_i*(down_count+faceless_down_count)
}
unless voteable[:update_counters] == false
inc_options.merge!(
'votes.count' => up_count + down_count,
'votes.up_count' => up_count,
- 'votes.down_count' => down_count
+ 'votes.down_count' => down_count,
+ 'votes.faceless_up_count' => faceless_up_count,
+ 'votes.faceless_down_count' => faceless_down_count
)
end
View
12 lib/voteable_mongo/voteable.rb
@@ -9,6 +9,8 @@ module Voteable
DEFAULT_VOTES = {
'up' => [],
'down' => [],
+ 'faceless_up_count' => 0,
+ 'faceless_down_count' => 0,
'up_count' => 0,
'down_count' => 0,
'count' => 0,
@@ -127,7 +129,7 @@ module InstanceMethods
def vote(options)
options[:votee_id] = id
options[:votee] = self
- options[:voter_id] ||= options[:voter].id
+ options[:voter_id] ||= options[:voter].try(:id)
if options[:unvote]
options[:value] ||= vote_value(options[:voter_id])
@@ -170,6 +172,14 @@ def voter_ids
def up_votes_count
votes.try(:[], 'up_count') || 0
end
+
+ def faceless_up_count
+ votes.try(:[], 'faceless_up_count') || 0
+ end
+
+ def faceless_down_count
+ votes.try(:[], 'faceless_down_count') || 0
+ end
# Get the number of down votes
def down_votes_count
View
71 lib/voteable_mongo/voting.rb
@@ -17,39 +17,35 @@ module ClassMethods
def vote(options)
validate_and_normalize_vote_options(options)
options[:voteable] = VOTEABLE[name][name]
-
- if options[:voteable]
- query, update = if options[:revote]
- revote_query_and_update(options)
- elsif options[:unvote]
- unvote_query_and_update(options)
- else
- new_vote_query_and_update(options)
- end
+ return unless options[:voteable]
+ query, update = if options[:revote]
+ revote_query_and_update(options)
+ elsif options[:unvote]
+ unvote_query_and_update(options)
+ else
+ new_vote_query_and_update(options)
+ end
- # http://www.mongodb.org/display/DOCS/findAndModify+Command
- begin
- doc = voteable_collection.find_and_modify(
- :query => query,
- :update => update,
- :new => true
- )
- rescue Mongo::OperationFailure
- doc = nil
- end
+ # http://www.mongodb.org/display/DOCS/findAndModify+Command
+ begin
+ doc = voteable_collection.find_and_modify(
+ :query => query,
+ :update => update,
+ :new => true
+ )
+ rescue Mongo::OperationFailure
+ doc = nil
+ end
- if doc
- update_parent_votes(doc, options) if options[:voteable][:update_parents]
- # Update new votes data
- options[:votee].write_attribute('votes', doc['votes']) if options[:votee]
- options[:votee] || new(doc)
- else
- false
- end
+ if doc
+ update_parent_votes(doc, options) if options[:voteable][:update_parents]
+ # Update new votes data
+ options[:votee].try(:reload) || new(doc)
+ else
+ false
end
end
-
private
def validate_and_normalize_vote_options(options)
options.symbolize_keys!
@@ -60,12 +56,13 @@ def validate_and_normalize_vote_options(options)
def new_vote_query_and_update(options)
if options[:value] == :up
- positive_voter_ids = 'votes.up'
- positive_votes_count = 'votes.up_count'
+ vote_option_ids = 'votes.up'
+ vote_option_count = options[:voter_id].present? ? 'votes.up_count' : 'votes.faceless_up_count'
else
- positive_voter_ids = 'votes.down'
- positive_votes_count = 'votes.down_count'
+ vote_option_ids = 'votes.down'
+ vote_option_count = options[:voter_id].present? ? 'votes.down_count' : 'votes.faceless_down_count'
end
+ push_option = options[:voter_id].present? ? { '$push' => { vote_option_ids => options[:voter_id] } } : {}
return {
# Validate voter_id did not vote for votee_id yet
@@ -74,13 +71,12 @@ def new_vote_query_and_update(options)
'votes.down' => { '$ne' => options[:voter_id] }
}, {
# then update
- '$push' => { positive_voter_ids => options[:voter_id] },
'$inc' => {
'votes.count' => +1,
- positive_votes_count => +1,
+ vote_option_count => +1,
'votes.point' => options[:voteable][options[:value]]
}
- }
+ }.merge!(push_option)
end
@@ -150,6 +146,7 @@ def unvote_query_and_update(options)
def update_parent_votes(doc, options)
+
VOTEABLE[name].each do |class_name, voteable|
if metadata = voteable_relation(class_name)
if (parent_id = doc[voteable_foreign_key(metadata)]).present?
@@ -199,9 +196,9 @@ def parent_inc_options(voteable, options)
unless voteable[:update_counters] == false
inc_options['votes.count'] = +1
if options[:value] == :up
- inc_options['votes.up_count'] = +1
+ options[:voter_id].present? ? inc_options['votes.up_count'] = +1 : inc_options['votes.faceless_up_count'] = +1
else
- inc_options['votes.down_count'] = +1
+ options[:voter_id].present? ? inc_options['votes.down_count'] = +1 : inc_options['votes.faceless_down_count'] = +1
end
end
end
View
2  spec/spec_helper.rb
@@ -3,7 +3,7 @@
Bundler.setup
# TODO: Need better solution
-if rand > 0.5
+if rand > 0
puts 'Mongoid'
require 'mongoid'
models_folder = File.join(File.dirname(__FILE__), 'mongoid/models')
View
178 spec/voteable_mongo/voteable_spec.rb
@@ -45,6 +45,15 @@
@user1 = User.create!
@user2 = User.create!
+
+ # for anonymous voting tests
+ @_category1 = Category.create!(:name => '123')
+ @_category2 = Category.create!(:name => '456')
+ @_post1 = Post.create!(:title => 'post11')
+ @_post2 = Post.create!(:title => 'post21')
+ @_post1.category_ids = [@_category1.id, @_category2.id]
+ @_post1.save!
+ @_comment = @_post2.comments.create!
end
it "vote for unexisting post" do
@@ -55,26 +64,36 @@
it 'votes_count, up_votes_count, down_votes_count, votes_point should be zero' do
@category1.up_votes_count.should == 0
@category1.down_votes_count.should == 0
+ @category1.faceless_up_count.should == 0
+ @category1.faceless_down_count.should == 0
@category1.votes_count.should == 0
@category1.votes_point.should == 0
@category2.up_votes_count.should == 0
@category2.down_votes_count.should == 0
+ @category2.faceless_up_count.should == 0
+ @category2.faceless_down_count.should == 0
@category2.votes_count.should == 0
@category2.votes_point.should == 0
@post1.up_votes_count.should == 0
@post1.down_votes_count.should == 0
+ @post1.faceless_up_count.should == 0
+ @post1.faceless_down_count.should == 0
@post1.votes_count.should == 0
@post1.votes_point.should == 0
@post2.up_votes_count.should == 0
@post2.down_votes_count.should == 0
+ @post2.faceless_up_count.should == 0
+ @post2.faceless_down_count.should == 0
@post2.votes_count.should == 0
@post2.votes_point.should == 0
@comment.up_votes_count.should == 0
@comment.down_votes_count.should == 0
+ @comment.faceless_up_count.should == 0
+ @comment.faceless_down_count.should == 0
@comment.votes_count.should == 0
@comment.votes_point.should == 0
end
@@ -127,6 +146,58 @@
end
end
+
+ context 'anonymous vote up post1 the first time' do
+ before :all do
+ @post = @_post1.vote(:value => :up)
+ end
+ it 'validates return post' do
+ @post.should be_is_a Post
+ @post.should_not be_new_record
+
+ @post.votes.should == {
+ 'up' => [],
+ 'down' => [],
+ 'faceless_up_count' => 1,
+ 'faceless_down_count' => 0,
+ 'up_count' => 0,
+ 'down_count' => 0,
+ 'count' => 1,
+ 'point' => 1
+ }
+ end
+ it 'validates post counters' do
+ @_post1.up_votes_count.should == 0
+ @_post1.down_votes_count.should == 0
+ @_post1.faceless_up_count.should == 1
+ @_post1.faceless_down_count.should == 0
+ @_post1.votes_count.should == 1
+ @_post1.votes_point.should == 1
+ end
+ it "validates voters stats" do
+ @_post1.up_voters(User).to_a.should be_empty
+ @_post1.voters(User).to_a.should be_empty
+ @_post1.down_voters(User).should be_empty
+ end
+ it "validates parents stats" do
+ @_category1.reload
+ @_category1.up_votes_count.should == 0
+ @_category1.down_votes_count.should == 0
+ @_category1.faceless_up_count.should == 0
+ @_category1.faceless_down_count.should == 0
+ @_category1.votes_count.should == 0
+ @_category1.votes_point.should == 3
+
+ @_category2.reload
+ @_category2.up_votes_count.should == 0
+ @_category2.down_votes_count.should == 0
+ @_category2.faceless_up_count.should == 0
+ @_category2.faceless_down_count.should == 0
+ @_category2.votes_count.should == 0
+ @_category2.votes_point.should == 3
+ end
+ end
+
context 'user1 vote up post1 the first time' do
before :all do
@post = @post1.vote(:voter_id => @user1.id, :value => :up)
@@ -139,6 +210,8 @@
@post.votes.should == {
'up' => [@user1.id],
'down' => [],
+ 'faceless_up_count' => 0,
+ 'faceless_down_count' => 0,
'up_count' => 1,
'down_count' => 0,
'count' => 1,
@@ -149,6 +222,8 @@
it 'validates' do
@post1.up_votes_count.should == 1
@post1.down_votes_count.should == 0
+ @post1.faceless_up_count.should == 0
+ @post1.faceless_down_count.should == 0
@post1.votes_count.should == 1
@post1.votes_point.should == 1
@@ -167,12 +242,16 @@
@category1.reload
@category1.up_votes_count.should == 0
@category1.down_votes_count.should == 0
+ @category1.faceless_up_count.should == 0
+ @category1.faceless_down_count.should == 0
@category1.votes_count.should == 0
@category1.votes_point.should == 3
@category2.reload
@category2.up_votes_count.should == 0
@category2.down_votes_count.should == 0
+ @category2.faceless_up_count.should == 0
+ @category2.faceless_down_count.should == 0
@category2.votes_count.should == 0
@category2.votes_point.should == 3
end
@@ -183,6 +262,8 @@
@post1.up_votes_count.should == 1
@post1.down_votes_count.should == 0
+ @post1.faceless_up_count.should == 0
+ @post1.faceless_down_count.should == 0
@post1.votes_count.should == 1
@post1.votes_point.should == 1
@@ -190,6 +271,51 @@
end
end
+ context "anonymous votes down post1 the first time" do
+ before :all do
+ Post.vote(:votee_id => @_post1.id, :value => :down)
+ @_post1.reload
+ end
+ it 'post1 up_votes_count is the same' do
+ @_post1.up_votes_count.should == 0
+ end
+
+ it 'post1 faceless_up_count is the same' do
+ @_post1.faceless_up_count.should == 1
+ end
+
+ it 'down_votes_count, votes_count, and votes_point changed' do
+ @_post1.down_votes_count.should == 0
+ @_post1.faceless_down_count.should == 1
+ @_post1.votes_count.should == 2
+ @_post1.votes_point.should == 0
+ end
+
+ it 'post1 get voters' do
+ @_post1.up_voters(User).to_a.should be_empty
+ @_post1.down_voters(User).to_a.should be_empty
+ @_post1.voters(User).to_a.should be_empty
+ end
+
+ it 'categories votes' do
+ @_category1.reload
+ @_category1.up_votes_count.should == 0
+ @_category1.down_votes_count.should == 0
+ @_category1.faceless_up_count.should == 0
+ @_category1.faceless_down_count.should == 0
+ @_category1.votes_count.should == 0
+ @_category1.votes_point.should == -2
+
+ @_category2.reload
+ @_category2.up_votes_count.should == 0
+ @_category2.down_votes_count.should == 0
+ @_category2.faceless_up_count.should == 0
+ @_category2.faceless_down_count.should == 0
+ @_category2.votes_count.should == 0
+ @_category2.votes_point.should == -2
+ end
+ end
+
context 'user2 vote down post1 the first time' do
before :all do
Post.vote(:votee_id => @post1.id, :voter_id => @user2.id, :value => :down)
@@ -200,6 +326,10 @@
@post1.up_votes_count.should == 1
end
+ it 'post1 faceless_up_count is the same' do
+ @post1.faceless_up_count.should == 0
+ end
+
it 'post1 vote_value on user1 is the same' do
@post1.vote_value(@user1.id).should == :up
end
@@ -226,12 +356,16 @@
@category1.reload
@category1.up_votes_count.should == 0
@category1.down_votes_count.should == 0
+ @category1.faceless_up_count.should == 0
+ @category1.faceless_down_count.should == 0
@category1.votes_count.should == 0
@category1.votes_point.should == -2
@category2.reload
@category2.up_votes_count.should == 0
@category2.down_votes_count.should == 0
+ @category2.faceless_up_count.should == 0
+ @category2.faceless_down_count.should == 0
@category2.votes_count.should == 0
@category2.votes_point.should == -2
end
@@ -298,6 +432,30 @@
end
end
+ context 'anonymous vote up post2 comment the first time' do
+ before :all do
+ @_comment.vote(:value => :up)
+ @_comment.reload
+ @_post2.reload
+ end
+
+ it 'validates' do
+ @_post2.up_votes_count.should == 0
+ @_post2.down_votes_count.should == 0
+ @_post2.faceless_up_count.should == 1
+ @_post2.faceless_down_count.should == 0
+ @_post2.votes_count.should == 1
+ @_post2.votes_point.should == 2
+
+ @_comment.up_votes_count.should == 0
+ @_comment.down_votes_count.should == 0
+ @_comment.faceless_up_count.should == 1
+ @_comment.faceless_down_count.should == 0
+ @_comment.votes_count.should == 1
+ @_comment.votes_point.should == 1
+ end
+ end
+
context 'user1 vote up post2 comment the first time' do
before :all do
@@ -309,11 +467,15 @@
it 'validates' do
@post2.up_votes_count.should == 2
@post2.down_votes_count.should == 0
+ @post2.faceless_up_count.should == 0
+ @post2.faceless_down_count.should == 0
@post2.votes_count.should == 2
@post2.votes_point.should == 3
@comment.up_votes_count.should == 1
@comment.down_votes_count.should == 0
+ @comment.faceless_up_count.should == 0
+ @comment.faceless_down_count.should == 0
@comment.votes_count.should == 1
@comment.votes_point.should == 1
end
@@ -364,6 +526,8 @@
it 'validates' do
@post1.up_votes_count.should == 0
@post1.down_votes_count.should == 1
+ @post1.faceless_up_count.should == 0
+ @post1.faceless_down_count.should == 0
@post1.votes_count.should == 1
@post1.votes_point.should == -1
@@ -378,6 +542,8 @@
it "verify @post1 counters" do
@post1.up_votes_count.should == 0
@post1.down_votes_count.should == 1
+ @post1.faceless_up_count.should == 0
+ @post1.faceless_down_count.should == 0
@post1.votes_count.should == 1
@post1.votes_point.should == -1
end
@@ -385,6 +551,8 @@
it "verify @post2 counters" do
@post2.up_votes_count.should == 1
@post2.down_votes_count.should == 1
+ @post2.faceless_up_count.should == 0
+ @post2.faceless_down_count.should == 0
@post2.votes_count.should == 2
@post2.votes_point.should == 0
end
@@ -401,11 +569,15 @@
it "" do
@comment.up_votes_count.should == 0
@comment.down_votes_count.should == 0
+ @comment.faceless_up_count.should == 0
+ @comment.faceless_down_count.should == 0
@comment.votes_count.should == 0
@comment.votes_point.should == 0
@post2.up_votes_count.should == 1
@post2.down_votes_count.should == 0
+ @post2.faceless_up_count.should == 0
+ @post2.faceless_down_count.should == 0
@post2.votes_count.should == 1
@post2.votes_point.should == 1
end
@@ -417,16 +589,22 @@
@post1.up_votes_count.should == 0
@post1.down_votes_count.should == 1
+ @post1.faceless_up_count.should == 0
+ @post1.faceless_down_count.should == 0
@post1.votes_count.should == 1
@post1.votes_point.should == -1
@post2.up_votes_count.should == 1
@post2.down_votes_count.should == 0
+ @post2.faceless_up_count.should == 0
+ @post2.faceless_down_count.should == 0
@post2.votes_count.should == 1
@post2.votes_point.should == 1
@comment.up_votes_count.should == 0
@comment.down_votes_count.should == 0
+ @comment.faceless_up_count.should == 0
+ @comment.faceless_down_count.should == 0
@comment.votes_count.should == 0
@comment.votes_point.should == 0
end
View
2  voteable_mongo.gemspec
@@ -12,7 +12,7 @@ Gem::Specification.new do |s|
s.summary = %q{Add up / down voting ability to Mongoid and MongoMapper documents}
s.description = %q{Add up / down voting ability to Mongoid and MongoMapper documents. Optimized for speed by using only ONE request to MongoDB to validate, update, and retrieve updated data.}
- s.add_development_dependency 'rspec', '~> 2.5.0'
+ s.add_development_dependency 'rspec', '~> 2.6.0'
s.add_development_dependency 'mongoid', '~> 2.0.0'
s.add_development_dependency 'mongo_mapper', '~> 0.9.0'

0 comments on commit e9f8afa

Please sign in to comment.
Something went wrong with that request. Please try again.