Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Changeset 7749

Show
Ignore:
Timestamp:
10/06/07 00:25:07 (9 months ago)
Author:
rick
Message:

Fix that ActiveRecord would create attribute methods and override custom attribute getters if the method is also defined in Kernel.methods. [Rick]

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/activerecord/CHANGELOG

    r7748 r7749  
    11*SVN* 
     2 
     3* Fix that ActiveRecord would create attribute methods and override custom attribute getters if the method is also defined in Kernel.methods. [Rick] 
    24 
    35* Don't call attr_readonly on polymorphic belongs_to associations, in case it matches the name of some other non-ActiveRecord class/module.  [Rick] 
     
    4648* Deprecation: remove deprecated threaded_connections methods. Use allow_concurrency instead.  [Jeremy Kemper] 
    4749 
    48 * Associations macros accept extension blocks alongside modules.  #9346 [Josh 
    49 Peek] 
     50* Associations macros accept extension blocks alongside modules.  #9346 [Josh Peek] 
    5051 
    5152* Speed up and simplify query caching.  [Jeremy Kemper] 
  • trunk/activerecord/lib/active_record/attribute_methods.rb

    r7731 r7749  
    7777      end 
    7878 
     79      # Check to see if the method is defined in the model or any of it's subclasses that also derive from ActiveRecord. 
     80      # Raise DangerousAttributeError if the method is defined by ActiveRecord though. 
    7981      def instance_method_already_implemented?(method_name) 
    80         if method_defined?(method_name) || private_method_defined?(method_name) || protected_method_defined?(method_name) 
    81           # method is defined but maybe its a simple Kernel:: method which we could simply override 
    82           @@_overrideable_kernel_methods ||= Set.new(Kernel.methods) 
    83           !@@_overrideable_kernel_methods.include?(method_name) 
    84         else 
    85           false 
    86         end 
     82        return true if method_name =~ /^id(=$|\?$|$)/ 
     83        @_defined_class_methods         ||= Set.new(ancestors.first(ancestors.index(ActiveRecord::Base)).collect! { |m| m.public_instance_methods(false) | m.private_instance_methods(false) | m.protected_instance_methods(false) }.flatten) 
     84        @@_defined_activerecord_methods ||= Set.new(ActiveRecord::Base.public_instance_methods(false) | ActiveRecord::Base.private_instance_methods(false) | ActiveRecord::Base.protected_instance_methods(false)) 
     85        raise DangerousAttributeError, "#{method_name} is defined by ActiveRecord" if @@_defined_activerecord_methods.include?(method_name) 
     86        @_defined_class_methods.include?(method_name) 
    8787      end 
    8888       
    8989      alias :define_read_methods :define_attribute_methods 
    90  
    91  
    9290 
    9391      private 
  • trunk/activerecord/lib/active_record/base.rb

    r7723 r7749  
    3030  class StaleObjectError < ActiveRecordError #:nodoc: 
    3131  end 
    32   class ConfigurationError < StandardError #:nodoc: 
     32  class ConfigurationError < ActiveRecordError #:nodoc: 
    3333  end 
    34   class ReadOnlyRecord < StandardError #:nodoc: 
     34  class ReadOnlyRecord < ActiveRecordError #:nodoc: 
    3535  end 
    36   class Rollback < StandardError #:nodoc: 
     36  class Rollback < ActiveRecordError #:nodoc: 
     37  end 
     38   
     39  class DangerousAttributeError < ActiveRecordError #:nodoc: 
    3740  end 
    3841   
  • trunk/activerecord/test/attribute_methods_test.rb

    r7406 r7749  
    5454    topic.freeze 
    5555    assert_equal myobj, topic.content 
    56      
     56  end 
     57   
     58  def test_kernel_methods_not_implemented_in_activerecord 
     59    %w(test name display y).each do |method| 
     60      assert_equal false, ActiveRecord::Base.instance_method_already_implemented?(method), "##{method} is defined" 
     61    end 
     62  end 
     63   
     64  def test_primary_key_implemented 
     65    assert_equal true, Class.new(ActiveRecord::Base).instance_method_already_implemented?('id') 
     66  end 
     67   
     68  def test_defined_kernel_methods_implemented_in_model 
     69    %w(test name display y).each do |method| 
     70      klass = Class.new ActiveRecord::Base 
     71      klass.class_eval "def #{method}() 'defined #{method}' end" 
     72      assert_equal true, klass.instance_method_already_implemented?(method), "##{method} is not defined" 
     73    end 
     74  end 
     75   
     76  def test_defined_kernel_methods_implemented_in_model_abstract_subclass 
     77    %w(test name display y).each do |method| 
     78      abstract = Class.new ActiveRecord::Base 
     79      abstract.class_eval "def #{method}() 'defined #{method}' end" 
     80      abstract.abstract_class = true 
     81      klass = Class.new abstract 
     82      assert_equal true, klass.instance_method_already_implemented?(method), "##{method} is not defined" 
     83    end 
     84  end 
     85   
     86  def test_raises_dangerous_attribute_error_when_defining_activerecord_method_in_model 
     87    %w(save create_or_update).each do |method| 
     88      klass = Class.new ActiveRecord::Base 
     89      klass.class_eval "def #{method}() 'defined #{method}' end" 
     90      assert_raises ActiveRecord::DangerousAttributeError do 
     91        klass.instance_method_already_implemented?(method) 
     92      end 
     93    end 
    5794  end 
    5895end