From fbdf0b41099236e361cc182ab451764cceecd0f6 Mon Sep 17 00:00:00 2001 From: Rob Date: Mon, 9 Mar 2009 22:59:04 +0000 Subject: [PATCH] Added anonymous extension modules for all associations --- activerecord/lib/active_record/associations.rb | 23 +++++++++++++------- .../test/cases/associations/extension_test.rb | 17 +++++++++++++- activerecord/test/models/post.rb | 11 +++++++++ 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 301b3a3..32feaf0 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -860,6 +860,8 @@ module ActiveRecord # as the default :foreign_key. # [:primary_key] # Specify the method that returns the primary key used for the association. By default this is +id+. + # [:extend] + # Specify a named module for extending the proxy. See "Association extensions". # [:include] # Specify second-order associations that should be eager loaded when this object is loaded. # [:as] @@ -894,12 +896,12 @@ module ActiveRecord # has_one :boss, :readonly => :true # has_one :club, :through => :membership # has_one :primary_address, :through => :addressables, :conditions => ["addressable.primary = ?", true], :source => :addressable - def has_one(association_id, options = {}) + def has_one(association_id, options = {}, &extension) if options[:through] - reflection = create_has_one_through_reflection(association_id, options) + reflection = create_has_one_through_reflection(association_id, options, &extension) association_accessor_methods(reflection, ActiveRecord::Associations::HasOneThroughAssociation) else - reflection = create_has_one_reflection(association_id, options) + reflection = create_has_one_reflection(association_id, options, &extension) association_accessor_methods(reflection, HasOneAssociation) association_constructor_method(:build, reflection, HasOneAssociation) association_constructor_method(:create, reflection, HasOneAssociation) @@ -969,6 +971,8 @@ module ActiveRecord # is used on the associate class (such as a Post class). You can also specify a custom counter cache column by providing # a column name instead of a +true+/+false+ value to this option (e.g., :counter_cache => :my_custom_counter.) # Note: Specifying a counter cache will add it to that model's list of readonly attributes using +attr_readonly+. + # [:extend] + # Specify a named module for extending the proxy. See "Association extensions". # [:include] # Specify second-order associations that should be eager loaded when this object is loaded. # [:polymorphic] @@ -990,8 +994,8 @@ module ActiveRecord # belongs_to :attachable, :polymorphic => true # belongs_to :project, :readonly => true # belongs_to :post, :counter_cache => true - def belongs_to(association_id, options = {}) - reflection = create_belongs_to_reflection(association_id, options) + def belongs_to(association_id, options = {}, &extension) + reflection = create_belongs_to_reflection(association_id, options, &extension) if reflection.options[:polymorphic] association_accessor_methods(reflection, BelongsToPolymorphicAssociation) @@ -1483,15 +1487,17 @@ module ActiveRecord :validate, :primary_key ] - def create_has_one_reflection(association_id, options) + def create_has_one_reflection(association_id, options, &extension) options.assert_valid_keys(valid_keys_for_has_one_association) + options[:extend] = create_extension_modules(association_id, extension, options[:extend]) create_reflection(:has_one, association_id, options, self) end - def create_has_one_through_reflection(association_id, options) + def create_has_one_through_reflection(association_id, options, &extension) options.assert_valid_keys( :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :through, :source, :source_type, :validate ) + options[:extend] = create_extension_modules(association_id, extension, options[:extend]) create_reflection(:has_one, association_id, options, self) end @@ -1502,8 +1508,9 @@ module ActiveRecord :validate ] - def create_belongs_to_reflection(association_id, options) + def create_belongs_to_reflection(association_id, options, &extension) options.assert_valid_keys(valid_keys_for_belongs_to_association) + options[:extend] = create_extension_modules(association_id, extension, options[:extend]) reflection = create_reflection(:belongs_to, association_id, options, self) if options[:polymorphic] diff --git a/activerecord/test/cases/associations/extension_test.rb b/activerecord/test/cases/associations/extension_test.rb index 9390633..ecf88d3 100644 --- a/activerecord/test/cases/associations/extension_test.rb +++ b/activerecord/test/cases/associations/extension_test.rb @@ -1,12 +1,27 @@ require "cases/helper" require 'models/post' +require 'models/author' require 'models/comment' +require 'models/tag' +require 'models/tagging' require 'models/project' require 'models/developer' require 'models/company_in_module' class AssociationsExtensionsTest < ActiveRecord::TestCase - fixtures :projects, :developers, :developers_projects, :comments, :posts + fixtures :projects, :developers, :developers_projects, :comments, :posts, :tags, :taggings + + def test_extension_on_belongs_to + assert_equal "hello", posts(:welcome).author.greeting + end + + def test_extension_on_has_one + assert_equal "the last comment associated with a post...", posts(:welcome).last_comment.what_are_you + end + + def test_extension_on_has_one_through + assert_equal "the last tag associated with a post...", posts(:welcome).last_tag.what_are_you + end def test_extension_on_has_many assert_equal comments(:more_greetings), posts(:welcome).comments.find_most_recent diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb index 374e536..683f257 100644 --- a/activerecord/test/models/post.rb +++ b/activerecord/test/models/post.rb @@ -18,6 +18,11 @@ class Post < ActiveRecord::Base belongs_to :author_with_address, :class_name => "Author", :foreign_key => :author_id, :include => :author_address has_one :last_comment, :class_name => 'Comment', :order => 'id desc' + has_one :last_comment, :class_name => 'Comment', :order => 'id desc' do + def what_are_you + "the last comment associated with a post..." + end + end named_scope :with_special_comments, :joins => :comments, :conditions => {:comments => {:type => 'SpecialComment'} } named_scope :with_very_special_comments, :joins => :comments, :conditions => {:comments => {:type => 'VerySpecialComment'} } @@ -56,6 +61,12 @@ class Post < ActiveRecord::Base has_many :super_tags, :through => :taggings has_one :tagging, :as => :taggable + has_one :last_tag, :class_name => 'Tag', :order => 'id desc', :through => :taggings, :source => :tag do + def what_are_you + "the last tag associated with a post..." + end + end + has_many :invalid_taggings, :as => :taggable, :class_name => "Tagging", :conditions => 'taggings.id < 0' has_many :invalid_tags, :through => :invalid_taggings, :source => :tag -- 1.6.2.1217.gd7bc3