diff options
author | Emilio Tagua <miloops@gmail.com> | 2009-05-12 16:13:00 -0300 |
---|---|---|
committer | Emilio Tagua <miloops@gmail.com> | 2009-05-12 16:13:00 -0300 |
commit | 0048897a417774f7e5a0c8c9e82fc8684f94ebc1 (patch) | |
tree | 8df248dab434bdaac61ea60249d4630958260eed /activerecord/lib/active_record | |
parent | 6c7d8cb8ac9e6b6775e9a54ef0be62dbaab592f5 (diff) | |
parent | 22c5667c2ef46d6723c1805d3adc52dc8e92429b (diff) | |
download | rails-0048897a417774f7e5a0c8c9e82fc8684f94ebc1.tar.gz rails-0048897a417774f7e5a0c8c9e82fc8684f94ebc1.tar.bz2 rails-0048897a417774f7e5a0c8c9e82fc8684f94ebc1.zip |
Merge commit 'rails/master'
Diffstat (limited to 'activerecord/lib/active_record')
20 files changed, 142 insertions, 122 deletions
diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb index 1eefebb3b3..359e70f5ed 100644 --- a/activerecord/lib/active_record/aggregations.rb +++ b/activerecord/lib/active_record/aggregations.rb @@ -1,8 +1,6 @@ module ActiveRecord module Aggregations # :nodoc: - def self.included(base) - base.extend(ClassMethods) - end + extend ActiveSupport::DependencyModule def clear_aggregation_cache #:nodoc: self.class.reflect_on_all_aggregations.to_a.each do |assoc| diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index e4ab69aa1b..5df76bb183 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -1,9 +1,7 @@ module ActiveRecord # See ActiveRecord::AssociationPreload::ClassMethods for documentation. module AssociationPreload #:nodoc: - def self.included(base) - base.extend(ClassMethods) - end + extend ActiveSupport::DependencyModule # Implements the details of eager loading of ActiveRecord associations. # Application developers should not use this module directly. @@ -126,6 +124,7 @@ module ActiveRecord association_proxy = parent_record.send(reflection_name) association_proxy.loaded association_proxy.target.push(*[associated_record].flatten) + association_proxy.__send__(:set_inverse_instance, associated_record, parent_record) end end @@ -152,7 +151,8 @@ module ActiveRecord seen_keys[associated_record[key].to_s] = true mapped_records = id_to_record_map[associated_record[key].to_s] mapped_records.each do |mapped_record| - mapped_record.send("set_#{reflection_name}_target", associated_record) + association_proxy = mapped_record.send("set_#{reflection_name}_target", associated_record) + association_proxy.__send__(:set_inverse_instance, associated_record, mapped_record) end end end diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index b23cb14c1b..2fe08b2456 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -77,6 +77,8 @@ module ActiveRecord # See ActiveRecord::Associations::ClassMethods for documentation. module Associations # :nodoc: + extend ActiveSupport::DependencyModule + # These classes will be loaded when associations are created. # So there is no need to eager load them. autoload :AssociationCollection, 'active_record/associations/association_collection' @@ -89,10 +91,6 @@ module ActiveRecord autoload :HasOneAssociation, 'active_record/associations/has_one_association' autoload :HasOneThroughAssociation, 'active_record/associations/has_one_through_association' - def self.included(base) - base.extend(ClassMethods) - end - # Clears out the association cache def clear_association_cache #:nodoc: self.class.reflect_on_all_associations.to_a.each do |assoc| @@ -1679,17 +1677,29 @@ module ActiveRecord string.scan(/([\.a-zA-Z_]+).?\./).flatten end + def tables_in_hash(hash) + return [] if hash.blank? + tables = hash.map do |key, value| + if value.is_a?(Hash) + key.to_s + else + tables_in_string(key) if key.is_a?(String) + end + end + tables.flatten.compact + end + def conditions_tables(options) # look in both sets of conditions conditions = [scope(:find, :conditions), options[:conditions]].inject([]) do |all, cond| case cond when nil then all - when Array then all << cond.first - when Hash then all << cond.keys - else all << cond + when Array then all << tables_in_string(cond.first) + when Hash then all << tables_in_hash(cond) + else all << tables_in_string(cond) end end - tables_in_string(conditions.join(' ')) + conditions.flatten end def order_tables(options) @@ -1924,21 +1934,27 @@ module ActiveRecord return nil if record.id.to_s != join.parent.record_id(row).to_s or row[join.aliased_primary_key].nil? association = join.instantiate(row) collection.target.push(association) + collection.__send__(:set_inverse_instance, association, record) when :has_one return if record.id.to_s != join.parent.record_id(row).to_s return if record.instance_variable_defined?("@#{join.reflection.name}") association = join.instantiate(row) unless row[join.aliased_primary_key].nil? - record.send("set_#{join.reflection.name}_target", association) + set_target_and_inverse(join, association, record) when :belongs_to return if record.id.to_s != join.parent.record_id(row).to_s or row[join.aliased_primary_key].nil? association = join.instantiate(row) - record.send("set_#{join.reflection.name}_target", association) + set_target_and_inverse(join, association, record) else raise ConfigurationError, "unknown macro: #{join.reflection.macro}" end return association end + def set_target_and_inverse(join, association, record) + association_proxy = record.send("set_#{join.reflection.name}_target", association) + association_proxy.__send__(:set_inverse_instance, association, record) + end + class JoinBase # :nodoc: attr_reader :active_record, :table_joins delegate :table_name, :column_names, :primary_key, :reflections, :sanitize_sql, :to => :active_record diff --git a/activerecord/lib/active_record/associations/has_one_association.rb b/activerecord/lib/active_record/associations/has_one_association.rb index 4908005d2e..b72b84343b 100644 --- a/activerecord/lib/active_record/associations/has_one_association.rb +++ b/activerecord/lib/active_record/associations/has_one_association.rb @@ -90,7 +90,7 @@ module ActiveRecord when @reflection.options[:as] @finder_sql = "#{@reflection.quoted_table_name}.#{@reflection.options[:as]}_id = #{owner_quoted_id} AND " + - "#{@reflection.quoted_table_name}.#{@reflection.options[:as]}_type = #{@owner.class.quote_value(@owner.class.name.to_s)}" + "#{@reflection.quoted_table_name}.#{@reflection.options[:as]}_type = #{@owner.class.quote_value(@owner.class.base_class.name.to_s)}" else @finder_sql = "#{@reflection.quoted_table_name}.#{@reflection.primary_key_name} = #{owner_quoted_id}" end diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index 3ffc48941c..8d68d77eac 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -1,17 +1,21 @@ module ActiveRecord module AttributeMethods #:nodoc: + extend ActiveSupport::DependencyModule + DEFAULT_SUFFIXES = %w(= ? _before_type_cast) ATTRIBUTE_TYPES_CACHED_BY_DEFAULT = [:datetime, :timestamp, :time, :date] - def self.included(base) - base.extend ClassMethods - base.attribute_method_suffix(*DEFAULT_SUFFIXES) - base.cattr_accessor :attribute_types_cached_by_default, :instance_writer => false - base.attribute_types_cached_by_default = ATTRIBUTE_TYPES_CACHED_BY_DEFAULT - base.cattr_accessor :time_zone_aware_attributes, :instance_writer => false - base.time_zone_aware_attributes = false - base.class_inheritable_accessor :skip_time_zone_conversion_for_attributes, :instance_writer => false - base.skip_time_zone_conversion_for_attributes = [] + included do + attribute_method_suffix(*DEFAULT_SUFFIXES) + + cattr_accessor :attribute_types_cached_by_default, :instance_writer => false + self.attribute_types_cached_by_default = ATTRIBUTE_TYPES_CACHED_BY_DEFAULT + + cattr_accessor :time_zone_aware_attributes, :instance_writer => false + self.time_zone_aware_attributes = false + + class_inheritable_accessor :skip_time_zone_conversion_for_attributes, :instance_writer => false + self.skip_time_zone_conversion_for_attributes = [] end # Declare and check for suffixed attribute methods. diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb index 9717ca3d8b..4ab2818282 100644 --- a/activerecord/lib/active_record/autosave_association.rb +++ b/activerecord/lib/active_record/autosave_association.rb @@ -125,16 +125,15 @@ module ActiveRecord # post.author.name = '' # post.save(false) # => true module AutosaveAssociation + extend ActiveSupport::DependencyModule + ASSOCIATION_TYPES = %w{ has_one belongs_to has_many has_and_belongs_to_many } - def self.included(base) - base.class_eval do - base.extend(ClassMethods) - alias_method_chain :reload, :autosave_associations + included do + alias_method_chain :reload, :autosave_associations - ASSOCIATION_TYPES.each do |type| - base.send("valid_keys_for_#{type}_association") << :autosave - end + ASSOCIATION_TYPES.each do |type| + send("valid_keys_for_#{type}_association") << :autosave end end diff --git a/activerecord/lib/active_record/batches.rb b/activerecord/lib/active_record/batches.rb index 5a6cecd4ad..4836601297 100644 --- a/activerecord/lib/active_record/batches.rb +++ b/activerecord/lib/active_record/batches.rb @@ -1,8 +1,6 @@ module ActiveRecord module Batches # :nodoc: - def self.included(base) - base.extend(ClassMethods) - end + extend ActiveSupport::DependencyModule # When processing large numbers of records, it's often a good idea to do # so in batches to prevent memory ballooning. diff --git a/activerecord/lib/active_record/calculations.rb b/activerecord/lib/active_record/calculations.rb index 9d04686a5f..98f9450662 100644 --- a/activerecord/lib/active_record/calculations.rb +++ b/activerecord/lib/active_record/calculations.rb @@ -1,9 +1,8 @@ module ActiveRecord module Calculations #:nodoc: + extend ActiveSupport::DependencyModule + CALCULATIONS_OPTIONS = [:conditions, :joins, :order, :select, :group, :having, :distinct, :limit, :offset, :include, :from] - def self.included(base) - base.extend(ClassMethods) - end module ClassMethods # Count operates using three different approaches. diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb index e375037b5b..a77fdb1c13 100644 --- a/activerecord/lib/active_record/callbacks.rb +++ b/activerecord/lib/active_record/callbacks.rb @@ -211,21 +211,23 @@ module ActiveRecord # needs to be aware of it because an ordinary +save+ will raise such exception # instead of quietly returning +false+. module Callbacks + extend ActiveSupport::DependencyModule + CALLBACKS = %w( after_find after_initialize before_save after_save before_create after_create before_update after_update before_validation after_validation before_validation_on_create after_validation_on_create before_validation_on_update after_validation_on_update before_destroy after_destroy ) - def self.included(base) #:nodoc: - base.extend Observable + included do + extend Observable [:create_or_update, :valid?, :create, :update, :destroy].each do |method| - base.send :alias_method_chain, method, :callbacks + alias_method_chain method, :callbacks end - base.send :include, ActiveSupport::Callbacks - base.define_callbacks *CALLBACKS + include ActiveSupport::Callbacks + define_callbacks *CALLBACKS end # Is called when the object was instantiated by one of the finders, like <tt>Base.find</tt>. diff --git a/activerecord/lib/active_record/dirty.rb b/activerecord/lib/active_record/dirty.rb index 4a2510aa63..fac6ca40d3 100644 --- a/activerecord/lib/active_record/dirty.rb +++ b/activerecord/lib/active_record/dirty.rb @@ -34,20 +34,21 @@ module ActiveRecord # person.name << 'by' # person.name_change # => ['uncle bob', 'uncle bobby'] module Dirty + extend ActiveSupport::DependencyModule + DIRTY_SUFFIXES = ['_changed?', '_change', '_will_change!', '_was'] - def self.included(base) - base.attribute_method_suffix *DIRTY_SUFFIXES - base.alias_method_chain :write_attribute, :dirty - base.alias_method_chain :save, :dirty - base.alias_method_chain :save!, :dirty - base.alias_method_chain :update, :dirty - base.alias_method_chain :reload, :dirty + included do + attribute_method_suffix *DIRTY_SUFFIXES - base.superclass_delegating_accessor :partial_updates - base.partial_updates = true + alias_method_chain :write_attribute, :dirty + alias_method_chain :save, :dirty + alias_method_chain :save!, :dirty + alias_method_chain :update, :dirty + alias_method_chain :reload, :dirty - base.send(:extend, ClassMethods) + superclass_delegating_accessor :partial_updates + self.partial_updates = true end # Do any attributes have unsaved changes? diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index c6501113bf..91b4b4e182 100644 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -805,27 +805,25 @@ end module ActiveRecord module TestFixtures - def self.included(base) - base.class_eval do - setup :setup_fixtures - teardown :teardown_fixtures - - superclass_delegating_accessor :fixture_path - superclass_delegating_accessor :fixture_table_names - superclass_delegating_accessor :fixture_class_names - superclass_delegating_accessor :use_transactional_fixtures - superclass_delegating_accessor :use_instantiated_fixtures # true, false, or :no_instances - superclass_delegating_accessor :pre_loaded_fixtures - - self.fixture_table_names = [] - self.use_transactional_fixtures = false - self.use_instantiated_fixtures = true - self.pre_loaded_fixtures = false - - self.fixture_class_names = {} - end + extend ActiveSupport::DependencyModule + + included do + setup :setup_fixtures + teardown :teardown_fixtures + + superclass_delegating_accessor :fixture_path + superclass_delegating_accessor :fixture_table_names + superclass_delegating_accessor :fixture_class_names + superclass_delegating_accessor :use_transactional_fixtures + superclass_delegating_accessor :use_instantiated_fixtures # true, false, or :no_instances + superclass_delegating_accessor :pre_loaded_fixtures + + self.fixture_table_names = [] + self.use_transactional_fixtures = false + self.use_instantiated_fixtures = true + self.pre_loaded_fixtures = false - base.extend ClassMethods + self.fixture_class_names = {} end module ClassMethods diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb index a4f5dd8516..e51748b7d2 100644 --- a/activerecord/lib/active_record/locking/optimistic.rb +++ b/activerecord/lib/active_record/locking/optimistic.rb @@ -42,17 +42,17 @@ module ActiveRecord # To override the name of the lock_version column, invoke the <tt>set_locking_column</tt> method. # This method uses the same syntax as <tt>set_table_name</tt> module Optimistic - def self.included(base) #:nodoc: - base.extend ClassMethods + extend ActiveSupport::DependencyModule - base.cattr_accessor :lock_optimistically, :instance_writer => false - base.lock_optimistically = true + included do + cattr_accessor :lock_optimistically, :instance_writer => false + self.lock_optimistically = true - base.alias_method_chain :update, :lock - base.alias_method_chain :destroy, :lock - base.alias_method_chain :attributes_from_column_definition, :lock + alias_method_chain :update, :lock + alias_method_chain :destroy, :lock + alias_method_chain :attributes_from_column_definition, :lock - class << base + class << self alias_method :locking_column=, :set_locking_column end end diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index 3df7089096..32bb36c07c 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -1,5 +1,7 @@ module ActiveRecord module NamedScope + extend ActiveSupport::DependencyModule + # All subclasses of ActiveRecord::Base have one named scope: # * <tt>scoped</tt> - which allows for the creation of anonymous \scopes, on the fly: <tt>Shirt.scoped(:conditions => {:color => 'red'}).scoped(:include => :washing_instructions)</tt> # @@ -7,11 +9,8 @@ module ActiveRecord # intermediate values (scopes) around as first-class objects is convenient. # # You can define a scope that applies to all finders using ActiveRecord::Base.default_scope. - def self.included(base) - base.class_eval do - extend ClassMethods - named_scope :scoped, lambda { |scope| scope } - end + included do + named_scope :scoped, lambda { |scope| scope } end module ClassMethods diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb index e3122d195a..1ea2f53fd8 100644 --- a/activerecord/lib/active_record/nested_attributes.rb +++ b/activerecord/lib/active_record/nested_attributes.rb @@ -1,9 +1,10 @@ module ActiveRecord module NestedAttributes #:nodoc: - def self.included(base) - base.extend(ClassMethods) - base.class_inheritable_accessor :reject_new_nested_attributes_procs, :instance_writer => false - base.reject_new_nested_attributes_procs = {} + extend ActiveSupport::DependencyModule + + included do + class_inheritable_accessor :reject_new_nested_attributes_procs, :instance_writer => false + self.reject_new_nested_attributes_procs = {} end # == Nested Attributes @@ -180,10 +181,14 @@ module ActiveRecord # and the Proc should return either +true+ or +false+. When no Proc # is specified a record will be built for all attribute hashes that # do not have a <tt>_delete</tt> that evaluates to true. + # Passing <tt>:all_blank</tt> instead of a Proc will create a proc + # that will reject a record where all the attributes are blank. # # Examples: # # creates avatar_attributes= # accepts_nested_attributes_for :avatar, :reject_if => proc { |attributes| attributes['name'].blank? } + # # creates avatar_attributes= + # accepts_nested_attributes_for :avatar, :reject_if => :all_blank # # creates avatar_attributes= and posts_attributes= # accepts_nested_attributes_for :avatar, :posts, :allow_destroy => true def accepts_nested_attributes_for(*attr_names) @@ -201,7 +206,12 @@ module ActiveRecord end reflection.options[:autosave] = true - self.reject_new_nested_attributes_procs[association_name.to_sym] = options[:reject_if] + + self.reject_new_nested_attributes_procs[association_name.to_sym] = if options[:reject_if] == :all_blank + proc { |attributes| attributes.all? {|k,v| v.blank?} } + else + options[:reject_if] + end # def pirate_attributes=(attributes) # assign_nested_attributes_for_one_to_one_association(:pirate, attributes, false) diff --git a/activerecord/lib/active_record/observer.rb b/activerecord/lib/active_record/observer.rb index b35e407cc1..1ca76c7b2f 100644 --- a/activerecord/lib/active_record/observer.rb +++ b/activerecord/lib/active_record/observer.rb @@ -3,9 +3,7 @@ require 'set' module ActiveRecord module Observing # :nodoc: - def self.included(base) - base.extend ClassMethods - end + extend ActiveSupport::DependencyModule module ClassMethods # Activates the observers assigned. Examples: diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index ec0175497d..3747ba449d 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -1,8 +1,6 @@ module ActiveRecord module Reflection # :nodoc: - def self.included(base) - base.extend(ClassMethods) - end + extend ActiveSupport::DependencyModule # Reflection allows you to interrogate Active Record classes and objects about their associations and aggregations. # This information can, for example, be used in a form builder that took an Active Record object and created input diff --git a/activerecord/lib/active_record/serializers/json_serializer.rb b/activerecord/lib/active_record/serializers/json_serializer.rb index 48df15d2c0..d376fd5e1b 100644 --- a/activerecord/lib/active_record/serializers/json_serializer.rb +++ b/activerecord/lib/active_record/serializers/json_serializer.rb @@ -2,9 +2,10 @@ require 'active_support/json' module ActiveRecord #:nodoc: module Serialization - def self.included(base) - base.cattr_accessor :include_root_in_json, :instance_writer => false - base.extend ClassMethods + extend ActiveSupport::DependencyModule + + included do + cattr_accessor :include_root_in_json, :instance_writer => false end # Returns a JSON string representing the model. Some configuration is diff --git a/activerecord/lib/active_record/timestamp.rb b/activerecord/lib/active_record/timestamp.rb index d9e1ef351f..3734e170af 100644 --- a/activerecord/lib/active_record/timestamp.rb +++ b/activerecord/lib/active_record/timestamp.rb @@ -8,12 +8,14 @@ module ActiveRecord # Timestamps are in the local timezone by default but you can use UTC by setting # <tt>ActiveRecord::Base.default_timezone = :utc</tt> module Timestamp - def self.included(base) #:nodoc: - base.alias_method_chain :create, :timestamps - base.alias_method_chain :update, :timestamps + extend ActiveSupport::DependencyModule - base.class_inheritable_accessor :record_timestamps, :instance_writer => false - base.record_timestamps = true + included do + alias_method_chain :create, :timestamps + alias_method_chain :update, :timestamps + + class_inheritable_accessor :record_timestamps, :instance_writer => false + self.record_timestamps = true end # Saves the record with the updated_at/on attributes set to the current time. diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb index b059eb7f6f..471a81dfb5 100644 --- a/activerecord/lib/active_record/transactions.rb +++ b/activerecord/lib/active_record/transactions.rb @@ -3,16 +3,14 @@ require 'thread' module ActiveRecord # See ActiveRecord::Transactions::ClassMethods for documentation. module Transactions + extend ActiveSupport::DependencyModule + class TransactionError < ActiveRecordError # :nodoc: end - def self.included(base) - base.extend(ClassMethods) - - base.class_eval do - [:destroy, :save, :save!].each do |method| - alias_method_chain method, :transactions - end + included do + [:destroy, :save, :save!].each do |method| + alias_method_chain method, :transactions end end diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index e6b61e0b35..9907a3c9b7 100644 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -301,17 +301,16 @@ module ActiveRecord # # An Errors object is automatically created for every Active Record. module Validations + extend ActiveSupport::DependencyModule + VALIDATIONS = %w( validate validate_on_create validate_on_update ) - def self.included(base) # :nodoc: - base.extend ClassMethods - base.class_eval do - alias_method_chain :save, :validation - alias_method_chain :save!, :validation - end + included do + alias_method_chain :save, :validation + alias_method_chain :save!, :validation - base.send :include, ActiveSupport::Callbacks - base.define_callbacks *VALIDATIONS + include ActiveSupport::Callbacks + define_callbacks *VALIDATIONS end # Active Record classes can implement validations in several ways. The highest level, easiest to read, |