kandadaboggu-vote_fu 0.0.13 → 0.0.14
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.markdown +6 -1
- data/README.markdown +25 -7
- data/lib/acts_as_voteable.rb +48 -21
- metadata +1 -1
data/CHANGELOG.markdown
CHANGED
@@ -1,6 +1,11 @@
|
|
1
|
+
2010-02-21
|
2
|
+
==========
|
3
|
+
* Changed the `tally` method to add support for `at_least_total` and `at_most_total` parameters to filter by sum of votes.
|
4
|
+
* Changed the `tally` method to add support for `total` column in :order paramter.
|
5
|
+
|
1
6
|
2010-02-20
|
2
7
|
==========
|
3
|
-
* Changed the data-type of `vote` column in `votes` table to integer type.
|
8
|
+
* Changed the data-type of the `vote` column in the `votes` table to integer type.
|
4
9
|
* Added support for vote count caching at the `voteable` model.
|
5
10
|
* Added new method `votes_total` on `voteable` model to return the sum of +ve and -ve votes
|
6
11
|
* Optimized several methods in `voteable` model (`voters_who_voted`, `voted_by?`)
|
data/README.markdown
CHANGED
@@ -21,12 +21,14 @@ This plugin started as an adaptation / update of act\_as\_voteable. It has grown
|
|
21
21
|
5. Adds "has\_karma" mixin for identifying key content contributors
|
22
22
|
|
23
23
|
### Difference between original vote_fu
|
24
|
-
1. The data-type of `vote` column in `votes` table is changed to integer type.
|
24
|
+
1. The data-type of the `vote` column in the `votes` table is changed to integer type.
|
25
25
|
2. Support for vote count caching at the `voteable` model.
|
26
26
|
3. New method `votes_total` on `voteable` model to return the sum of +ve and -ve votes
|
27
27
|
4. Optimized several methods in `voteable` model (`voters_who_voted`, `voted_by?`)
|
28
28
|
5. Code cleanup to use associations instead of direct SQL
|
29
|
-
|
29
|
+
6. The `tally` method supports `at_least_total` and `at_most_total` parameters to
|
30
|
+
filter by sum of votes.
|
31
|
+
7. The :order option of the `tally` method supports order by `total` (E.g: :order => "toal DESC")
|
30
32
|
Installation
|
31
33
|
============
|
32
34
|
Use either the plugin or the gem installation method depending on your preference. If you're not sure, the plugin method is simpler. Whichever you choose, create the migration afterward and run it to create the required model.
|
@@ -61,7 +63,7 @@ Usage
|
|
61
63
|
end
|
62
64
|
|
63
65
|
class Post < ActiveRecord::Base
|
64
|
-
acts_as_voteable :vote_counter => true # Stores the sum of the votes in the `
|
66
|
+
acts_as_voteable :vote_counter => true # Stores the sum of the votes in the `vote_total`
|
65
67
|
# column of the `posts` table.
|
66
68
|
end
|
67
69
|
|
@@ -109,17 +111,33 @@ You can easily retrieve voteable object collections based on the properties of t
|
|
109
111
|
:limit => 10,
|
110
112
|
:order => "items.name desc"
|
111
113
|
})
|
112
|
-
|
113
114
|
This will select the Items with between 1 and 10,000 votes, the votes having been cast within the last two weeks (not including today), then display the 10 last items in an alphabetical list.
|
114
115
|
|
116
|
+
@items = Item.tally(
|
117
|
+
{ :at_least_total => 1,
|
118
|
+
:at_most_total => 10000,
|
119
|
+
:start_at => 2.weeks.ago,
|
120
|
+
:end_at => 1.day.ago,
|
121
|
+
:limit => 10,
|
122
|
+
:order => "total desc"
|
123
|
+
})
|
124
|
+
This will select the Items with between 1 and 10,000 total votes, the votes having been cast within the last two weeks (not including today), then display the 10 last items in a descending order list by total votes.
|
125
|
+
|
126
|
+
|
115
127
|
##### Tally Options:
|
116
128
|
:start_at - Restrict the votes to those created after a certain time
|
117
129
|
:end_at - Restrict the votes to those created before a certain time
|
118
130
|
:conditions - A piece of SQL conditions to add to the query
|
119
131
|
:limit - The maximum number of voteables to return
|
120
|
-
:order - A piece of SQL to order by.
|
121
|
-
|
122
|
-
|
132
|
+
:order - A piece of SQL to order by. Two calculated columns `count`, and `total`
|
133
|
+
are available for sorting apart from other columns. Defaults to `total DESC`.
|
134
|
+
Eg: :order => 'count desc'
|
135
|
+
:order => 'total desc'
|
136
|
+
:order => 'post.created_at desc'
|
137
|
+
:at_least - Item must have at least X votes count
|
138
|
+
:at_most - Item may not have more than X votes count
|
139
|
+
:at_least_total - Item must have at least X votes total
|
140
|
+
:at_most_total - Item may not have more than X votes total
|
123
141
|
|
124
142
|
#### Lower level queries
|
125
143
|
ActiveRecord models that act as voteable can be queried for the positive votes, negative votes, and a total vote count by using the votes\_for, votes\_against, and votes\_count methods respectively. Here is an example:
|
data/lib/acts_as_voteable.rb
CHANGED
@@ -11,7 +11,7 @@ module Juixe
|
|
11
11
|
#
|
12
12
|
# Options:
|
13
13
|
# :vote_counter
|
14
|
-
# Model stores the sum of votes in the vote counter column when the value is true. This requires a column named `
|
14
|
+
# Model stores the sum of votes in the vote counter column when the value is true. This requires a column named `vote_total` in the table corresponding to `voteable` model.
|
15
15
|
# You can also specify a custom vote counter column by providing a column name instead of a true/false value to this option (e.g., :vote_counter => :my_custom_counter.)
|
16
16
|
# Note: Specifying a counter will add it to that model‘s list of readonly attributes using attr_readonly.
|
17
17
|
#
|
@@ -23,10 +23,18 @@ module Juixe
|
|
23
23
|
Vote.send(:include, Juixe::Acts::Voteable::VoteCounterClassMethods) unless Vote.respond_to?(:vote_counters)
|
24
24
|
Vote.vote_counters = [self]
|
25
25
|
# define vote_counter_column instance method on voteable
|
26
|
-
|
27
|
-
|
26
|
+
counter_column_name = (options[:vote_counter] == true) ? :vote_total : options[:vote_counter]
|
27
|
+
class_eval <<-EOS
|
28
|
+
def self.vote_counter_column # def self.vote_counter_column
|
29
|
+
:"#{counter_column_name}" # :vote_total
|
30
|
+
end # end
|
31
|
+
def vote_counter_column
|
32
|
+
self.class.vote_counter_column
|
33
|
+
end
|
34
|
+
EOS
|
35
|
+
|
28
36
|
define_method(:reload_vote_counter) {reload(:select => vote_counter_column.to_s)}
|
29
|
-
attr_readonly
|
37
|
+
attr_readonly counter_column_name
|
30
38
|
end
|
31
39
|
end
|
32
40
|
end
|
@@ -49,31 +57,41 @@ module Juixe
|
|
49
57
|
module SingletonMethods
|
50
58
|
|
51
59
|
# Calculate the vote counts for all voteables of my type.
|
52
|
-
def tally(options = {})
|
53
|
-
find(:all, options_for_tally({:order =>"count DESC" }.merge(options)))
|
54
|
-
end
|
55
|
-
|
56
|
-
#
|
57
60
|
# Options:
|
58
61
|
# :start_at - Restrict the votes to those created after a certain time
|
59
62
|
# :end_at - Restrict the votes to those created before a certain time
|
60
63
|
# :conditions - A piece of SQL conditions to add to the query
|
61
64
|
# :limit - The maximum number of voteables to return
|
62
|
-
# :order - A piece of SQL to order by.
|
63
|
-
#
|
64
|
-
#
|
65
|
+
# :order - A piece of SQL to order by. Two calculated columns `count`, and `total`
|
66
|
+
# are available for sorting apart from other columns. Defaults to `total DESC`.
|
67
|
+
# Eg: :order => 'count desc'
|
68
|
+
# :order => 'total desc'
|
69
|
+
# :order => 'post.created_at desc'
|
70
|
+
# :at_least - Item must have at least X votes count
|
71
|
+
# :at_most - Item may not have more than X votes count
|
72
|
+
# :at_least_total - Item must have at least X votes total
|
73
|
+
# :at_most_total - Item may not have more than X votes total
|
74
|
+
def tally(options = {})
|
75
|
+
find(:all, options_for_tally({:order =>"total DESC" }.merge(options)))
|
76
|
+
end
|
77
|
+
|
65
78
|
def options_for_tally (options = {})
|
66
|
-
options.assert_valid_keys :start_at, :end_at, :conditions, :at_least, :at_most, :order, :limit
|
79
|
+
options.assert_valid_keys :start_at, :end_at, :conditions, :at_least, :at_most, :order, :limit, :at_least_total, :at_most_total
|
67
80
|
|
68
81
|
scope = scope(:find)
|
69
82
|
start_at = sanitize_sql(["#{Vote.table_name}.created_at >= ?", options.delete(:start_at)]) if options[:start_at]
|
70
83
|
end_at = sanitize_sql(["#{Vote.table_name}.created_at <= ?", options.delete(:end_at)]) if options[:end_at]
|
71
84
|
|
72
|
-
|
73
|
-
|
85
|
+
if respond_to?(:vote_counter_column)
|
86
|
+
# use the counter cache column if present.
|
87
|
+
total_col = "#{table_name}.#{vote_counter_column}"
|
88
|
+
at_least_total = sanitize_sql(["#{total_col} >= ?", options.delete(:at_least_total)]) if options[:at_least_total]
|
89
|
+
at_most_total = sanitize_sql(["#{total_col} <= ?", options.delete(:at_most_total)]) if options[:at_most_total]
|
90
|
+
end
|
74
91
|
conditions = [
|
75
|
-
type_and_context,
|
76
92
|
options[:conditions],
|
93
|
+
at_least_total,
|
94
|
+
at_most_total,
|
77
95
|
start_at,
|
78
96
|
end_at
|
79
97
|
]
|
@@ -81,20 +99,29 @@ module Juixe
|
|
81
99
|
conditions = conditions.compact.join(' AND ')
|
82
100
|
conditions = merge_conditions(conditions, scope[:conditions]) if scope
|
83
101
|
|
84
|
-
|
102
|
+
type_and_context = "#{Vote.table_name}.voteable_type = #{quote_value(base_class.name)}"
|
103
|
+
joins = ["LEFT OUTER JOIN #{Vote.table_name} ON #{table_name}.#{primary_key} = #{Vote.table_name}.voteable_id AND #{type_and_context}"]
|
85
104
|
joins << scope[:joins] if scope && scope[:joins]
|
86
105
|
at_least = sanitize_sql(["COUNT(#{Vote.table_name}.id) >= ?", options.delete(:at_least)]) if options[:at_least]
|
87
106
|
at_most = sanitize_sql(["COUNT(#{Vote.table_name}.id) <= ?", options.delete(:at_most)]) if options[:at_most]
|
88
|
-
|
107
|
+
at_least_total = at_most_total = nil # reset the values
|
108
|
+
unless respond_to?(:vote_counter_column)
|
109
|
+
# aggregate the votes when counter cache is absent.
|
110
|
+
total_col = "SUM(#{Vote.table_name}.vote)"
|
111
|
+
at_least_total = sanitize_sql(["#{total_col} >= ?", options.delete(:at_least_total)]) if options[:at_least_total]
|
112
|
+
at_most_total = sanitize_sql(["#{total_col} <= ?", options.delete(:at_most_total)]) if options[:at_most_total]
|
113
|
+
end
|
114
|
+
having = [at_least, at_most, at_least_total, at_most_total].compact.join(' AND ')
|
89
115
|
group_by = "#{Vote.table_name}.voteable_id HAVING COUNT(#{Vote.table_name}.id) > 0"
|
90
116
|
group_by << " AND #{having}" unless having.blank?
|
91
|
-
|
92
|
-
{ :select => "#{table_name}.*, COUNT(#{Vote.table_name}.id) AS count",
|
117
|
+
|
118
|
+
{ :select => "#{table_name}.*, COUNT(#{Vote.table_name}.id) AS count, #{total_col} AS total",
|
93
119
|
:joins => joins.join(" "),
|
94
120
|
:conditions => conditions,
|
95
121
|
:group => group_by
|
96
122
|
}.update(options)
|
97
123
|
end
|
124
|
+
|
98
125
|
end
|
99
126
|
|
100
127
|
# This module contains instance methods
|
@@ -127,4 +154,4 @@ module Juixe
|
|
127
154
|
end
|
128
155
|
end
|
129
156
|
end
|
130
|
-
end
|
157
|
+
end
|