Skip to content

Instantly share code, notes, and snippets.

@lukeredpath
Created February 27, 2009 17:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lukeredpath/71587 to your computer and use it in GitHub Desktop.
Save lukeredpath/71587 to your computer and use it in GitHub Desktop.
From b7894c95720d13ec7d955fb3675294db5aedf987 Mon Sep 17 00:00:00 2001
From: Luke Redpath <contact@lukeredpath.co.uk>
Date: Fri, 27 Feb 2009 17:35:41 +0000
Subject: [PATCH] Initial attempt at adding a :scope option to has_many :through.
This allows you to have has_many :through collections that go
through a named scope on your join model. This should make it
clearer: http://gist.github.com/71585
---
activerecord/lib/active_record/associations.rb | 3 ++-
.../associations/has_many_through_association.rb | 11 +++++++++++
.../has_many_through_associations_test.rb | 11 +++++++++++
activerecord/test/models/post.rb | 2 ++
activerecord/test/models/tagging.rb | 2 ++
activerecord/test/schema/schema.rb | 1 +
6 files changed, 29 insertions(+), 1 deletions(-)
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index 6e88c89..7ab3a88 100755
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1462,7 +1462,8 @@ module ActiveRecord
:finder_sql, :counter_sql,
:before_add, :after_add, :before_remove, :after_remove,
:extend, :readonly,
- :validate
+ :validate,
+ :scope
]
def create_has_many_reflection(association_id, options, &extension)
diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb
index d5d188a..b8f197f 100644
--- a/activerecord/lib/active_record/associations/has_many_through_association.rb
+++ b/activerecord/lib/active_record/associations/has_many_through_association.rb
@@ -125,8 +125,19 @@ module ActiveRecord
"#{table_name}.#{attr} = #{value}"
end
conditions << sql_conditions if sql_conditions
+ conditions << through_scope_conditions if through_scope_conditions
"(" + conditions.join(') AND (') + ")"
end
+
+ def through_scope_conditions
+ return unless @reflection.options[:scope]
+ if scope_proxy = @reflection.through_reflection.klass.send(@reflection.options[:scope])
+ scope_proxy.proxy_options[:conditions].inject([]) do |scope_conditions, (key, value)|
+ scope_conditions << "#{@reflection.through_reflection.quoted_table_name}.#{key} = #{value}"
+ scope_conditions
+ end
+ end
+ end
def construct_from
@reflection.quoted_table_name
diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb
index 1e5d1a0..b9538f7 100644
--- a/activerecord/test/cases/associations/has_many_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb
@@ -249,4 +249,15 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
author.author_favorites.create(:favorite_author_id => 3)
assert_equal post.author.author_favorites, post.author_favorites
end
+
+ def test_has_many_association_through_a_scoped_association
+ author = authors(:mary)
+ post = Post.create!(:author => author, :title => "TITLE", :body => "BODY")
+ tag_one = Tag.create!(:name => 'ruby')
+ tag_two = Tag.create!(:name => 'rails')
+ post.taggings.flagged.create(:tag => tag_one)
+ post.taggings.create(:tag => tag_two)
+ assert post.taggings.first.flagged?
+ assert_equal [tag_one], post.flagged_tags
+ end
end
diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb
index 374e536..ce665f2 100644
--- a/activerecord/test/models/post.rb
+++ b/activerecord/test/models/post.rb
@@ -58,6 +58,8 @@ class Post < ActiveRecord::Base
has_many :invalid_taggings, :as => :taggable, :class_name => "Tagging", :conditions => 'taggings.id < 0'
has_many :invalid_tags, :through => :invalid_taggings, :source => :tag
+
+ has_many :flagged_tags, :through => :taggings, :source => :tag, :scope => :flagged
has_many :categorizations, :foreign_key => :category_id
has_many :authors, :through => :categorizations
diff --git a/activerecord/test/models/tagging.rb b/activerecord/test/models/tagging.rb
index a1fa1a9..3e04dc8 100644
--- a/activerecord/test/models/tagging.rb
+++ b/activerecord/test/models/tagging.rb
@@ -7,4 +7,6 @@ class Tagging < ActiveRecord::Base
belongs_to :super_tag, :class_name => 'Tag', :foreign_key => 'super_tag_id'
belongs_to :invalid_tag, :class_name => 'Tag', :foreign_key => 'tag_id'
belongs_to :taggable, :polymorphic => true, :counter_cache => true
+
+ named_scope :flagged, :conditions => {:flagged => true}
end
\ No newline at end of file
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 74a8939..4610f67 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -414,6 +414,7 @@ ActiveRecord::Schema.define do
t.column :super_tag_id, :integer
t.column :taggable_type, :string
t.column :taggable_id, :integer
+ t.column :flagged, :boolean
end
create_table :tags, :force => true do |t|
--
1.5.6.4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment