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 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 `vote_count`
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. Eg 'votes.count desc' or 'voteable.created_at desc'
121
- :at_least - Item must have at least X votes
122
- :at_most - Item may not have more than X votes
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:
@@ -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 `vote_count` in the table corresponding to `voteable` model.
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
- vote_counter_column = (options[:vote_counter] == true) ? :vote_count : options[:vote_counter]
27
- define_method(:vote_counter_column) {vote_counter_column}
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 vote_counter_column
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. Eg 'votes.count desc' or 'voteable.created_at desc'
63
- # :at_least - Item must have at least X votes
64
- # :at_most - Item may not have more than X votes
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
- type_and_context = "#{Vote.table_name}.voteable_type = #{quote_value(base_class.name)}"
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
- joins = ["LEFT OUTER JOIN #{Vote.table_name} ON #{table_name}.#{primary_key} = #{Vote.table_name}.voteable_id"]
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
- having = [at_least, at_most].compact.join(' AND ')
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
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kandadaboggu-vote_fu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.13
4
+ version: 0.0.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Jackson