diff options
7 files changed, 57 insertions, 15 deletions
diff --git a/activerecord/lib/active_record/associations/builder/association.rb b/activerecord/lib/active_record/associations/builder/association.rb index 686db0725d..3534e037b7 100644 --- a/activerecord/lib/active_record/associations/builder/association.rb +++ b/activerecord/lib/active_record/associations/builder/association.rb @@ -6,7 +6,7 @@ module ActiveRecord::Associations::Builder # Set by subclasses class_attribute :macro - attr_reader :model, :name, :options, :reflection, :mixin + attr_reader :model, :name, :options, :reflection def self.build(model, name, options) new(model, name, options).build @@ -14,8 +14,10 @@ module ActiveRecord::Associations::Builder def initialize(model, name, options) @model, @name, @options = model, name, options - @mixin = Module.new - @model.__send__(:include, @mixin) + end + + def mixin + @model.generated_feature_methods end def build diff --git a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb index f3391eba13..30fc44b4c2 100644 --- a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb +++ b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb @@ -15,10 +15,14 @@ module ActiveRecord::Associations::Builder def define_destroy_hook name = self.name - mixin.send(:define_method, :destroy_associations) do - association(name).delete_all - super() - end + model.send(:include, Module.new { + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def destroy_associations + association(#{name.to_sym.inspect}).delete_all + super + end + RUBY + }) end # TODO: These checks should probably be moved into the Reflection, and we should not be diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index 2d720fe700..d7bfaa5655 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -8,12 +8,6 @@ module ActiveRecord include ActiveModel::AttributeMethods module ClassMethods - def inherited(child_class) - # force creation + include before accessor method modules - child_class.generated_attribute_methods - super - end - # Generates all the attribute related methods for columns in the database # accessors, mutators and query methods. def define_attribute_methods diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 3558ae3545..a9c8ed1396 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -450,6 +450,20 @@ module ActiveRecord #:nodoc: :having, :create_with, :uniq, :to => :scoped delegate :count, :average, :minimum, :maximum, :sum, :calculate, :to => :scoped + def inherited(child_class) #:nodoc: + # force attribute methods to be higher in inheritance hierarchy than other generated methods + child_class.generated_attribute_methods + child_class.generated_feature_methods + super + end + + def generated_feature_methods + unless const_defined?(:GeneratedFeatureMethods, false) + include const_set(:GeneratedFeatureMethods, Module.new) + end + const_get(:GeneratedFeatureMethods) + end + # Executes a custom SQL query against your database and returns all the results. The results will # be returned as an array with columns requested encapsulated as attributes of the model you call # this method from. If you call <tt>Product.find_by_sql</tt> then the results will be returned in diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb index 34d90cc395..32a3389422 100644 --- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb @@ -77,7 +77,7 @@ end class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase fixtures :accounts, :companies, :categories, :posts, :categories_posts, :developers, :projects, :developers_projects, - :parrots, :pirates, :treasures, :price_estimates, :tags, :taggings + :parrots, :pirates, :parrots_pirates, :treasures, :price_estimates, :tags, :taggings def setup_data_for_habtm_case ActiveRecord::Base.connection.execute('delete from countries_treaties') @@ -445,6 +445,26 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase assert david.projects(true).empty? end + def test_destroy_associations_destroys_multiple_associations + george = parrots(:george) + assert !george.pirates.empty? + assert !george.treasures.empty? + + assert_no_difference "Pirate.count" do + assert_no_difference "Treasure.count" do + george.destroy_associations + end + end + + join_records = Parrot.connection.select_all("SELECT * FROM parrots_pirates WHERE parrot_id = #{george.id}") + assert join_records.empty? + assert george.pirates(true).empty? + + join_records = Parrot.connection.select_all("SELECT * FROM parrots_treasures WHERE parrot_id = #{george.id}") + assert join_records.empty? + assert george.treasures(true).empty? + end + def test_deprecated_push_with_attributes_was_removed jamis = developers(:jamis) assert_raise(NoMethodError) do diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index fdb656fe13..2b0cf76d84 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -69,6 +69,15 @@ end class BasicsTest < ActiveRecord::TestCase fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things', :authors, :categorizations, :categories, :posts + def test_generated_methods_modules + modules = Computer.ancestors + assert modules.include?(Computer::GeneratedFeatureMethods) + assert_equal(Computer::GeneratedFeatureMethods, Computer.generated_feature_methods) + assert(modules.index(Computer.generated_attribute_methods) > modules.index(Computer.generated_feature_methods), + "generated_attribute_methods must be higher in inheritance hierarchy than generated_feature_methods") + assert_not_equal Computer.generated_feature_methods, Post.generated_feature_methods + end + def test_column_names_are_escaped conn = ActiveRecord::Base.connection classname = conn.class.name[/[^:]*$/] diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb index 23db5650d4..bfadfd9d75 100644 --- a/activerecord/test/models/author.rb +++ b/activerecord/test/models/author.rb @@ -128,7 +128,6 @@ class Author < ActiveRecord::Base belongs_to :author_address, :dependent => :destroy belongs_to :author_address_extra, :dependent => :delete, :class_name => "AuthorAddress" - has_many :post_categories, :through => :posts, :source => :categories has_many :category_post_comments, :through => :categories, :source => :post_comments has_many :misc_posts, :class_name => 'Post', |