Skip to content

Commit

Permalink
Adds the ability to unvote an object
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Neighman committed Apr 10, 2012
1 parent 5b0e1dd commit ac6b329
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 82 deletions.
139 changes: 75 additions & 64 deletions Gemfile.lock
Expand Up @@ -7,81 +7,92 @@ PATH
GEM
remote: http://rubygems.org/
specs:
abstract (1.0.0)
actionmailer (3.0.9)
actionpack (= 3.0.9)
mail (~> 2.2.19)
actionpack (3.0.9)
activemodel (= 3.0.9)
activesupport (= 3.0.9)
builder (~> 2.1.2)
erubis (~> 2.6.6)
i18n (~> 0.5.0)
rack (~> 1.2.1)
rack-mount (~> 0.6.14)
rack-test (~> 0.5.7)
tzinfo (~> 0.3.23)
activemodel (3.0.9)
activesupport (= 3.0.9)
builder (~> 2.1.2)
i18n (~> 0.5.0)
activerecord (3.0.9)
activemodel (= 3.0.9)
activesupport (= 3.0.9)
arel (~> 2.0.10)
tzinfo (~> 0.3.23)
activeresource (3.0.9)
activemodel (= 3.0.9)
activesupport (= 3.0.9)
activesupport (3.0.9)
arel (2.0.10)
builder (2.1.2)
diff-lcs (1.1.2)
erubis (2.6.6)
abstract (>= 1.0.0)
i18n (0.5.0)
mail (2.2.19)
activesupport (>= 2.3.6)
actionmailer (3.2.3)
actionpack (= 3.2.3)
mail (~> 2.4.4)
actionpack (3.2.3)
activemodel (= 3.2.3)
activesupport (= 3.2.3)
builder (~> 3.0.0)
erubis (~> 2.7.0)
journey (~> 1.0.1)
rack (~> 1.4.0)
rack-cache (~> 1.2)
rack-test (~> 0.6.1)
sprockets (~> 2.1.2)
activemodel (3.2.3)
activesupport (= 3.2.3)
builder (~> 3.0.0)
activerecord (3.2.3)
activemodel (= 3.2.3)
activesupport (= 3.2.3)
arel (~> 3.0.2)
tzinfo (~> 0.3.29)
activeresource (3.2.3)
activemodel (= 3.2.3)
activesupport (= 3.2.3)
activesupport (3.2.3)
i18n (~> 0.6)
multi_json (~> 1.0)
arel (3.0.2)
builder (3.0.0)
diff-lcs (1.1.3)
erubis (2.7.0)
hike (1.2.1)
i18n (0.6.0)
journey (1.0.3)
json (1.6.6)
mail (2.4.4)
i18n (>= 0.4.0)
mime-types (~> 1.16)
treetop (~> 1.4.8)
mime-types (1.16)
polyglot (0.3.2)
rack (1.2.3)
rack-mount (0.6.14)
rack (>= 1.0.0)
rack-test (0.5.7)
mime-types (1.18)
multi_json (1.2.0)
polyglot (0.3.3)
rack (1.4.1)
rack-cache (1.2)
rack (>= 0.4)
rack-ssl (1.3.2)
rack
rack-test (0.6.1)
rack (>= 1.0)
rails (3.0.9)
actionmailer (= 3.0.9)
actionpack (= 3.0.9)
activerecord (= 3.0.9)
activeresource (= 3.0.9)
activesupport (= 3.0.9)
rails (3.2.3)
actionmailer (= 3.2.3)
actionpack (= 3.2.3)
activerecord (= 3.2.3)
activeresource (= 3.2.3)
activesupport (= 3.2.3)
bundler (~> 1.0)
railties (= 3.0.9)
railties (3.0.9)
actionpack (= 3.0.9)
activesupport (= 3.0.9)
railties (= 3.2.3)
railties (3.2.3)
actionpack (= 3.2.3)
activesupport (= 3.2.3)
rack-ssl (~> 1.3.2)
rake (>= 0.8.7)
rdoc (~> 3.4)
thor (~> 0.14.4)
rake (0.9.2)
rdoc (3.8)
rspec (2.3.0)
rspec-core (~> 2.3.0)
rspec-expectations (~> 2.3.0)
rspec-mocks (~> 2.3.0)
rspec-core (2.3.1)
rspec-expectations (2.3.0)
diff-lcs (~> 1.1.2)
rspec-mocks (2.3.0)
sqlite3 (1.3.3)
thor (~> 0.14.6)
rake (0.9.2.2)
rdoc (3.12)
json (~> 1.4)
rspec (2.9.0)
rspec-core (~> 2.9.0)
rspec-expectations (~> 2.9.0)
rspec-mocks (~> 2.9.0)
rspec-core (2.9.0)
rspec-expectations (2.9.1)
diff-lcs (~> 1.1.3)
rspec-mocks (2.9.0)
sprockets (2.1.2)
hike (~> 1.2)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
sqlite3 (1.3.5)
thor (0.14.6)
tilt (1.3.3)
treetop (1.4.10)
polyglot
polyglot (>= 0.3.1)
tzinfo (0.3.29)
tzinfo (0.3.33)

PLATFORMS
ruby
Expand Down
12 changes: 11 additions & 1 deletion README.markdown
Expand Up @@ -77,14 +77,24 @@ Revisiting the previous example of code.
# negative votes
@post.downvote_from @user2
@post.vote :voter => @user2, :vote => 'bad'

# tally them up!
@post.votes.size # => 5
@post.likes.size # => 3
@post.upvotes.size # => 3
@post.dislikes.size # => 2
@post.downvotes.size # => 2

You can also 'unvote' a model to remove a previous vote.

@post.liked_by @user1
@post.unlike_by @user1

@post.disliked_by @user1
@post.undisliked_by @user1

Unvoting works for both positive and negative votes.

### The Voter

You can have your voters ``acts_as_voter`` to provide some reserve functionality.
Expand Down
2 changes: 1 addition & 1 deletion lib/acts_as_votable/version.rb
@@ -1,3 +1,3 @@
module ActsAsVotable
VERSION = "0.1.3"
VERSION = "0.2.0"
end
23 changes: 18 additions & 5 deletions lib/acts_as_votable/votable.rb
Expand Up @@ -26,8 +26,10 @@ def self.included base

:down_votes => [
:false_votes, :downs, :downvotes, :dislikes, :negatives
],
:unvote => [
:unliked_by, :undisliked_by
]

}

base.class_eval do
Expand Down Expand Up @@ -101,6 +103,17 @@ def vote args = {}

end

def unvote args = {}
return false if args[:voter].nil?
_votes_ = find_votes(:voter_id => args[:voter].id, :voter_type => args[:voter].class.name)

return true if _votes_.size == 0
_votes_.each(&:destroy)
update_cached_votes
self.vote_registered = false if votes.count == 0
return true
end

def vote_up voter
self.vote :voter => voter, :vote => true
end
Expand Down Expand Up @@ -151,27 +164,27 @@ def count_votes_total skip_cache = false
if !skip_cache && self.respond_to?(:cached_votes_total)
return self.send(:cached_votes_total)
end
find_votes.size
find_votes.count
end

def count_votes_up skip_cache = false
if !skip_cache && self.respond_to?(:cached_votes_up)
return self.send(:cached_votes_up)
end
up_votes.size
up_votes.count
end

def count_votes_down skip_cache = false
if !skip_cache && self.respond_to?(:cached_votes_down)
return self.send(:cached_votes_down)
end
down_votes.size
down_votes.count
end

# voters
def voted_on_by? voter
votes = find_votes :voter_id => voter.id, :voter_type => voter.class.name
votes.size > 0
votes.count > 0
end

end
Expand Down
9 changes: 7 additions & 2 deletions lib/acts_as_votable/voter.rb
Expand Up @@ -5,8 +5,9 @@ def self.included(base)

# allow user to define these
aliases = {
:vote_up_for => [:likes, :upvotes, :up_votes],
:vote_down_for => [:dislikes, :downvotes, :down_votes]
:vote_up_for => [:likes, :upvotes, :up_votes],
:vote_down_for => [:dislikes, :downvotes, :down_votes],
:unvote_for => [:unlike, :undislike]
}

base.class_eval do
Expand Down Expand Up @@ -43,6 +44,10 @@ def vote_down_for model
vote :votable => model, :vote => false
end

def unvote_for model
model.unvote :voter => self
end

# results
def voted_on? votable
votes = find_votes(:votable_id => votable.id, :votable_type => votable.class.name)
Expand Down
59 changes: 54 additions & 5 deletions spec/votable_spec.rb
Expand Up @@ -14,7 +14,7 @@
it "should be votable" do
Votable.should be_votable
end

describe "voting on a votable object" do

before(:each) do
Expand All @@ -24,7 +24,7 @@

@voter2 = Voter.new(:name => 'a new person')
@voter2.save

@votable = Votable.new(:name => 'a voting model')
@votable.save
end
Expand All @@ -37,7 +37,7 @@
@votable.vote :voter => @voter, :vote => 'yes'
@votable.votes.size.should == 1
end

it "should have one vote when voted on twice by the same person" do
@votable.vote :voter => @voter, :vote => 'yes'
@votable.vote :voter => @voter, :vote => 'no'
Expand Down Expand Up @@ -87,7 +87,7 @@
@votable.vote :voter => @voter, :vote => 'yes'
@votable.vote_registered?.should be false
end

it "should count the vote as registered if the voter has voted and the vote has changed" do
@votable.vote :voter => @voter, :vote => true
@votable.vote :voter => @voter, :vote => 'dislike'
Expand All @@ -99,10 +99,35 @@
@votable.voted_on_by?(@voter).should be true
end

it "should unvote a positive vote" do
@votable.vote :voter => @voter
@votable.unvote :voter => @voter
@votable.find_votes.count.should == 0
end

it "should set the votable to unregistered after unvoting" do
@votable.vote :voter => @voter
@votable.unvote :voter => @voter
@votable.vote_registered?.should be false
end

it "should unvote a negative vote" do
@votable.vote :voter => @voter, :vote => 'no'
@votable.unvote :voter => @voter
@votable.find_votes.count.should == 0
end

it "should unvote only the from a single voter" do
@votable.vote :voter => @voter
@votable.vote :voter => @voter2
@votable.unvote :voter => @voter
@votable.find_votes.count.should == 1
end

it "should be contained to instances" do
votable2 = Votable.new(:name => '2nd votable')
votable2.save

@votable.vote :voter => @voter, :vote => false
votable2.vote :voter => @voter, :vote => true
votable2.vote :voter => @voter, :vote => true
Expand Down Expand Up @@ -135,6 +160,18 @@
@votable_cache.cached_votes_total.should == 1
end

it "should update cached total votes when a vote up is removed" do
@votable_cache.vote :voter => @voter, :vote => 'true'
@votable_cache.unvote :voter => @voter
@votable_cache.cached_votes_total.should == 0
end

it "should update cached total votes when a vote down is removed" do
@votable_cache.vote :voter => @voter, :vote => 'false'
@votable_cache.unvote :voter => @voter
@votable_cache.cached_votes_total.should == 0
end

it "should update cached up votes if there is an up vote column" do
@votable_cache.cached_votes_up = 50
@votable_cache.vote :voter => @voter
Expand All @@ -148,6 +185,18 @@
@votable_cache.cached_votes_down.should == 1
end

it "should update cached up votes when a vote up is removed" do
@votable_cache.vote :voter => @voter, :vote => 'true'
@votable_cache.unvote :voter => @voter
@votable_cache.cached_votes_up.should == 0
end

it "should update cached down votes when a vote down is removed" do
@votable_cache.vote :voter => @voter, :vote => 'false'
@votable_cache.unvote :voter => @voter
@votable_cache.cached_votes_down.should == 0
end

it "should select from cached total votes if there a total column" do
@votable_cache.vote :voter => @voter
@votable_cache.cached_votes_total = 50
Expand Down

0 comments on commit ac6b329

Please sign in to comment.