class ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation
:nodoc:
def ==(other)
def ==(other) other.class == self.class && other.reflection == reflection && other.parent == parent end
def aliased_table_name_for(name, suffix = nil)
def aliased_table_name_for(name, suffix = nil) if @join_dependency.table_aliases[name].zero? @join_dependency.table_aliases[name] = @join_dependency.count_aliases_from_table_joins(name) end if !@join_dependency.table_aliases[name].zero? # We need an alias name = active_record.connection.table_alias_for "#{pluralize(reflection.name)}_#{parent_table_name}#{suffix}" @join_dependency.table_aliases[name] += 1 if @join_dependency.table_aliases[name] == 1 # First time we've seen this name # Also need to count the aliases from the table_aliases to avoid incorrect count @join_dependency.table_aliases[name] += @join_dependency.count_aliases_from_table_joins(name) end table_index = @join_dependency.table_aliases[name] name = name[0..active_record.connection.table_alias_length-3] + "_#{table_index}" if table_index > 1 else @join_dependency.table_aliases[name] += 1 end name end
def association_join
def association_join return @join if @join aliased_table = Arel::Table.new(table_name, :as => @aliased_table_name, :engine => arel_engine, :columns => klass.columns) parent_table = Arel::Table.new(parent.table_name, :as => parent.aliased_table_name, :engine => arel_engine, :columns => parent.active_record.columns) as_conditions = reflection.options[:conditions] && process_conditions(reflection.options[:conditions], aliased_table_name) @join = case reflection.macro when :has_and_belongs_to_many join_table = Arel::Table.new(options[:join_table], :as => aliased_join_table_name, :engine => arel_engine) fk = options[:foreign_key] || reflection.active_record.to_s.foreign_key klass_fk = options[:association_foreign_key] || klass.to_s.foreign_key [ join_table[fk].eq(parent_table[reflection.active_record.primary_key]), [aliased_table[klass.primary_key].eq(join_table[klass_fk]), as_conditions].reject{ |x| x.blank? } ] when :has_many, :has_one if reflection.options[:through] join_table = Arel::Table.new(through_reflection.klass.table_name, :as => aliased_join_table_name, :engine => arel_engine) jt_as_conditions = through_reflection.options[:conditions] && process_conditions(through_reflection.options[:conditions], aliased_table_name) jt_as_extra = jt_source_extra = jt_sti_extra = nil first_key = second_key = as_extra = nil if through_reflection.macro == :belongs_to jt_primary_key = through_reflection.primary_key_name jt_foreign_key = through_reflection.association_primary_key else jt_primary_key = through_reflection.active_record_primary_key jt_foreign_key = through_reflection.primary_key_name if through_reflection.options[:as] # has_many :through against a polymorphic join jt_as_extra = join_table[through_reflection.options[:as].to_s + '_type'].eq(parent.active_record.base_class.name) end end case source_reflection.macro when :has_many, :has_one if source_reflection.options[:as] first_key = "#{source_reflection.options[:as]}_id" second_key = options[:foreign_key] || primary_key as_extra = aliased_table["#{source_reflection.options[:as]}_type"].eq(source_reflection.active_record.base_class.name) else first_key = through_reflection.klass.base_class.to_s.foreign_key second_key = options[:foreign_key] || primary_key end unless through_reflection.klass.descends_from_active_record? jt_sti_extra = join_table[through_reflection.active_record.inheritance_column].eq(through_reflection.klass.sti_name) end when :belongs_to first_key = primary_key if reflection.options[:source_type] second_key = source_reflection.association_foreign_key jt_source_extra = join_table[reflection.source_reflection.options[:foreign_type]].eq(reflection.options[:source_type]) else second_key = source_reflection.primary_key_name end end [ [parent_table[jt_primary_key].eq(join_table[jt_foreign_key]), jt_as_extra, jt_source_extra, jt_sti_extra, jt_as_conditions].reject{|x| x.blank? }, [aliased_table[first_key].eq(join_table[second_key]), as_extra, as_conditions].reject{ |x| x.blank? } ] elsif reflection.options[:as] id_rel = aliased_table["#{reflection.options[:as]}_id"].eq(parent_table[parent.primary_key]) type_rel = aliased_table["#{reflection.options[:as]}_type"].eq(parent.active_record.base_class.name) [id_rel, type_rel, as_conditions].reject{ |x| x.blank?} else foreign_key = options[:foreign_key] || reflection.active_record.name.foreign_key [aliased_table[foreign_key].eq(parent_table[reflection.options[:primary_key] || parent.primary_key]), as_conditions].reject{ |x| x.blank? } end when :belongs_to [aliased_table[options[:primary_key] || reflection.klass.primary_key].eq(parent_table[options[:foreign_key] || reflection.primary_key_name]), as_conditions].reject{ |x| x.blank? } end unless klass.descends_from_active_record? sti_column = aliased_table[klass.inheritance_column] sti_condition = sti_column.eq(klass.sti_name) klass.descendants.each {|subclass| sti_condition = sti_condition.or(sti_column.eq(subclass.sti_name)) } @join << sti_condition end @join end
def find_parent_in(other_join_dependency)
def find_parent_in(other_join_dependency) other_join_dependency.joins.detect do |join| self.parent == join end end
def initialize(reflection, join_dependency, parent = nil)
def initialize(reflection, join_dependency, parent = nil) reflection.check_validity! if reflection.options[:polymorphic] raise EagerLoadPolymorphicError.new(reflection) end super(reflection.klass) @join_dependency = join_dependency @parent = parent @reflection = reflection @aliased_prefix = "t#{ join_dependency.joins.size }" @parent_table_name = parent.active_record.table_name @aliased_table_name = aliased_table_name_for(table_name) @join = nil @join_type = Arel::InnerJoin if reflection.macro == :has_and_belongs_to_many @aliased_join_table_name = aliased_table_name_for(reflection.options[:join_table], "_join") end if [:has_many, :has_one].include?(reflection.macro) && reflection.options[:through] @aliased_join_table_name = aliased_table_name_for(reflection.through_reflection.klass.table_name, "_join") end end
def join_relation(joining_relation)
def join_relation(joining_relation) self.join_type = Arel::OuterJoin joining_relation.joins(self) end
def pluralize(table_name)
def pluralize(table_name) ActiveRecord::Base.pluralize_table_names ? table_name.to_s.pluralize : table_name end
def process_conditions(conditions, table_name)
def process_conditions(conditions, table_name) sanitized = sanitize_sql(conditions, table_name) if sanitized =~ /\#\{.*\}/ ActiveSupport::Deprecation.warn( 'String-based interpolation of association conditions is deprecated. Please use a ' \ 'proc instead. So, for example, has_many :older_friends, :conditions => \'age > #{age}\' ' \ 'should be changed to has_many :older_friends, :conditions => proc { "age > #{age}" }.' ) instance_eval("%@#{sanitized.gsub('@', '\@')}@", __FILE__, __LINE__) elsif conditions.respond_to?(:to_proc) conditions = sanitize_sql(instance_eval(&conditions), table_name) else sanitized end end
def relation
def relation aliased = Arel::Table.new(table_name, :as => @aliased_table_name, :engine => arel_engine, :columns => klass.columns) if reflection.macro == :has_and_belongs_to_many [Arel::Table.new(options[:join_table], :as => aliased_join_table_name, :engine => arel_engine), aliased] elsif reflection.options[:through] [Arel::Table.new(through_reflection.klass.table_name, :as => aliased_join_table_name, :engine => arel_engine), aliased] else aliased end end
def table_alias_for(table_name, table_alias)
def table_alias_for(table_name, table_alias) "#{table_name} #{table_alias if table_name != table_alias}".strip end
def table_name_and_alias
def table_name_and_alias table_alias_for table_name, @aliased_table_name end