jy-acts_as_votable 0.3.1

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.
@@ -0,0 +1,36 @@
1
+ module ActsAsVotable::Helpers
2
+
3
+ # this helper provides methods that help find what words are
4
+ # up votes and what words are down votes
5
+ #
6
+ # It can be called
7
+ #
8
+ # votable_object.votable_words.that_mean_true
9
+ #
10
+ module Words
11
+
12
+ def votable_words
13
+ VotableWords
14
+ end
15
+
16
+ end
17
+
18
+ class VotableWords
19
+
20
+ def self.that_mean_true
21
+ ['up', 'upvote', 'like', 'liked', 'positive', 'yes', 'good', 'true', 1, true]
22
+ end
23
+
24
+ def self.that_mean_false
25
+ ['down', 'downvote', 'dislike', 'disliked', 'negative', 'no', 'bad', 'false', 0, false]
26
+ end
27
+
28
+ # check is word is a true or bad vote
29
+ # if the word is unknown, then it counts it as a true/good
30
+ # vote. this exists to allow all voting to be good by default
31
+ def self.meaning_of word
32
+ !that_mean_false.include?(word)
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,3 @@
1
+ module ActsAsVotable
2
+ VERSION = "0.3.1"
3
+ end
@@ -0,0 +1,195 @@
1
+ require 'acts_as_votable/helpers/words'
2
+
3
+ module ActsAsVotable
4
+ module Votable
5
+
6
+ include Helpers::Words
7
+
8
+ def self.included base
9
+
10
+ # allow the user to define these himself
11
+ aliases = {
12
+
13
+ :vote_up => [
14
+ :up_by, :upvote_by, :like_by, :liked_by, :vote_by,
15
+ :up_from, :upvote_from, :upvote_by, :like_from, :liked_from, :vote_from
16
+ ],
17
+
18
+ :vote_down => [
19
+ :down_by, :downvote_by, :dislike_by, :disliked_by,
20
+ :down_from, :downvote_from, :downvote_by, :dislike_by, :disliked_by
21
+ ],
22
+
23
+ :up_votes => [
24
+ :true_votes, :ups, :upvotes, :likes, :positives, :for_votes,
25
+ ],
26
+
27
+ :down_votes => [
28
+ :false_votes, :downs, :downvotes, :dislikes, :negatives
29
+ ],
30
+ :unvote => [
31
+ :unliked_by, :undisliked_by
32
+ ]
33
+ }
34
+
35
+ base.class_eval do
36
+
37
+ belongs_to :votable, :polymorphic => true
38
+ has_many :votes, :class_name => "ActsAsVotable::Vote", :as => :votable do
39
+ def voters
40
+ includes(:voter).map(&:voter)
41
+ end
42
+ end
43
+
44
+ aliases.each do |method, links|
45
+ links.each do |new_method|
46
+ alias_method(new_method, method)
47
+ end
48
+ end
49
+
50
+ end
51
+ end
52
+
53
+ attr_accessor :vote_registered
54
+
55
+ def vote_registered?
56
+ return self.vote_registered
57
+ end
58
+
59
+ def default_conditions
60
+ {
61
+ :votable_id => self.id,
62
+ :votable_type => self.class.base_class.name.to_s
63
+ }
64
+ end
65
+
66
+ # voting
67
+ def vote args = {}
68
+
69
+ options = {
70
+ :vote => true,
71
+ }.merge(args)
72
+
73
+ self.vote_registered = false
74
+
75
+ if options[:voter].nil?
76
+ return false
77
+ end
78
+
79
+ # find the vote
80
+ _votes_ = find_votes({
81
+ :voter_id => options[:voter].id,
82
+ :voter_type => options[:voter].class.name
83
+ })
84
+
85
+ if _votes_.count == 0
86
+ # this voter has never voted
87
+ vote = ActsAsVotable::Vote.new(
88
+ :votable => self,
89
+ :voter => options[:voter]
90
+ )
91
+ else
92
+ # this voter is potentially changing his vote
93
+ vote = _votes_.first
94
+ end
95
+
96
+ last_update = vote.updated_at
97
+
98
+ vote.vote_flag = votable_words.meaning_of(options[:vote])
99
+
100
+ if vote.save
101
+ self.vote_registered = true if last_update != vote.updated_at
102
+ update_cached_votes
103
+ return true
104
+ else
105
+ self.vote_registered = false
106
+ return false
107
+ end
108
+
109
+ end
110
+
111
+ def unvote args = {}
112
+ return false if args[:voter].nil?
113
+ _votes_ = find_votes(:voter_id => args[:voter].id, :voter_type => args[:voter].class.name)
114
+
115
+ return true if _votes_.size == 0
116
+ _votes_.each(&:destroy)
117
+ update_cached_votes
118
+ self.vote_registered = false if votes.count == 0
119
+ return true
120
+ end
121
+
122
+ def vote_up voter
123
+ self.vote :voter => voter, :vote => true
124
+ end
125
+
126
+ def vote_down voter
127
+ self.vote :voter => voter, :vote => false
128
+ end
129
+
130
+ # caching
131
+ def update_cached_votes
132
+
133
+ updates = {}
134
+
135
+ if self.respond_to?(:cached_votes_total=)
136
+ updates[:cached_votes_total] = count_votes_total(true)
137
+ end
138
+
139
+ if self.respond_to?(:cached_votes_up=)
140
+ updates[:cached_votes_up] = count_votes_up(true)
141
+ end
142
+
143
+ if self.respond_to?(:cached_votes_down=)
144
+ updates[:cached_votes_down] = count_votes_down(true)
145
+ end
146
+
147
+ self.update_attributes(updates, :without_protection => true) if updates.size > 0
148
+
149
+ end
150
+
151
+
152
+ # results
153
+ def find_votes extra_conditions = {}
154
+ votes.where(extra_conditions)
155
+ end
156
+
157
+ def up_votes
158
+ find_votes(:vote_flag => true)
159
+ end
160
+
161
+ def down_votes
162
+ find_votes(:vote_flag => false)
163
+ end
164
+
165
+
166
+ # counting
167
+ def count_votes_total skip_cache = false
168
+ if !skip_cache && self.respond_to?(:cached_votes_total)
169
+ return self.send(:cached_votes_total)
170
+ end
171
+ find_votes.count
172
+ end
173
+
174
+ def count_votes_up skip_cache = false
175
+ if !skip_cache && self.respond_to?(:cached_votes_up)
176
+ return self.send(:cached_votes_up)
177
+ end
178
+ up_votes.count
179
+ end
180
+
181
+ def count_votes_down skip_cache = false
182
+ if !skip_cache && self.respond_to?(:cached_votes_down)
183
+ return self.send(:cached_votes_down)
184
+ end
185
+ down_votes.count
186
+ end
187
+
188
+ # voters
189
+ def voted_on_by? voter
190
+ votes = find_votes :voter_id => voter.id, :voter_type => voter.class.name
191
+ votes.count > 0
192
+ end
193
+
194
+ end
195
+ end
@@ -0,0 +1,27 @@
1
+ require 'acts_as_votable/helpers/words'
2
+
3
+ module ActsAsVotable
4
+ class Vote < ::ActiveRecord::Base
5
+
6
+ include Helpers::Words
7
+
8
+ attr_accessible :votable_id, :votable_type,
9
+ :voter_id, :voter_type,
10
+ :votable, :voter,
11
+ :vote_flag
12
+
13
+ belongs_to :votable, :polymorphic => true
14
+ belongs_to :voter, :polymorphic => true
15
+
16
+ scope :up, where(:vote_flag => true)
17
+ scope :down, where(:vote_flag => false)
18
+ scope :for_type, lambda{ |klass| where(:votable_type => klass) }
19
+ scope :by_type, lambda{ |klass| where(:voter_type => klass) }
20
+
21
+ validates_presence_of :votable_id
22
+ validates_presence_of :voter_id
23
+
24
+ end
25
+
26
+ end
27
+
@@ -0,0 +1,100 @@
1
+ module ActsAsVotable
2
+ module Voter
3
+
4
+ def self.included(base)
5
+
6
+ # allow user to define these
7
+ aliases = {
8
+ :vote_up_for => [:likes, :upvotes, :up_votes],
9
+ :vote_down_for => [:dislikes, :downvotes, :down_votes],
10
+ :unvote_for => [:unlike, :undislike]
11
+ }
12
+
13
+ base.class_eval do
14
+
15
+ belongs_to :voter, :polymorphic => true
16
+ has_many :votes, :class_name => "ActsAsVotable::Vote", :as => :voter do
17
+ def votables
18
+ includes(:votable).map(&:votable)
19
+ end
20
+ end
21
+
22
+ aliases.each do |method, links|
23
+ links.each do |new_method|
24
+ alias_method(new_method, method)
25
+ end
26
+ end
27
+
28
+ end
29
+
30
+ end
31
+
32
+ # voting
33
+ def vote args
34
+ args[:votable].vote args.merge({:voter => self})
35
+ end
36
+
37
+ def vote_up_for model=nil
38
+ vote :votable => model, :vote => true
39
+ end
40
+
41
+ def vote_down_for model
42
+ vote :votable => model, :vote => false
43
+ end
44
+
45
+ def unvote_for model
46
+ model.unvote :voter => self
47
+ end
48
+
49
+ # results
50
+ def voted_on? votable
51
+ votes = find_votes(:votable_id => votable.id, :votable_type => votable.class.base_class.name)
52
+ votes.size > 0
53
+ end
54
+ alias :voted_for? :voted_on?
55
+
56
+ def voted_up_on? votable
57
+ votes = find_votes(:votable_id => votable.id, :votable_type => votable.class.base_class.name, :vote_flag => true)
58
+ votes.size > 0
59
+ end
60
+ alias :voted_up_for? :voted_up_on?
61
+
62
+ def voted_down_on? votable
63
+ votes = find_votes(:votable_id => votable.id, :votable_type => votable.class.base_class.name, :vote_flag => false)
64
+ votes.size > 0
65
+ end
66
+ alias :voted_down_for? :voted_down_on?
67
+
68
+ def voted_as_when_voting_on votable
69
+ votes = find_votes(:votable_id => votable.id, :votable_type => votable.class.base_class.name)
70
+ return nil if votes.size == 0
71
+ return votes.first.vote_flag
72
+ end
73
+ alias :voted_as_when_voted_for :voted_as_when_voting_on
74
+
75
+ def find_votes extra_conditions = {}
76
+ votes.where(extra_conditions)
77
+ end
78
+
79
+ def find_up_votes
80
+ find_votes :vote_flag => true
81
+ end
82
+
83
+ def find_down_votes
84
+ find_votes :vote_flag => false
85
+ end
86
+
87
+ def find_votes_for_class klass, extra_conditions = {}
88
+ find_votes extra_conditions.merge({:votable_type => klass.name})
89
+ end
90
+
91
+ def find_up_votes_for_class klass
92
+ find_votes_for_class klass, :vote_flag => true
93
+ end
94
+
95
+ def find_down_votes_for_class klass
96
+ find_votes_for_class klass, :vote_flag => false
97
+ end
98
+
99
+ end
100
+ end
@@ -0,0 +1,31 @@
1
+ require 'rails/generators/migration'
2
+
3
+ module ActsAsVotable
4
+ class MigrationGenerator < Rails::Generators::Base
5
+ include Rails::Generators::Migration
6
+
7
+ desc "Generates migration for votable (votes table)"
8
+
9
+ def self.orm
10
+ Rails::Generators.options[:rails][:orm]
11
+ end
12
+
13
+ def self.source_root
14
+ File.join(File.dirname(__FILE__), 'templates', (orm.to_s unless orm.class.eql?(String)) )
15
+ end
16
+
17
+ def self.orm_has_migration?
18
+ [:active_record].include? orm
19
+ end
20
+
21
+ def self.next_migration_number(path)
22
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
23
+ end
24
+
25
+ def create_migration_file
26
+ if self.class.orm_has_migration?
27
+ migration_template 'migration.rb', 'db/migrate/acts_as_votable_migration'
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,20 @@
1
+ class ActsAsVotableMigration < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :votes do |t|
4
+
5
+ t.references :votable, :polymorphic => true
6
+ t.references :voter, :polymorphic => true
7
+
8
+ t.boolean :vote_flag
9
+
10
+ t.timestamps
11
+ end
12
+
13
+ add_index :votes, [:votable_id, :votable_type]
14
+ add_index :votes, [:voter_id, :voter_type]
15
+ end
16
+
17
+ def self.down
18
+ drop_table :votes
19
+ end
20
+ end
@@ -0,0 +1,103 @@
1
+ $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
2
+ require 'acts_as_votable'
3
+
4
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
5
+
6
+ ActiveRecord::Schema.define(:version => 1) do
7
+ create_table :votes do |t|
8
+ t.references :votable, :polymorphic => true
9
+ t.references :voter, :polymorphic => true
10
+
11
+ t.boolean :vote_flag
12
+
13
+ t.timestamps
14
+ end
15
+
16
+ add_index :votes, [:votable_id, :votable_type]
17
+ add_index :votes, [:voter_id, :voter_type]
18
+
19
+ create_table :voters do |t|
20
+ t.string :name
21
+ end
22
+
23
+ create_table :not_voters do |t|
24
+ t.string :name
25
+ end
26
+
27
+ create_table :votables do |t|
28
+ t.string :name
29
+ end
30
+
31
+ create_table :sti_votables do |t|
32
+ t.string :name
33
+ t.string :type
34
+ end
35
+
36
+ create_table :sti_not_votables do |t|
37
+ t.string :name
38
+ t.string :type
39
+ end
40
+
41
+ create_table :not_votables do |t|
42
+ t.string :name
43
+ end
44
+
45
+ create_table :votable_caches do |t|
46
+ t.string :name
47
+ t.integer :cached_votes_total
48
+ t.integer :cached_votes_up
49
+ t.integer :cached_votes_down
50
+ end
51
+
52
+ end
53
+
54
+
55
+ class Voter < ActiveRecord::Base
56
+ acts_as_voter
57
+ end
58
+
59
+ class NotVoter < ActiveRecord::Base
60
+
61
+ end
62
+
63
+ class Votable < ActiveRecord::Base
64
+ acts_as_votable
65
+ validates_presence_of :name
66
+ end
67
+
68
+ class StiVotable < ActiveRecord::Base
69
+ acts_as_votable
70
+ end
71
+
72
+ class ChildOfStiVotable < StiVotable
73
+ end
74
+
75
+ class StiNotVotable < ActiveRecord::Base
76
+ validates_presence_of :name
77
+ end
78
+
79
+ class VotableChildOfStiNotVotable < StiNotVotable
80
+ acts_as_votable
81
+ end
82
+
83
+ class NotVotable < ActiveRecord::Base
84
+ end
85
+
86
+ class VotableCache < ActiveRecord::Base
87
+ acts_as_votable
88
+ validates_presence_of :name
89
+ end
90
+
91
+ class ABoringClass
92
+ def self.hw
93
+ 'hello world'
94
+ end
95
+ end
96
+
97
+
98
+ def clean_database
99
+ models = [ActsAsVotable::Vote, Voter, NotVoter, Votable, NotVotable, VotableCache]
100
+ models.each do |model|
101
+ ActiveRecord::Base.connection.execute "DELETE FROM #{model.table_name}"
102
+ end
103
+ end