Skip to content
This repository has been archived by the owner on Dec 1, 2017. It is now read-only.

Commit

Permalink
add association calculation method to order by results of a sql funct…
Browse files Browse the repository at this point in the history
…ion on a column of a joined table
  • Loading branch information
mjankowski committed Jan 20, 2011
1 parent b0b56b1 commit b4abc54
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 4 deletions.
12 changes: 12 additions & 0 deletions README.md
Expand Up @@ -56,6 +56,7 @@ Assuming a database schema...
create_table :comments, :force => true do |t| create_table :comments, :force => true do |t|
t.integer :user_id t.integer :user_id
t.text :description t.text :description
t.integer :rating
t.timestamps t.timestamps
end end
end end
Expand All @@ -71,6 +72,7 @@ And some basic model declarations...
has_ranking :comments has_ranking :comments
has_recent_records :comments has_recent_records :comments
has_recent_records :articles, :comments has_recent_records :articles, :comments
has_calculated_records :comments, :on => :rating
end end


class Post < ActiveRecord::Base class Post < ActiveRecord::Base
Expand Down Expand Up @@ -199,6 +201,16 @@ Records with associated records since a certain time...
User.recent_comments_and_posts_since(3.days.ago) User.recent_comments_and_posts_since(3.days.ago)
User.recent_comments_or_posts_since(4.days.ago) User.recent_comments_or_posts_since(4.days.ago)


Records with highest and lowest association column average...

User.by_comments_highest_rating_average
User.by_comments_lowest_rating_average

Records with highest and lowest association column total...

User.by_comments_highest_rating_total
User.by_comments_lowest_rating_total

State columns State columns
------------- -------------


Expand Down
19 changes: 19 additions & 0 deletions lib/pacecar/associations.rb
Expand Up @@ -6,6 +6,25 @@ def self.included(base)


module ClassMethods module ClassMethods


def has_calculated_records(*names)
opts = names.extract_options!
names.each do |name|
*columns = opts[:on] || []
columns.flatten.each do |column|
{ 'highest' => 'desc', 'lowest' => 'asc' }.each do |direction_name, direction|
{ 'average' => 'avg', 'total' => 'sum' }.each do |function_name, function_method|
scope "by_#{name}_#{direction_name}_#{column}_#{function_name}".to_sym, {
:select => "#{quoted_table_name}.*, #{function_method}(#{connection.quote_table_name(name)}.#{connection.quote_column_name column}) as #{name}_#{column}_#{function_name}",
:joins => "inner join #{connection.quote_table_name(name)} on #{connection.quote_table_name(name)}.#{connection.quote_column_name reflections[name.to_sym].primary_key_name} = #{quoted_table_name}.#{connection.quote_column_name primary_key}",
:group => safe_column_names.collect { |column_name| "#{quoted_table_name}.#{connection.quote_column_name(column_name)}" }.join(', '),
:order => "#{name}_#{column}_#{function_name} #{direction}"
}
end
end
end
end
end

def has_recent_records(*names) def has_recent_records(*names)
names.each do |name| names.each do |name|
scope "recent_#{name}_since".to_sym, lambda { |since| scope "recent_#{name}_since".to_sym, lambda { |since|
Expand Down
39 changes: 38 additions & 1 deletion spec/associations_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper' require 'spec_helper'


describe 'Associations' do describe 'Associations', 'has recent records' do


before do before do
@comment_user = Factory :user @comment_user = Factory :user
Expand Down Expand Up @@ -30,3 +30,40 @@
end end


end end


describe 'Associations', 'has calculated records' do
before do
@user_one = Factory :user
@user_two = Factory :user
Factory :comment, :user => @user_one, :rating => 8
Factory :comment, :user => @user_one, :rating => 6
Factory :comment, :user => @user_two, :rating => 4
Factory :comment, :user => @user_two, :rating => 3
Factory :comment, :user => @user_two, :rating => 2
end
it "should order records based on association column highest average" do
output = User.by_comments_highest_rating_average
output.should == [@user_one, @user_two]
output.first.comments_rating_average.to_i.should == 7
output.last.comments_rating_average.to_i.should == 3
end
it "should order records based on association column lowest average" do
output = User.by_comments_lowest_rating_average
output.should == [@user_two, @user_one]
output.first.comments_rating_average.to_i.should == 3
output.last.comments_rating_average.to_i.should == 7
end
it "should order records based on association column highest total" do
output = User.by_comments_highest_rating_total
output.should == [@user_one, @user_two]
output.first.comments_rating_total.to_i.should == 14
output.last.comments_rating_total.to_i.should == 9
end
it "should order records based on association column lowest total" do
output = User.by_comments_lowest_rating_total
output.should == [@user_two, @user_one]
output.first.comments_rating_total.to_i.should == 9
output.last.comments_rating_total.to_i.should == 14
end
end
1 change: 1 addition & 0 deletions spec/dummy/app/models/user.rb
Expand Up @@ -9,5 +9,6 @@ class User < ActiveRecord::Base
has_ranking :comments has_ranking :comments
has_recent_records :comments has_recent_records :comments
has_recent_records :posts, :comments has_recent_records :posts, :comments
has_calculated_records :comments, :on => :rating


end end
1 change: 1 addition & 0 deletions spec/dummy/db/migrate/20100419201348_create_schema.rb
Expand Up @@ -24,6 +24,7 @@ def self.up
create_table :comments, :force => true do |t| create_table :comments, :force => true do |t|
t.integer :user_id t.integer :user_id
t.text :description t.text :description
t.integer :rating
t.timestamps t.timestamps
end end
create_table :mammals, :force => true do |t| create_table :mammals, :force => true do |t|
Expand Down
2 changes: 1 addition & 1 deletion spec/helpers_spec.rb
Expand Up @@ -14,7 +14,7 @@


describe "A class with a db table" do describe "A class with a db table" do
it "should should return columns for #safe_column_names" do it "should should return columns for #safe_column_names" do
Comment.safe_column_names.should == ['id', 'user_id', 'description', 'created_at', 'updated_at'] Comment.safe_column_names.should == ['id', 'user_id', 'description', 'rating', 'created_at', 'updated_at']
end end
end end


Expand Down
10 changes: 8 additions & 2 deletions spec/ranking_spec.rb
Expand Up @@ -11,11 +11,17 @@
end end


it "should set the correct expected values on a maximum_ column method" do it "should set the correct expected values on a maximum_ column method" do
User.maximum_comments.should == [@many, @few] output = User.maximum_comments
output.should == [@many, @few]
output.first.comments_count.to_i.should == 5
output.last.comments_count.to_i.should == 2
end end


it "should set the correct expected values on a minimum_ column method" do it "should set the correct expected values on a minimum_ column method" do
User.minimum_comments.should == [@few, @many] output = User.minimum_comments
output.should == [@few, @many]
output.first.comments_count.to_i.should == 2
output.last.comments_count.to_i.should == 5
end end


end end

0 comments on commit b4abc54

Please sign in to comment.