Permalink
Browse files

Add a HasAssociation module for common code for has_* associations

  • Loading branch information...
1 parent 0c27247 commit b0498372a10bda006350af42708a5588ab28ffcb @jonleighton jonleighton committed Dec 26, 2010
@@ -120,6 +120,8 @@ module Associations # :nodoc:
# So there is no need to eager load them.
autoload :AssociationCollection, 'active_record/associations/association_collection'
autoload :AssociationProxy, 'active_record/associations/association_proxy'
+ autoload :HasAssociation, 'active_record/associations/has_association'
+ autoload :ThroughAssociation, 'active_record/associations/through_association'
autoload :BelongsToAssociation, 'active_record/associations/belongs_to_association'
autoload :BelongsToPolymorphicAssociation, 'active_record/associations/belongs_to_polymorphic_association'
autoload :HasAndBelongsToManyAssociation, 'active_record/associations/has_and_belongs_to_many_association'
@@ -18,6 +18,8 @@ module Associations
# If you need to work on all current children, new and existing records,
# +load_target+ and the +loaded+ flag are your friends.
class AssociationCollection < AssociationProxy #:nodoc:
+ include HasAssociation
+
delegate :group, :order, :limit, :joins, :where, :preload, :eager_load, :includes, :from, :lock, :readonly, :having, :to => :scoped
def select(select = nil)
@@ -4,17 +4,17 @@ module ActiveRecord
module Associations
# = Active Record Associations
#
- # This is the root class of all association proxies:
+ # This is the root class of all association proxies ('+ Foo' signifies an included module Foo):
#
# AssociationProxy
# BelongsToAssociation
- # HasOneAssociation
# BelongsToPolymorphicAssociation
- # AssociationCollection
+ # AssociationCollection + HasAssociation
# HasAndBelongsToManyAssociation
# HasManyAssociation
- # HasManyThroughAssociation
- # HasOneThroughAssociation
+ # HasManyThroughAssociation + ThroughAssociation
+ # HasOneAssociation + HasAssociation
+ # HasOneThroughAssociation + ThroughAssociation
#
# Association proxies in Active Record are middlemen between the object that
# holds the association, known as the <tt>@owner</tt>, and the actual associated
@@ -176,43 +176,6 @@ def sanitize_sql(sql, table_name = @reflection.klass.table_name)
@reflection.klass.send(:sanitize_sql, sql, table_name)
end
- # Sets the owner attributes on the given record
- # Note: does not really make sense for belongs_to associations, but this method is not
- # used by belongs_to
- def set_owner_attributes(record)
- if @owner.persisted?
- construct_owner_attributes.each { |key, value| record[key] = value }
- end
- end
-
- # Returns a has linking the owner to the association represented by the reflection
- def construct_owner_attributes(reflection = @reflection)
- attributes = {}
- if reflection.macro == :belongs_to
- attributes[reflection.association_primary_key] = @owner.send(reflection.primary_key_name)
- else
- attributes[reflection.primary_key_name] = @owner.send(reflection.active_record_primary_key)
-
- if reflection.options[:as]
- attributes["#{reflection.options[:as]}_type"] = @owner.class.base_class.name
- end
- end
- attributes
- end
-
- # Builds an array of arel nodes from the owner attributes hash
- def construct_owner_conditions(table = aliased_table, reflection = @reflection)
- construct_owner_attributes(reflection).map do |attr, value|
- table[attr].eq(value)
- end
- end
-
- def construct_conditions
- conditions = construct_owner_conditions
- conditions << Arel.sql(sql_conditions) if sql_conditions
- aliased_table.create_and(conditions)
- end
-
# Merges into +options+ the ones coming from the reflection.
def merge_options_from_reflection!(options)
options.reverse_merge!(
@@ -312,18 +275,6 @@ def raise_on_type_mismatch(record)
end
end
- if RUBY_VERSION < '1.9.2'
- # Array#flatten has problems with recursive arrays before Ruby 1.9.2.
- # Going one level deeper solves the majority of the problems.
- def flatten_deeper(array)
- array.collect { |element| (element.respond_to?(:flatten) && !element.is_a?(Hash)) ? element.flatten : element }.flatten
- end
- else
- def flatten_deeper(array)
- array.flatten
- end
- end
-
# Returns the ID of the owner, quoted if needed.
def owner_quoted_id
@owner.quoted_id
@@ -0,0 +1,54 @@
+module ActiveRecord
+ module Associations
+ # Included in all has_* associations (i.e. everything except belongs_to)
+ module HasAssociation #:nodoc:
+ protected
+ # Sets the owner attributes on the given record
+ def set_owner_attributes(record)
+ if @owner.persisted?
+ construct_owner_attributes.each { |key, value| record[key] = value }
+ end
+ end
+
+ # Returns a hash linking the owner to the association represented by the reflection
+ def construct_owner_attributes(reflection = @reflection)
+ attributes = {}
+ if reflection.macro == :belongs_to
+ attributes[reflection.association_primary_key] = @owner.send(reflection.primary_key_name)
+ else
+ attributes[reflection.primary_key_name] = @owner.send(reflection.active_record_primary_key)
+
+ if reflection.options[:as]
+ attributes["#{reflection.options[:as]}_type"] = @owner.class.base_class.name
+ end
+ end
+ attributes
+ end
+
+ # Builds an array of arel nodes from the owner attributes hash
+ def construct_owner_conditions(table = aliased_table, reflection = @reflection)
+ construct_owner_attributes(reflection).map do |attr, value|
+ table[attr].eq(value)
+ end
+ end
+
+ def construct_conditions
+ conditions = construct_owner_conditions
+ conditions << Arel.sql(sql_conditions) if sql_conditions
+ aliased_table.create_and(conditions)
+ end
+
+ if RUBY_VERSION < '1.9.2'
+ # Array#flatten has problems with recursive arrays before Ruby 1.9.2.
+ # Going one level deeper solves the majority of the problems.
+ def flatten_deeper(array)
+ array.collect { |element| (element.respond_to?(:flatten) && !element.is_a?(Hash)) ? element.flatten : element }.flatten
+ end
+ else
+ def flatten_deeper(array)
+ array.flatten
+ end
+ end
+ end
+ end
+end
@@ -1,11 +1,10 @@
-require "active_record/associations/through_association_scope"
require 'active_support/core_ext/object/blank'
module ActiveRecord
# = Active Record Has Many Through Association
module Associations
class HasManyThroughAssociation < HasManyAssociation #:nodoc:
- include ThroughAssociationScope
+ include ThroughAssociation
alias_method :new, :build
@@ -2,6 +2,8 @@ module ActiveRecord
# = Active Record Belongs To Has One Association
module Associations
class HasOneAssociation < AssociationProxy #:nodoc:
+ include HasAssociation
+
def create(attrs = {}, replace_existing = true)
new_record(replace_existing) do |reflection|
attrs = merge_with_conditions(attrs)
@@ -1,10 +1,8 @@
-require "active_record/associations/through_association_scope"
-
module ActiveRecord
# = Active Record Has One Through Association
module Associations
class HasOneThroughAssociation < HasOneAssociation
- include ThroughAssociationScope
+ include ThroughAssociation
def replace(new_value)
create_through_record(new_value)
@@ -1,7 +1,7 @@
module ActiveRecord
- # = Active Record Through Association Scope
+ # = Active Record Through Association
module Associations
- module ThroughAssociationScope
+ module ThroughAssociation
def scoped
with_scope(@scope) do

0 comments on commit b049837

Please sign in to comment.