acts_as_votable 0.10.0 → 0.11.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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +9 -6
  3. data/.rubocop.yml +121 -0
  4. data/.travis.yml +12 -23
  5. data/Appraisals +13 -0
  6. data/Gemfile +3 -14
  7. data/README.markdown +80 -13
  8. data/Rakefile +6 -4
  9. data/acts_as_votable.gemspec +12 -5
  10. data/gemfiles/.bundle/config +2 -0
  11. data/gemfiles/rails_4.gemfile +7 -0
  12. data/gemfiles/rails_4.gemfile.lock +159 -0
  13. data/gemfiles/rails_5.gemfile +7 -0
  14. data/gemfiles/rails_5.gemfile.lock +166 -0
  15. data/gemfiles/rails_5_1.gemfile +7 -0
  16. data/gemfiles/rails_5_1.gemfile.lock +166 -0
  17. data/lib/acts_as_votable.rb +9 -9
  18. data/lib/acts_as_votable/cacheable.rb +174 -0
  19. data/lib/acts_as_votable/extenders/controller.rb +3 -4
  20. data/lib/acts_as_votable/extenders/votable.rb +17 -6
  21. data/lib/acts_as_votable/extenders/voter.rb +4 -6
  22. data/lib/acts_as_votable/helpers/words.rb +7 -10
  23. data/lib/acts_as_votable/version.rb +3 -1
  24. data/lib/acts_as_votable/votable.rb +50 -187
  25. data/lib/acts_as_votable/vote.rb +10 -12
  26. data/lib/acts_as_votable/voter.rb +52 -53
  27. data/lib/generators/acts_as_votable/migration/migration_generator.rb +19 -4
  28. data/lib/generators/acts_as_votable/migration/templates/active_record/{migration.rb → migration.erb} +1 -6
  29. data/spec/factories/votable.rb +6 -0
  30. data/spec/factories/votable_cache.rb +6 -0
  31. data/spec/factories/votable_cache_update_attributes.rb +6 -0
  32. data/spec/factories/votable_cache_update_columns.rb +6 -0
  33. data/spec/factories/votable_child_of_sti_not_votable.rb +6 -0
  34. data/spec/factories/votable_child_of_sti_votable.rb +6 -0
  35. data/spec/factories/votable_voter.rb +6 -0
  36. data/spec/factories/vote.rb +6 -0
  37. data/spec/factories/voter.rb +6 -0
  38. data/spec/generators/active_record_generator_spec.rb +13 -0
  39. data/spec/shared_example/votable_model.rb +506 -0
  40. data/spec/shared_example/voter_model.rb +280 -0
  41. data/spec/spec_helper.rb +28 -18
  42. data/spec/support/factory_girl.rb +10 -0
  43. data/spec/votable_spec.rb +10 -9
  44. data/spec/votable_voter_spec.rb +12 -12
  45. data/spec/voter_spec.rb +9 -10
  46. data/spec/words_spec.rb +9 -12
  47. metadata +98 -27
  48. data/spec/shared_example/votable_model_spec.rb +0 -421
  49. data/spec/shared_example/voter_model_spec.rb +0 -279
@@ -1,29 +1,27 @@
1
- require 'acts_as_votable/helpers/words'
1
+ # frozen_string_literal: true
2
+
3
+ require "acts_as_votable/helpers/words"
2
4
 
3
5
  module ActsAsVotable
4
6
  class Vote < ::ActiveRecord::Base
5
-
6
7
  include Helpers::Words
7
8
 
8
- if ::ActiveRecord::VERSION::MAJOR < 4
9
+ if defined?(ProtectedAttributes)
9
10
  attr_accessible :votable_id, :votable_type,
10
11
  :voter_id, :voter_type,
11
12
  :votable, :voter,
12
13
  :vote_flag, :vote_scope
13
14
  end
14
15
 
15
- belongs_to :votable, :polymorphic => true
16
- belongs_to :voter, :polymorphic => true
16
+ belongs_to :votable, polymorphic: true
17
+ belongs_to :voter, polymorphic: true
17
18
 
18
- scope :up, lambda{ where(:vote_flag => true) }
19
- scope :down, lambda{ where(:vote_flag => false) }
20
- scope :for_type, lambda{ |klass| where(:votable_type => klass) }
21
- scope :by_type, lambda{ |klass| where(:voter_type => klass) }
19
+ scope :up, -> { where(vote_flag: true) }
20
+ scope :down, -> { where(vote_flag: false) }
21
+ scope :for_type, ->(klass) { where(votable_type: klass.to_s) }
22
+ scope :by_type, ->(klass) { where(voter_type: klass.to_s) }
22
23
 
23
24
  validates_presence_of :votable_id
24
25
  validates_presence_of :voter_id
25
-
26
26
  end
27
-
28
27
  end
29
-
@@ -1,24 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActsAsVotable
2
4
  module Voter
3
-
4
5
  def self.included(base)
5
-
6
6
  # allow user to define these
7
7
  aliases = {
8
- :vote_up_for => [:likes, :upvotes, :up_votes],
9
- :vote_down_for => [:dislikes, :downvotes, :down_votes],
10
- :unvote_for => [:unlike, :undislike],
11
- :voted_on? => [:voted_for?],
12
- :voted_up_on? => [:voted_up_for?, :liked?],
13
- :voted_down_on? => [:voted_down_for?, :disliked?],
14
- :voted_as_when_voting_on => [:voted_as_when_voted_on, :voted_as_when_voting_for, :voted_as_when_voted_for],
15
- :find_up_voted_items => [:find_liked_items],
16
- :find_down_voted_items => [:find_disliked_items]
8
+ vote_up_for: [:likes, :upvotes, :up_votes],
9
+ vote_down_for: [:dislikes, :downvotes, :down_votes],
10
+ unvote_for: [:unlike, :undislike],
11
+ voted_on?: [:voted_for?],
12
+ voted_up_on?: [:voted_up_for?, :liked?],
13
+ voted_down_on?: [:voted_down_for?, :disliked?],
14
+ voted_as_when_voting_on: [:voted_as_when_voted_on, :voted_as_when_voting_for, :voted_as_when_voted_for],
15
+ find_up_voted_items: [:find_liked_items],
16
+ find_down_voted_items: [:find_disliked_items]
17
17
  }
18
18
 
19
19
  base.class_eval do
20
20
 
21
- has_many :votes, :class_name => 'ActsAsVotable::Vote', :as => :voter, :dependent => :destroy do
21
+ has_many :votes, class_name: "ActsAsVotable::Vote", as: :voter, dependent: :destroy do
22
22
  def votables
23
23
  includes(:votable).map(&:votable)
24
24
  end
@@ -31,74 +31,73 @@ module ActsAsVotable
31
31
  end
32
32
 
33
33
  end
34
-
35
34
  end
36
35
 
37
36
  # voting
38
- def vote args
39
- args[:votable].vote_by args.merge({:voter => self})
37
+ def vote(args)
38
+ args[:votable].vote_by args.merge(voter: self)
40
39
  end
41
40
 
42
- def vote_up_for model=nil, args={}
43
- vote :votable => model, :vote_scope => args[:vote_scope], :vote => true
41
+ def vote_up_for(model = nil, args = {})
42
+ vote votable: model, vote_scope: args[:vote_scope], vote: true
44
43
  end
45
44
 
46
- def vote_down_for model=nil, args={}
47
- vote :votable => model, :vote_scope => args[:vote_scope], :vote => false
45
+ def vote_down_for(model = nil, args = {})
46
+ vote votable: model, vote_scope: args[:vote_scope], vote: false
48
47
  end
49
48
 
50
- def unvote_for model, args={}
51
- model.unvote :voter => self, :vote_scope => args[:vote_scope]
49
+ def unvote_for(model, args = {})
50
+ model.unvote voter: self, vote_scope: args[:vote_scope]
52
51
  end
53
52
 
54
53
  # results
55
- def voted_on? votable, args={}
56
- votes = find_votes(:votable_id => votable.id, :votable_type => votable.class.base_class.name,
57
- :vote_scope => args[:vote_scope])
54
+ def voted_on?(votable, args = {})
55
+ votes = find_votes(votable_id: votable.id, votable_type: votable.class.base_class.name,
56
+ vote_scope: args[:vote_scope])
58
57
  votes.size > 0
59
58
  end
60
59
 
61
- def voted_up_on? votable, args={}
62
- votes = find_votes(:votable_id => votable.id, :votable_type => votable.class.base_class.name,
63
- :vote_scope => args[:vote_scope], :vote_flag => true)
60
+ def voted_up_on?(votable, args = {})
61
+ votes = find_votes(votable_id: votable.id, votable_type: votable.class.base_class.name,
62
+ vote_scope: args[:vote_scope], vote_flag: true)
64
63
  votes.size > 0
65
64
  end
66
65
 
67
- def voted_down_on? votable, args={}
68
- votes = find_votes(:votable_id => votable.id, :votable_type => votable.class.base_class.name,
69
- :vote_scope => args[:vote_scope], :vote_flag => false)
66
+ def voted_down_on?(votable, args = {})
67
+ votes = find_votes(votable_id: votable.id, votable_type: votable.class.base_class.name,
68
+ vote_scope: args[:vote_scope], vote_flag: false)
70
69
  votes.size > 0
71
70
  end
72
71
 
73
- def voted_as_when_voting_on votable, args={}
74
- vote = find_votes(:votable_id => votable.id, :votable_type => votable.class.base_class.name,
75
- :vote_scope => args[:vote_scope]).select(:vote_flag).last
72
+ def voted_as_when_voting_on(votable, args = {})
73
+ vote = find_votes(votable_id: votable.id, votable_type: votable.class.base_class.name,
74
+ vote_scope: args[:vote_scope]).select(:vote_flag).last
76
75
  return nil unless vote
77
76
  return vote.vote_flag
78
77
  end
79
78
 
80
- def find_votes extra_conditions = {}
79
+ def find_votes(extra_conditions = {})
81
80
  votes.where(extra_conditions)
82
81
  end
83
82
 
84
- def find_up_votes args={}
85
- find_votes :vote_flag => true, :vote_scope => args[:vote_scope]
83
+ def find_up_votes(args = {})
84
+ find_votes vote_flag: true, vote_scope: args[:vote_scope]
86
85
  end
87
86
 
88
- def find_down_votes args={}
89
- find_votes :vote_flag => false, :vote_scope => args[:vote_scope]
87
+ def find_down_votes(args = {})
88
+ find_votes vote_flag: false, vote_scope: args[:vote_scope]
90
89
  end
91
90
 
92
- def find_votes_for_class klass, extra_conditions = {}
93
- find_votes extra_conditions.merge({:votable_type => klass.name})
91
+ def find_votes_for_class(klass, extra_conditions = {})
92
+ find_votes extra_conditions.merge(votable_type: klass.name)
94
93
  end
95
94
 
96
- def find_up_votes_for_class klass, args={}
97
- find_votes_for_class klass, :vote_flag => true, :vote_scope => args[:vote_scope]
95
+ def find_up_votes_for_class(klass, args = {})
96
+ find_votes_for_class klass, vote_flag: true, vote_scope: args[:vote_scope]
98
97
  end
99
98
 
100
- def find_down_votes_for_class klass, args={}
101
- find_votes_for_class klass, :vote_flag => false, :vote_scope => args[:vote_scope]
99
+ def find_down_votes_for_class(klass, args = {})
100
+ find_votes_for_class klass, vote_flag: false, vote_scope: args[:vote_scope]
102
101
  end
103
102
 
104
103
  # Including polymporphic relations for eager loading
@@ -106,28 +105,28 @@ module ActsAsVotable
106
105
  ActsAsVotable::Vote.includes(:votable)
107
106
  end
108
107
 
109
- def find_voted_items extra_conditions = {}
110
- options = extra_conditions.merge :voter_id => id, :voter_type => self.class.base_class.name
108
+ def find_voted_items(extra_conditions = {})
109
+ options = extra_conditions.merge voter_id: id, voter_type: self.class.base_class.name
111
110
  include_objects.where(options).collect(&:votable)
112
111
  end
113
112
 
114
- def find_up_voted_items extra_conditions = {}
115
- find_voted_items extra_conditions.merge(:vote_flag => true)
113
+ def find_up_voted_items(extra_conditions = {})
114
+ find_voted_items extra_conditions.merge(vote_flag: true)
116
115
  end
117
116
 
118
- def find_down_voted_items extra_conditions = {}
119
- find_voted_items extra_conditions.merge(:vote_flag => false)
117
+ def find_down_voted_items(extra_conditions = {})
118
+ find_voted_items extra_conditions.merge(vote_flag: false)
120
119
  end
121
120
 
122
- def get_voted klass, extra_conditions = {}
121
+ def get_voted(klass, extra_conditions = {})
123
122
  klass.joins(:votes_for).merge find_votes(extra_conditions)
124
123
  end
125
124
 
126
- def get_up_voted klass
125
+ def get_up_voted(klass)
127
126
  klass.joins(:votes_for).merge find_up_votes
128
127
  end
129
128
 
130
- def get_down_voted klass
129
+ def get_down_voted(klass)
131
130
  klass.joins(:votes_for).merge find_down_votes
132
131
  end
133
132
  end
@@ -1,4 +1,6 @@
1
- require 'rails/generators/migration'
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators/migration"
2
4
 
3
5
  module ActsAsVotable
4
6
  class MigrationGenerator < Rails::Generators::Base
@@ -11,21 +13,34 @@ module ActsAsVotable
11
13
  end
12
14
 
13
15
  def self.source_root
14
- File.join(File.dirname(__FILE__), 'templates', (orm.to_s unless orm.class.eql?(String)) )
16
+ File.join(File.dirname(__FILE__), "templates", (orm.to_s unless orm.class.eql?(String)))
15
17
  end
16
18
 
17
19
  def self.orm_has_migration?
18
20
  [:active_record].include? orm
19
21
  end
20
22
 
21
- def self.next_migration_number(path)
23
+ def self.next_migration_number(_path)
22
24
  Time.now.utc.strftime("%Y%m%d%H%M%S")
23
25
  end
24
26
 
25
27
  def create_migration_file
26
28
  if self.class.orm_has_migration?
27
- migration_template 'migration.rb', 'db/migrate/acts_as_votable_migration.rb'
29
+ migration_template "migration.rb", "db/migrate/acts_as_votable_migration.rb", migration_version: migration_version
30
+ end
31
+ end
32
+
33
+
34
+ private
35
+
36
+ def migration_version
37
+ if rails5?
38
+ "[4.2]"
28
39
  end
29
40
  end
41
+
42
+ def rails5?
43
+ Rails.version.start_with? "5"
44
+ end
30
45
  end
31
46
  end
@@ -1,4 +1,4 @@
1
- class ActsAsVotableMigration < ActiveRecord::Migration
1
+ class ActsAsVotableMigration < ActiveRecord::Migration<%= migration_version %>
2
2
  def self.up
3
3
  create_table :votes do |t|
4
4
 
@@ -12,11 +12,6 @@ class ActsAsVotableMigration < ActiveRecord::Migration
12
12
  t.timestamps
13
13
  end
14
14
 
15
- if ActiveRecord::VERSION::MAJOR < 4
16
- add_index :votes, [:votable_id, :votable_type]
17
- add_index :votes, [:voter_id, :voter_type]
18
- end
19
-
20
15
  add_index :votes, [:voter_id, :voter_type, :vote_scope]
21
16
  add_index :votes, [:votable_id, :votable_type, :vote_scope]
22
17
  end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryGirl.define do
4
+ factory :votable do
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryGirl.define do
4
+ factory :votable_cache do
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryGirl.define do
4
+ factory :votable_cache_update_attributes do
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryGirl.define do
4
+ factory :votable_cache_update_columns do
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryGirl.define do
4
+ factory :child_of_sti_not_votable do
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryGirl.define do
4
+ factory :child_of_sti_votable do
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryGirl.define do
4
+ factory :votable_voter do
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryGirl.define do
4
+ factory :vote, class: ActsAsVotable::Vote do
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryGirl.define do
4
+ factory :voter do
5
+ end
6
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "acts_as_votable"
4
+ require "spec_helper"
5
+
6
+ require "rails/generators"
7
+ require "generators/acts_as_votable/migration/migration_generator"
8
+
9
+ module ActsAsVotable
10
+ describe MigrationGenerator do
11
+ pending
12
+ end
13
+ end
@@ -0,0 +1,506 @@
1
+ # frozen_string_literal: true
2
+
3
+ shared_examples "a votable_model" do
4
+ it "should return false when a vote with no voter is saved" do
5
+ expect(votable.vote_by).to be false
6
+ end
7
+
8
+ it "should have one vote when saved" do
9
+ votable.vote_by voter: voter, vote: "yes"
10
+ expect(votable.votes_for.size).to eq(1)
11
+ end
12
+
13
+ it "should have one vote when voted on twice by the same person" do
14
+ votable.vote_by voter: voter, vote: "yes"
15
+ votable.vote_by voter: voter, vote: "no"
16
+ expect(votable.votes_for.size).to eq(1)
17
+ end
18
+
19
+ it "should have two votes_for when voted on twice by the same person with duplicate paramenter" do
20
+ votable.vote_by voter: voter, vote: "yes"
21
+ votable.vote_by voter: voter, vote: "no", duplicate: true
22
+ expect(votable.votes_for.size).to eq(2)
23
+ end
24
+
25
+ it "should have one scoped vote when voting under an scope" do
26
+ votable.vote_by voter: voter, vote: "yes", vote_scope: "rank"
27
+ expect(votable.find_votes_for(vote_scope: "rank").size).to eq(1)
28
+ end
29
+
30
+ it "should have one vote when voted on twice using scope by the same person" do
31
+ votable.vote_by voter: voter, vote: "yes", vote_scope: "rank"
32
+ votable.vote_by voter: voter, vote: "no", vote_scope: "rank"
33
+ expect(votable.find_votes_for(vote_scope: "rank").size).to eq(1)
34
+ end
35
+
36
+ it "should have two votes_for when voting on two different scopes by the same person" do
37
+ votable.vote_by voter: voter, vote: "yes", vote_scope: "weekly_rank"
38
+ votable.vote_by voter: voter, vote: "no", vote_scope: "monthly_rank"
39
+ expect(votable.votes_for.size).to eq(2)
40
+ end
41
+
42
+ it "should be callable with vote_up" do
43
+ votable.vote_up voter
44
+ expect(votable.get_up_votes.first.voter).to eq(voter)
45
+ end
46
+
47
+ it "should be callable with vote_down" do
48
+ votable.vote_down voter
49
+ expect(votable.get_down_votes.first.voter).to eq(voter)
50
+ end
51
+
52
+ it "should have 2 votes_for when voted on once by two different people" do
53
+ votable.vote_by voter: voter
54
+ votable.vote_by voter: voter2
55
+ expect(votable.votes_for.size).to eq(2)
56
+ end
57
+
58
+ it "should have one true vote" do
59
+ votable.vote_by voter: voter
60
+ votable.vote_by voter: voter2, vote: "dislike"
61
+ expect(votable.get_up_votes.size).to eq(1)
62
+ end
63
+
64
+ it "should have 2 false votes_for" do
65
+ votable.vote_by voter: voter, vote: "no"
66
+ votable.vote_by voter: voter2, vote: "dislike"
67
+ expect(votable.get_down_votes.size).to eq(2)
68
+ end
69
+
70
+ it "should have been voted on by voter2" do
71
+ votable.vote_by voter: voter2, vote: true
72
+ expect(votable.find_votes_for.first.voter.id).to be voter2.id
73
+ end
74
+
75
+ it "should count the vote as registered if this is the voters first vote" do
76
+ votable.vote_by voter: voter
77
+ expect(votable.vote_registered?).to be true
78
+ end
79
+
80
+ it "should not count the vote as being registered if that voter has already voted and the vote has not changed" do
81
+ votable.vote_by voter: voter, vote: true
82
+ votable.vote_by voter: voter, vote: "yes"
83
+ expect(votable.vote_registered?).to be false
84
+ end
85
+
86
+ it "should count the vote as registered if the voter has voted and the vote flag has changed" do
87
+ votable.vote_by voter: voter, vote: true
88
+ votable.vote_by voter: voter, vote: "dislike"
89
+ expect(votable.vote_registered?).to be true
90
+ end
91
+
92
+ it "should count the vote as registered if the voter has voted and the vote weight has changed" do
93
+ votable.vote_by voter: voter, vote: true, vote_weight: 1
94
+ votable.vote_by voter: voter, vote: true, vote_weight: 2
95
+ expect(votable.vote_registered?).to be true
96
+ end
97
+
98
+ it "should be voted on by voter" do
99
+ votable.vote_by voter: voter
100
+ expect(votable.voted_on_by?(voter)).to be true
101
+ end
102
+
103
+ it "should be able to unvote a voter" do
104
+ votable.liked_by(voter)
105
+ votable.unliked_by(voter)
106
+ expect(votable.voted_on_by?(voter)).to be false
107
+ end
108
+
109
+ it "should unvote a positive vote" do
110
+ votable.vote_by voter: voter
111
+ votable.unvote voter: voter
112
+ expect(votable.find_votes_for.count).to eq(0)
113
+ end
114
+
115
+ it "should set the votable to unregistered after unvoting" do
116
+ votable.vote_by voter: voter
117
+ votable.unvote voter: voter
118
+ expect(votable.vote_registered?).to be false
119
+ end
120
+
121
+ it "should unvote a negative vote" do
122
+ votable.vote_by voter: voter, vote: "no"
123
+ votable.unvote voter: voter
124
+ expect(votable.find_votes_for.count).to eq(0)
125
+ end
126
+
127
+ it "should unvote only the from a single voter" do
128
+ votable.vote_by voter: voter
129
+ votable.vote_by voter: voter2
130
+ votable.unvote voter: voter
131
+ expect(votable.find_votes_for.count).to eq(1)
132
+ end
133
+
134
+ it "should be contained to instances" do
135
+ votable2 = build(:votable, name: "2nd votable")
136
+ votable2.save
137
+
138
+ votable.vote_by voter: voter, vote: false
139
+ votable2.vote_by voter: voter, vote: true
140
+ votable2.vote_by voter: voter, vote: true
141
+
142
+ expect(votable.vote_registered?).to be true
143
+ expect(votable2.vote_registered?).to be false
144
+ end
145
+
146
+ it "should set default vote weight to 1 if not specified" do
147
+ votable.upvote_by voter
148
+ expect(votable.find_votes_for.first.vote_weight).to eq(1)
149
+ end
150
+
151
+ describe "with cached votes_for" do
152
+ let!(:voter) { create(:voter, name: "i can vote!") }
153
+ let!(:votable) { create(:votable, name: "a voting model without a cache") }
154
+ let!(:votable_cache) { create(:votable_cache, name: "voting model with cache") }
155
+
156
+ it "should not update cached votes_for if there are no columns" do
157
+ votable.vote_by voter: voter
158
+ end
159
+
160
+ it "should update cached total votes_for if there is a total column" do
161
+ votable_cache.cached_votes_total = 50
162
+ votable_cache.vote_by voter: voter
163
+ expect(votable_cache.cached_votes_total).to eq(1)
164
+ end
165
+
166
+ it "should update cached total votes_for when a vote up is removed" do
167
+ votable_cache.vote_by voter: voter, vote: "true"
168
+ votable_cache.unvote voter: voter
169
+ expect(votable_cache.cached_votes_total).to eq(0)
170
+ end
171
+
172
+ it "should update cached total votes_for when a vote down is removed" do
173
+ votable_cache.vote_by voter: voter, vote: "false"
174
+ votable_cache.unvote voter: voter
175
+ expect(votable_cache.cached_votes_total).to eq(0)
176
+ end
177
+
178
+ it "should update cached score votes_for if there is a score column" do
179
+ votable_cache.cached_votes_score = 50
180
+ votable_cache.vote_by voter: voter
181
+ expect(votable_cache.cached_votes_score).to eq(1)
182
+ votable_cache.vote_by voter: voter2, vote: "false"
183
+ expect(votable_cache.cached_votes_score).to eq(0)
184
+ votable_cache.vote_by voter: voter, vote: "false"
185
+ expect(votable_cache.cached_votes_score).to eq(-2)
186
+ end
187
+
188
+ it "should update cached score votes_for when a vote up is removed" do
189
+ votable_cache.vote_by voter: voter, vote: "true"
190
+ expect(votable_cache.cached_votes_score).to eq(1)
191
+ votable_cache.unvote voter: voter
192
+ expect(votable_cache.cached_votes_score).to eq(0)
193
+ end
194
+
195
+ it "should update cached score votes_for when a vote down is removed" do
196
+ votable_cache.vote_by voter: voter, vote: "false"
197
+ expect(votable_cache.cached_votes_score).to eq(-1)
198
+ votable_cache.unvote voter: voter
199
+ expect(votable_cache.cached_votes_score).to eq(0)
200
+ end
201
+
202
+ it "should update cached weighted total if there is a weighted total column" do
203
+ votable_cache.cached_weighted_total = 50
204
+ votable_cache.vote_by voter: voter
205
+ expect(votable_cache.cached_weighted_total).to eq(1)
206
+ votable_cache.vote_by voter: voter2, vote: "false"
207
+ expect(votable_cache.cached_weighted_total).to eq(2)
208
+ end
209
+
210
+ it "should update cached weighted total votes_for when a vote up is removed" do
211
+ votable_cache.vote_by voter: voter, vote: "true", vote_weight: 3
212
+ expect(votable_cache.cached_weighted_total).to eq(3)
213
+ votable_cache.unvote voter: voter
214
+ expect(votable_cache.cached_weighted_total).to eq(0)
215
+ end
216
+
217
+ it "should update cached weighted total votes_for when a vote down is removed" do
218
+ votable_cache.vote_by voter: voter, vote: "false", vote_weight: 4
219
+ expect(votable_cache.cached_weighted_total).to eq(4)
220
+ votable_cache.unvote voter: voter
221
+ expect(votable_cache.cached_weighted_total).to eq(0)
222
+ end
223
+
224
+ it "should update cached weighted score if there is a weighted score column" do
225
+ votable_cache.cached_weighted_score = 50
226
+ votable_cache.vote_by voter: voter, vote_weight: 3
227
+ expect(votable_cache.cached_weighted_score).to eq(3)
228
+ votable_cache.vote_by voter: voter2, vote: "false", vote_weight: 5
229
+ expect(votable_cache.cached_weighted_score).to eq(-2)
230
+ # voter changes her vote from 3 to 5
231
+ votable_cache.vote_by voter: voter, vote_weight: 5
232
+ expect(votable_cache.cached_weighted_score).to eq(0)
233
+ votable_cache.vote_by voter: voter3, vote_weight: 4
234
+ expect(votable_cache.cached_weighted_score).to eq(4)
235
+ end
236
+
237
+ it "should update cached weighted score votes_for when a vote up is removed" do
238
+ votable_cache.vote_by voter: voter, vote: "true", vote_weight: 3
239
+ expect(votable_cache.cached_weighted_score).to eq(3)
240
+ votable_cache.unvote voter: voter
241
+ expect(votable_cache.cached_weighted_score).to eq(0)
242
+ end
243
+
244
+ it "should update cached weighted score votes_for when a vote down is removed" do
245
+ votable_cache.vote_by voter: voter, vote: "false", vote_weight: 4
246
+ expect(votable_cache.cached_weighted_score).to eq(-4)
247
+ votable_cache.unvote voter: voter
248
+ expect(votable_cache.cached_weighted_score).to eq(0)
249
+ end
250
+
251
+ it "should update cached weighted average if there is a weighted average column" do
252
+ votable_cache.cached_weighted_average = 50.0
253
+ votable_cache.vote_by voter: voter, vote: "true", vote_weight: 5
254
+ expect(votable_cache.cached_weighted_average).to eq(5.0)
255
+ votable_cache.vote_by voter: voter2, vote: "true", vote_weight: 3
256
+ expect(votable_cache.cached_weighted_average).to eq(4.0)
257
+ # voter changes her vote from 5 to 4
258
+ votable_cache.vote_by voter: voter, vote: "true", vote_weight: 4
259
+ expect(votable_cache.cached_weighted_average).to eq(3.5)
260
+ votable_cache.vote_by voter: voter3, vote: "true", vote_weight: 5
261
+ expect(votable_cache.cached_weighted_average).to eq(4.0)
262
+ end
263
+
264
+ it "should update cached weighted average votes_for when a vote up is removed" do
265
+ votable_cache.vote_by voter: voter, vote: "true", vote_weight: 5
266
+ votable_cache.vote_by voter: voter2, vote: "true", vote_weight: 3
267
+ expect(votable_cache.cached_weighted_average).to eq(4)
268
+ votable_cache.unvote voter: voter
269
+ expect(votable_cache.cached_weighted_average).to eq(3)
270
+ end
271
+
272
+ it "should update cached up votes_for if there is an up vote column" do
273
+ votable_cache.cached_votes_up = 50
274
+ votable_cache.vote_by voter: voter
275
+ votable_cache.vote_by voter: voter
276
+ expect(votable_cache.cached_votes_up).to eq(1)
277
+ end
278
+
279
+ it "should update cached down votes_for if there is a down vote column" do
280
+ votable_cache.cached_votes_down = 50
281
+ votable_cache.vote_by voter: voter, vote: "false"
282
+ expect(votable_cache.cached_votes_down).to eq(1)
283
+ end
284
+
285
+ it "should update cached up votes_for when a vote up is removed" do
286
+ votable_cache.vote_by voter: voter, vote: "true"
287
+ votable_cache.unvote voter: voter
288
+ expect(votable_cache.cached_votes_up).to eq(0)
289
+ end
290
+
291
+ it "should update cached down votes_for when a vote down is removed" do
292
+ votable_cache.vote_by voter: voter, vote: "false"
293
+ votable_cache.unvote voter: voter
294
+ expect(votable_cache.cached_votes_down).to eq(0)
295
+ end
296
+
297
+ it "should select from cached total votes_for if there a total column" do
298
+ votable_cache.vote_by voter: voter
299
+ votable_cache.cached_votes_total = 50
300
+ expect(votable_cache.count_votes_total).to eq(50)
301
+ end
302
+
303
+ it "should select from cached up votes_for if there is an up vote column" do
304
+ votable_cache.vote_by voter: voter
305
+ votable_cache.cached_votes_up = 50
306
+ expect(votable_cache.count_votes_up).to eq(50)
307
+ end
308
+
309
+ it "should select from cached down votes_for if there is a down vote column" do
310
+ votable_cache.vote_by voter: voter, vote: "false"
311
+ votable_cache.cached_votes_down = 50
312
+ expect(votable_cache.count_votes_down).to eq(50)
313
+ end
314
+
315
+ it "should select from cached votes score if there is a votes score column" do
316
+ votable_cache.vote_by voter: voter, vote: "false"
317
+ votable_cache.cached_votes_score = 50
318
+ expect(votable_cache.count_votes_score).to eq(50)
319
+ end
320
+
321
+ it "should select from cached weighted total if there is a weighted total column" do
322
+ votable_cache.vote_by voter: voter, vote: "false"
323
+ votable_cache.cached_weighted_total = 50
324
+ expect(votable_cache.weighted_total).to eq(50)
325
+ end
326
+
327
+ it "should select from cached weighted score if there is a weighted score column" do
328
+ votable_cache.vote_by voter: voter, vote: "false"
329
+ votable_cache.cached_weighted_score = 50
330
+ expect(votable_cache.weighted_score).to eq(50)
331
+ end
332
+
333
+ it "should select from cached weighted average if there is a weighted average column" do
334
+ votable_cache.vote_by voter: voter, vote: "false"
335
+ votable_cache.cached_weighted_average = 50
336
+ expect(votable_cache.weighted_average).to eq(50)
337
+ end
338
+
339
+ it "should update cached total votes_for when voting under an scope" do
340
+ votable_cache.vote_by voter: voter, vote: "true", vote_scope: "rank"
341
+ expect(votable_cache.cached_votes_total).to eq(1)
342
+ end
343
+
344
+ it "should update cached up votes_for when voting under an scope" do
345
+ votable_cache.vote_by voter: voter, vote: "true", vote_scope: "rank"
346
+ expect(votable_cache.cached_votes_up).to eq(1)
347
+ end
348
+
349
+ it "should update cached total votes_for when a scoped vote down is removed" do
350
+ votable_cache.vote_by voter: voter, vote: "true", vote_scope: "rank"
351
+ votable_cache.unvote voter: voter, vote_scope: "rank"
352
+ expect(votable_cache.cached_votes_total).to eq(0)
353
+ end
354
+
355
+ it "should update cached up votes_for when a scoped vote down is removed" do
356
+ votable_cache.vote_by voter: voter, vote: "true", vote_scope: "rank"
357
+ votable_cache.unvote voter: voter, vote_scope: "rank"
358
+ expect(votable_cache.cached_votes_up).to eq(0)
359
+ end
360
+
361
+ it "should update cached down votes_for when downvoting under a scope" do
362
+ votable_cache.vote_by voter: voter, vote: "false", vote_scope: "rank"
363
+ expect(votable_cache.cached_votes_down).to eq(1)
364
+ end
365
+
366
+ it "should update cached down votes_for when a scoped vote down is removed" do
367
+ votable_cache.vote_by voter: voter, vote: "false", vote_scope: "rank"
368
+ votable_cache.unvote voter: voter, vote_scope: "rank"
369
+ expect(votable_cache.cached_votes_down).to eq(0)
370
+ end
371
+
372
+ describe "with acts_as_votable_options" do
373
+ describe "cacheable_strategy" do
374
+ let(:updated_at) { 3.days.ago }
375
+
376
+ before { votable_cache.vote_by voter: voter }
377
+
378
+ context "update_attributes" do
379
+ let(:votable_cache) { create(:votable_cache_update_attributes, name: "voting model with cache", updated_at: updated_at) }
380
+
381
+ it do
382
+ expect(votable_cache.cached_votes_total).to eq(1)
383
+ expect(votable_cache.updated_at).to_not eq updated_at
384
+ end
385
+ end
386
+
387
+ context "update_columns" do
388
+ let(:votable_cache) { create(:votable_cache_update_columns, name: "voting model with cache", updated_at: updated_at) }
389
+
390
+ it do
391
+ expect(votable_cache.cached_votes_total).to eq(1)
392
+ expect(votable_cache.updated_at).to eq updated_at
393
+ end
394
+ end
395
+ end
396
+ end
397
+ end
398
+
399
+ describe "with scoped cached votes_for" do
400
+
401
+ it "should update cached total votes_for if there is a total column" do
402
+ votable_cache.cached_scoped_test_votes_total = 50
403
+ votable_cache.vote_by voter: voter, vote_scope: "test"
404
+ expect(votable_cache.cached_scoped_test_votes_total).to eq(1)
405
+ end
406
+
407
+ it "should update cached total votes_for when a vote up is removed" do
408
+ votable_cache.vote_by voter: voter, vote: "true", vote_scope: "test"
409
+ votable_cache.unvote voter: voter, vote_scope: "test"
410
+ expect(votable_cache.cached_scoped_test_votes_total).to eq(0)
411
+ end
412
+
413
+ it "should update cached total votes_for when a vote down is removed" do
414
+ votable_cache.vote_by voter: voter, vote: "false", vote_scope: "test"
415
+ votable_cache.unvote voter: voter, vote_scope: "test"
416
+ expect(votable_cache.cached_scoped_test_votes_total).to eq(0)
417
+ end
418
+
419
+ it "should update cached score votes_for if there is a score column" do
420
+ votable_cache.cached_scoped_test_votes_score = 50
421
+ votable_cache.vote_by voter: voter, vote_scope: "test"
422
+ expect(votable_cache.cached_scoped_test_votes_score).to eq(1)
423
+ votable_cache.vote_by voter: voter2, vote: "false", vote_scope: "test"
424
+ expect(votable_cache.cached_scoped_test_votes_score).to eq(0)
425
+ votable_cache.vote_by voter: voter, vote: "false", vote_scope: "test"
426
+ expect(votable_cache.cached_scoped_test_votes_score).to eq(-2)
427
+ end
428
+
429
+ it "should update cached score votes_for when a vote up is removed" do
430
+ votable_cache.vote_by voter: voter, vote: "true", vote_scope: "test"
431
+ expect(votable_cache.cached_scoped_test_votes_score).to eq(1)
432
+ votable_cache.unvote voter: voter, vote_scope: "test"
433
+ expect(votable_cache.cached_scoped_test_votes_score).to eq(0)
434
+ end
435
+
436
+ it "should update cached score votes_for when a vote down is removed" do
437
+ votable_cache.vote_by voter: voter, vote: "false", vote_scope: "test"
438
+ expect(votable_cache.cached_scoped_test_votes_score).to eq(-1)
439
+ votable_cache.unvote voter: voter, vote_scope: "test"
440
+ expect(votable_cache.cached_scoped_test_votes_score).to eq(0)
441
+ end
442
+
443
+ it "should update cached up votes_for if there is an up vote column" do
444
+ votable_cache.cached_scoped_test_votes_up = 50
445
+ votable_cache.vote_by voter: voter, vote_scope: "test"
446
+ votable_cache.vote_by voter: voter, vote_scope: "test"
447
+ expect(votable_cache.cached_scoped_test_votes_up).to eq(1)
448
+ end
449
+
450
+ it "should update cached down votes_for if there is a down vote column" do
451
+ votable_cache.cached_scoped_test_votes_down = 50
452
+ votable_cache.vote_by voter: voter, vote: "false", vote_scope: "test"
453
+ expect(votable_cache.cached_scoped_test_votes_down).to eq(1)
454
+ end
455
+
456
+ it "should update cached up votes_for when a vote up is removed" do
457
+ votable_cache.vote_by voter: voter, vote: "true", vote_scope: "test"
458
+ votable_cache.unvote voter: voter, vote_scope: "test"
459
+ expect(votable_cache.cached_scoped_test_votes_up).to eq(0)
460
+ end
461
+
462
+ it "should update cached down votes_for when a vote down is removed" do
463
+ votable_cache.vote_by voter: voter, vote: "false", vote_scope: "test"
464
+ votable_cache.unvote voter: voter, vote_scope: "test"
465
+ expect(votable_cache.cached_scoped_test_votes_down).to eq(0)
466
+ end
467
+
468
+ it "should select from cached total votes_for if there a total column" do
469
+ votable_cache.vote_by voter: voter, vote_scope: "test"
470
+ votable_cache.cached_scoped_test_votes_total = 50
471
+ expect(votable_cache.count_votes_total(false, "test")).to eq(50)
472
+ end
473
+
474
+ it "should select from cached up votes_for if there is an up vote column" do
475
+ votable_cache.vote_by voter: voter, vote_scope: "test"
476
+ votable_cache.cached_scoped_test_votes_up = 50
477
+ expect(votable_cache.count_votes_up(false, "test")).to eq(50)
478
+ end
479
+
480
+ it "should select from cached down votes_for if there is a down vote column" do
481
+ votable_cache.vote_by voter: voter, vote: "false", vote_scope: "test"
482
+ votable_cache.cached_scoped_test_votes_down = 50
483
+ expect(votable_cache.count_votes_down(false, "test")).to eq(50)
484
+ end
485
+
486
+ end
487
+
488
+ describe "sti models" do
489
+ let(:child_sti_not_votable) { create(:child_of_sti_not_votable, name: "sti child") }
490
+ let(:child_sti_votable) { create(:child_of_sti_votable, name: "sti child") }
491
+
492
+ it "should be able to vote on a votable child of a non votable sti model" do
493
+ child_sti_not_votable.vote_by voter: voter, vote: "yes"
494
+ expect(child_sti_not_votable.votes_for.size).to eq(1)
495
+ end
496
+
497
+ it "should not be able to vote on a parent non votable" do
498
+ expect(StiNotVotable).not_to be_votable
499
+ end
500
+
501
+ it "should be able to vote on a child when its parent is votable" do
502
+ child_sti_votable.vote_by voter: voter, vote: "yes"
503
+ expect(child_sti_votable.votes_for.size).to eq(1)
504
+ end
505
+ end
506
+ end