Permalink
Browse files

Query improvements for the find_by_rating method

git-svn-id: svn://rubyforge.org/var/svn/acts-as-rated/trunk/acts_as_rated@3 d2fe85f9-699c-4bcc-83cd-509c172d722e
  • Loading branch information...
guynaor
guynaor committed Mar 9, 2007
1 parent 1324a90 commit 4766c86bf997a4740afcf006e88ba8f2a0e9255f
Showing with 46 additions and 9 deletions.
  1. +4 −0 README
  2. +28 −8 lib/acts_as_rated.rb
  3. +14 −1 test/rated_test.rb
View
4 README
@@ -56,6 +56,10 @@ Contact me at
* guy.naor@famundo.com
+== Changes
+* V3 - Added improved find_by_rating as proposed by Ian McIntosh
+* V2 - Passing MySQL tests, check if rated by a specific rater as proposed by Tiago Serafim
+
== TODO
* Test with more databases
* Test with other versions of Rails (tested against 1.2.1)
View
@@ -384,29 +384,49 @@ def find_rated_by rater
# Find by rating - pass either a specific value or a range and the precision to calculate with
# * <tt>value</tt> - the value to look for or a range
# * <tt>precision</tt> - number of decimal digits to round to. Default to 10. Use 0 for integer numbers comparision
- def find_by_rating value, precision = 10
+ # * <tt>round_it</tt> - round the rating average before comparing?. Defaults to true. Passing false will result in a faster query
+ def find_by_rating value, precision = 10, round = true
rating_class = acts_as_rated_options[:rating_class].constantize
if column_names.include? "rating_avg"
if Range === value
- conds = [ 'round(rating_avg, ?) >= ? AND round(rating_avg, ?) <= ?',
- precision.to_i, connection.quote(value.begin), precision.to_i, connection.quote(value.end) ]
+ conds = round ? [ 'round(rating_avg, ?) BETWEEN ? AND ?', precision.to_i, value.begin, value.end ] :
+ [ 'rating_avg BETWEEN ? AND ?', value.begin, value.end ]
else
- conds = [ 'round(rating_avg, ?) = ?', precision.to_i, connection.quote(value) ]
+ conds = round ? [ 'round(rating_avg, ?) = ?', precision.to_i, value ] : [ 'rating_avg = ?', value ]
end
find :all, :conditions => conds
else
- base_sql = <<-EOS
+ if round
+ base_sql = <<-EOS
select #{table_name}.*,round(COALESCE(average,0), #{precision.to_i}) AS rating_average from #{table_name} left outer join
(select avg(rating) as average, rated_id
from #{rating_class.table_name}
where rated_type = '#{class_name}'
group by rated_id) as rated
on rated_id=id
- EOS
+ EOS
+ else
+ base_sql = <<-EOS
+ select #{table_name}.*,COALESCE(average,0) AS rating_average from #{table_name} left outer join
+ (select avg(rating) as average, rated_id
+ from #{rating_class.table_name}
+ where rated_type = '#{class_name}'
+ group by rated_id) as rated
+ on rated_id=id
+ EOS
+ end
if Range === value
- where_part = " WHERE round(COALESCE(average,0), #{precision.to_i}) BETWEEN #{connection.quote(value.begin)} AND #{connection.quote(value.end)}"
+ if round
+ where_part = " WHERE round(COALESCE(average,0), #{precision.to_i}) BETWEEN #{connection.quote(value.begin)} AND #{connection.quote(value.end)}"
+ else
+ where_part = " WHERE COALESCE(average,0) BETWEEN #{connection.quote(value.begin)} AND #{connection.quote(value.end)}"
+ end
else
- where_part = " WHERE round(COALESCE(average,0), #{precision.to_i}) = #{connection.quote(value)}"
+ if round
+ where_part = " WHERE round(COALESCE(average,0), #{precision.to_i}) = #{connection.quote(value)}"
+ else
+ where_part = " WHERE COALESCE(average,0) = #{connection.quote(value)}"
+ end
end
find_by_sql base_sql + where_part
View
@@ -342,7 +342,13 @@ def test_find_by_rating
check_returned_array cs, ['Toyota Camry', 'VW Golf', 'VW Bug']
fs = Film.find_by_rating 1..4, 0
check_returned_array fs, ["Rambo 3", "Gone With The Wind", "Phantom Menace"]
- ms = Movie.find_by_rating 5
+ cs = Car.find_by_rating 3..4, 0, false
+ check_returned_array cs, ['Toyota Camry', 'VW Golf', 'VW Bug']
+ cs = Car.find_by_rating 3..4.5, 0, false
+ check_returned_array cs, ['Toyota Camry', 'VW Golf', 'Carrera', 'VW Bug']
+ fs = Film.find_by_rating 1..4, 0, false
+ check_returned_array fs, ["Rambo 3", "Phantom Menace"]
+ ms = Movie.find_by_rating 5
check_returned_array ms, ["The Wizard of Oz"]
bs = Book.find_by_rating 3..3.7
check_returned_array bs, ["Alice in Wonderland", "Aminal Farm", "The Lord of the Rings", "Catch 22"]
@@ -352,6 +358,13 @@ def test_find_by_rating
check_returned_array bs, ["Alice in Wonderland", "Aminal Farm", "The Lord of the Rings"]
bs = Book.find_by_rating 3, 0
check_returned_array bs, ["Alice in Wonderland", "Aminal Farm", "The Lord of the Rings"]
+
+ bs = Book.find_by_rating 3..3.7, 0, false
+ check_returned_array bs, ["Alice in Wonderland", "Aminal Farm", "The Lord of the Rings", "Catch 22"]
+ bs = Book.find_by_rating 1..3.3, 0, false
+ check_returned_array bs, ["Alice in Wonderland", "Aminal Farm", "The Lord of the Rings"]
+ bs = Book.find_by_rating 3.75, 0, false
+ check_returned_array bs, ["Shogun"]
end
def test_find_rated_by

0 comments on commit 4766c86

Please sign in to comment.