diff options
Diffstat (limited to 'activerecord/lib/active_record/associations.rb')
-rw-r--r-- | activerecord/lib/active_record/associations.rb | 88 |
1 files changed, 57 insertions, 31 deletions
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 35bc09bb10..5e3e5f709b 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -113,19 +113,19 @@ module ActiveRecord # These classes will be loaded when associations are created. # So there is no need to eager load them. - autoload :Association, 'active_record/associations/association' - autoload :SingularAssociation, 'active_record/associations/singular_association' - autoload :CollectionAssociation, 'active_record/associations/collection_association' - autoload :ForeignAssociation, 'active_record/associations/foreign_association' - autoload :CollectionProxy, 'active_record/associations/collection_proxy' + autoload :Association + autoload :SingularAssociation + autoload :CollectionAssociation + autoload :ForeignAssociation + autoload :CollectionProxy - autoload :BelongsToAssociation, 'active_record/associations/belongs_to_association' - autoload :BelongsToPolymorphicAssociation, 'active_record/associations/belongs_to_polymorphic_association' - autoload :HasManyAssociation, 'active_record/associations/has_many_association' - autoload :HasManyThroughAssociation, 'active_record/associations/has_many_through_association' - autoload :HasOneAssociation, 'active_record/associations/has_one_association' - autoload :HasOneThroughAssociation, 'active_record/associations/has_one_through_association' - autoload :ThroughAssociation, 'active_record/associations/through_association' + autoload :BelongsToAssociation + autoload :BelongsToPolymorphicAssociation + autoload :HasManyAssociation + autoload :HasManyThroughAssociation + autoload :HasOneAssociation + autoload :HasOneThroughAssociation + autoload :ThroughAssociation module Builder #:nodoc: autoload :Association, 'active_record/associations/builder/association' @@ -139,26 +139,20 @@ module ActiveRecord end eager_autoload do - autoload :Preloader, 'active_record/associations/preloader' - autoload :JoinDependency, 'active_record/associations/join_dependency' - autoload :AssociationScope, 'active_record/associations/association_scope' - autoload :AliasTracker, 'active_record/associations/alias_tracker' + autoload :Preloader + autoload :JoinDependency + autoload :AssociationScope + autoload :AliasTracker end - # Clears out the association cache. - def clear_association_cache #:nodoc: - @association_cache.clear if persisted? - end - - # :nodoc: - attr_reader :association_cache - # Returns the association instance for the given name, instantiating it if it doesn't already exist def association(name) #:nodoc: association = association_instance_get(name) if association.nil? - raise AssociationNotFoundError.new(self, name) unless reflection = self.class._reflect_on_association(name) + unless reflection = self.class._reflect_on_association(name) + raise AssociationNotFoundError.new(self, name) + end association = reflection.association_class.new(self, reflection) association_instance_set(name, association) end @@ -166,7 +160,31 @@ module ActiveRecord association end + def association_cached?(name) # :nodoc + @association_cache.key?(name) + end + + def initialize_dup(*) # :nodoc: + @association_cache = {} + super + end + + def reload(*) # :nodoc: + clear_association_cache + super + end + private + # Clears out the association cache. + def clear_association_cache # :nodoc: + @association_cache.clear if persisted? + end + + def init_internals # :nodoc: + @association_cache = {} + super + end + # Returns the specified association instance if it responds to :loaded?, nil otherwise. def association_instance_get(name) @association_cache[name] @@ -1000,6 +1018,8 @@ module ActiveRecord # callbacks declared either before or after the <tt>:dependent</tt> option # can affect what it does. # + # Note that <tt>:dependent</tt> option is ignored for +has_one+ <tt>:through</tt> associations. + # # === Delete or destroy? # # +has_many+ and +has_and_belongs_to_many+ associations have the methods <tt>destroy</tt>, @@ -1012,7 +1032,7 @@ module ActiveRecord # record(s) being removed so that callbacks are run. However <tt>delete</tt> and <tt>delete_all</tt> will either # do the deletion according to the strategy specified by the <tt>:dependent</tt> option, or # if no <tt>:dependent</tt> option is given, then it will follow the default strategy. - # The default strategy is <tt>:nullify</tt> (set the foreign keys to <tt>nil</tt>), except for + # The default strategy is to do nothing (leave the foreign keys with the parent ids set), except for # +has_many+ <tt>:through</tt>, where the default strategy is <tt>delete_all</tt> (delete # the join records, without running their callbacks). # @@ -1330,6 +1350,8 @@ module ActiveRecord # * <tt>:nullify</tt> causes the foreign key to be set to +NULL+. Callbacks are not executed. # * <tt>:restrict_with_exception</tt> causes an exception to be raised if there is an associated record # * <tt>:restrict_with_error</tt> causes an error to be added to the owner if there is an associated object + # + # Note that <tt>:dependent</tt> option is ignored when using <tt>:through</tt> option. # [:foreign_key] # Specify the foreign key used for the association. By default this is guessed to be the name # of this class in lower-case and "_id" suffixed. So a Person class that makes a +has_one+ association @@ -1382,7 +1404,7 @@ module ActiveRecord # has_one :last_comment, -> { order 'posted_on' }, class_name: "Comment" # has_one :project_manager, -> { where role: 'project_manager' }, class_name: "Person" # has_one :attachment, as: :attachable - # has_one :boss, readonly: :true + # has_one :boss, -> { readonly } # has_one :club, through: :membership # has_one :primary_address, -> { where primary: true }, through: :addressables, source: :addressable # has_one :credit_card, required: true @@ -1434,7 +1456,7 @@ module ActiveRecord # when you access the associated object. # # Scope examples: - # belongs_to :user, -> { where(id: 2) } + # belongs_to :firm, -> { where(id: 2) } # belongs_to :user, -> { joins(:friends) } # belongs_to :level, ->(level) { where("game_level > ?", level.current) } # @@ -1498,10 +1520,14 @@ module ActiveRecord # object that is the inverse of this <tt>belongs_to</tt> association. Does not work in # combination with the <tt>:polymorphic</tt> options. # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail. + # [:optional] + # When set to +true+, the association will not have its presence validated. # [:required] # When set to +true+, the association will also have its presence validated. # This will validate the association itself, not the id. You can use # +:inverse_of+ to avoid an extra query during validation. + # NOTE: <tt>required</tt> is set to <tt>true</tt> by default and is deprecated. If + # you don't want to have association presence validated, use <tt>optional: true</tt>. # # Option examples: # belongs_to :firm, foreign_key: "client_of" @@ -1510,11 +1536,11 @@ module ActiveRecord # belongs_to :valid_coupon, ->(o) { where "discounts > ?", o.payments_count }, # class_name: "Coupon", foreign_key: "coupon_id" # belongs_to :attachable, polymorphic: true - # belongs_to :project, readonly: true + # belongs_to :project, -> { readonly } # belongs_to :post, counter_cache: true - # belongs_to :company, touch: true + # belongs_to :comment, touch: true # belongs_to :company, touch: :employees_last_updated_at - # belongs_to :company, required: true + # belongs_to :user, optional: true def belongs_to(name, scope = nil, options = {}) reflection = Builder::BelongsTo.build(self, name, scope, options) Reflection.add_reflection self, name, reflection |