diff options
-rw-r--r-- | activerecord/lib/active_record/associations/association_proxy.rb | 55 |
1 files changed, 50 insertions, 5 deletions
diff --git a/activerecord/lib/active_record/associations/association_proxy.rb b/activerecord/lib/active_record/associations/association_proxy.rb index 77fc827e11..8a3186ded2 100644 --- a/activerecord/lib/active_record/associations/association_proxy.rb +++ b/activerecord/lib/active_record/associations/association_proxy.rb @@ -57,92 +57,127 @@ module ActiveRecord reset end + # Returns the owner of the proxy. def proxy_owner @owner end + # Returns the reflection object that represents the association handled + # by the proxy. def proxy_reflection @reflection end + # Returns the target of the proxy, same as +target+. def proxy_target @target end + # Does the proxy or its target respond to +symbol+? def respond_to?(symbol, include_priv = false) proxy_respond_to?(symbol, include_priv) || (load_target && @target.respond_to?(symbol, include_priv)) end - # Explicitly proxy === because the instance method removal above - # doesn't catch it. + # Forwards <tt>===</tt> explicitly to the target because the instance method + # removal above doesn't catch it. Loads the target if needed. def ===(other) load_target other === @target end + # Returns the name of the table of the related class: + # + # post.comments.aliased_table_name # => "comments" + # def aliased_table_name @reflection.klass.table_name end + # Returns the SQL string that corresponds to the <tt>:conditions</tt> + # option of the macro, if given, or +nil+ otherwise. def conditions @conditions ||= interpolate_sql(@reflection.sanitized_conditions) if @reflection.sanitized_conditions end alias :sql_conditions :conditions + # Resets the loaded flag to +false+ and sets the target to +nil+. def reset @loaded = false @target = nil end + # Reloads the target and returns +self+ on success. def reload reset load_target self unless @target.nil? end + # Has the target been already loaded? def loaded? @loaded end + # Asserts the target has been loaded setting the loaded flag to +true+. def loaded @loaded = true end + # Returns the target of this proxy, same as +proxy_target+. def target @target end + # Sets the target of this proxy to +target+, and the loaded flag to +true+. def target=(target) @target = target loaded end + # Forwards the call to the target. Loads the target if needed. def inspect load_target @target.inspect end protected + # Does the association have a <tt>:dependent</tt> option? def dependent? @reflection.options[:dependent] end + # Returns a string with the IDs of +records+ joined with a comma, quoted + # if needed. The result is ready to be inserted into a SQL IN clause. + # + # quoted_record_ids(records) # => "23,56,58,67" + # def quoted_record_ids(records) records.map { |record| record.quoted_id }.join(',') end + # Interpolates the SQL in <tt>options[key]</tt> and assigns the result + # back, for any +key+ in +keys+ that's present in +options+. + # + # Meant to be used like this: + # + # interpolate_sql_options!(@reflection.options, :finder_sql) + # def interpolate_sql_options!(options, *keys) keys.each { |key| options[key] &&= interpolate_sql(options[key]) } end + # Forwards the call to the owner. def interpolate_sql(sql, record = nil) @owner.send(:interpolate_sql, sql, record) end + # Forwards the call to the reflection class. def sanitize_sql(sql) @reflection.klass.send(:sanitize_sql, sql) end + # Assigns the ID of the owner to the corresponding foreign key in +record+. + # If the association is polymorphic the type of the owner is also set. def set_belongs_to_association_for(record) if @reflection.options[:as] record["#{@reflection.options[:as]}_id"] = @owner.id unless @owner.new_record? @@ -152,6 +187,7 @@ module ActiveRecord end end + # Merges into +options+ the ones coming from the reflection. def merge_options_from_reflection!(options) options.reverse_merge!( :group => @reflection.options[:group], @@ -164,11 +200,13 @@ module ActiveRecord ) end + # Forwards +with_scope+ to the reflection. def with_scope(*args, &block) @reflection.klass.send :with_scope, *args, &block end private + # Forwards any missing method call to the target. def method_missing(method, *args) if load_target if block_given? @@ -202,12 +240,17 @@ module ActiveRecord reset end - # Can be overwritten by associations that might have the foreign key available for an association without - # having the object itself (and still being a new record). Currently, only belongs_to presents this scenario. + # Can be overwritten by associations that might have the foreign key + # available for an association without having the object itself (and + # still being a new record). Currently, only +belongs_to+ presents + # this scenario (both vanilla and polymorphic). def foreign_key_present false end + # Raises ActiveRecord::AssociationTypeMismatch unless +record+ is of + # the kind of the class of the associated objects. Meant to be used as + # a sanity check when you are about to assing an associated record. def raise_on_type_mismatch(record) unless record.is_a?(@reflection.klass) message = "#{@reflection.class_name}(##{@reflection.klass.object_id}) expected, got #{record.class}(##{record.class.object_id})" @@ -215,11 +258,13 @@ module ActiveRecord end end - # Array#flatten has problems with recursive arrays. Going one level deeper solves the majority of the problems. + # Array#flatten has problems with recursive arrays. Going one level + # deeper solves the majority of the problems. def flatten_deeper(array) array.collect { |element| element.respond_to?(:flatten) ? element.flatten : element }.flatten end + # Returns the ID of the owner, quoted if needed. def owner_quoted_id @owner.quoted_id end |