Ok...so, I have inherited an old Rails 2.3.14 app that I've recently upgraded to Rails 3.1 (yes I know 6.x is the most recent but baby steps first.)
I've discovered in the original code base what looks like some meta programing that has been done. Three classes have been overridden. Only the last...class AssociationReflection
can be referenced in the Rails 3.1 Activerecord. The other two have been refactored into something else, somewhere else in Rails 3.1 Activerecord.
FYI: what is happening in this code is that alias_method is being used to allow for overrides of the original code with these modified copies.
...I have marked each line that was changed from the original with a ##ORIGINALY:
there are about 7 lines total, 6 of which I need to refactor.
rails_fix.rb
# NOTE:
# This makes brittle code. the instant the original methods aliased here no
# longer exist on the rails 3.1 activeRecord side..this code will break..and
# the app will break. Which is why the new programmer(me) has to fix it.
# This instantly coupled the code to a specific version of rails.
#
# NOTE: this is meta programming ... see SO post
# https://stackoverflow.com/questions/3695839/ruby-on-rails-alias-method-chain-what-exactly-does-it-do
module ActiveRecord
module Associations
module ClassMethods
class JoinDependency
class JoinAssociation
def association_join_with_fix
connection = reflection.active_record.connection
join = case reflection.macro
when :has_and_belongs_to_many
" #{join_type} %s ON %s.%s = %s.%s " % [
table_alias_for(options[:join_table], aliased_join_table_name),
connection.quote_table_name(aliased_join_table_name),
options[:foreign_key] || reflection.active_record.to_s.foreign_key,
connection.quote_table_name(parent.aliased_table_name),
reflection.active_record.primary_key] +
" #{join_type} %s ON %s.%s = %s.%s " % [
table_name_and_alias,
connection.quote_table_name(aliased_table_name),
klass.primary_key,
connection.quote_table_name(aliased_join_table_name),
options[:association_foreign_key] || klass.to_s.foreign_key
]
when :has_many, :has_one
case
when reflection.options[:through]
through_conditions = through_reflection.options[:conditions] ? "AND #{interpolate_sql(sanitize_sql(through_reflection.options[:conditions]))}" : ''
jt_foreign_key = jt_as_extra = jt_source_extra = jt_sti_extra = nil
first_key = second_key = as_extra = nil
if through_reflection.options[:as] # has_many :through against a polymorphic join
jt_foreign_key = through_reflection.options[:as].to_s + '_id'
jt_as_extra = " AND %s.%s = %s" % [
connection.quote_table_name(aliased_join_table_name),
connection.quote_column_name(through_reflection.options[:as].to_s + '_type'),
klass.quote_value(parent.active_record.base_class.name)
]
else
jt_foreign_key = through_reflection.primary_key_name
end
case source_reflection.macro
when :has_many
if source_reflection.options[:as]
first_key = "#{source_reflection.options[:as]}_id"
second_key = options[:foreign_key] || primary_key
as_extra = " AND %s.%s = %s" % [
connection.quote_table_name(aliased_table_name),
connection.quote_column_name("#{source_reflection.options[:as]}_type"),
klass.quote_value(source_reflection.active_record.base_class.name)
]
else
first_key = source_reflection.association_foreign_key ##ORIGINALY: through_reflection.klass.base_class.to_s.foreign_key
second_key = source_reflection.primary_key_name ##ORIGINALY: options[:foreign_key] || primary_key
end
unless through_reflection.klass.descends_from_active_record?
jt_sti_extra = " AND %s.%s = %s" % [
connection.quote_table_name(aliased_join_table_name),
connection.quote_column_name(through_reflection.active_record.inheritance_column),
through_reflection.klass.quote_value(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 = " AND %s.%s = %s" % [
connection.quote_table_name(aliased_join_table_name),
connection.quote_column_name(reflection.source_reflection.options[:foreign_type]),
klass.quote_value(reflection.options[:source_type])
]
else
second_key = source_reflection.primary_key_name
end
end
" #{join_type} %s ON (%s.%s = %s.%s%s%s%s) " % [
table_alias_for(through_reflection.klass.table_name, aliased_join_table_name),
connection.quote_table_name(aliased_join_table_name), ##ORIGINALY: connection.quote_table_name(parent.aliased_table_name),
connection.quote_column_name(parent.primary_key),
connection.quote_table_name(parent.aliased_table_name),##ORIGINALY: connection.quote_table_name(aliased_join_table_name),
connection.quote_column_name(jt_foreign_key),
jt_as_extra, jt_source_extra, jt_sti_extra
] +
" #{join_type} %s ON (%s.%s = %s.%s%s) " % [
table_name_and_alias,
connection.quote_table_name(aliased_table_name),
connection.quote_column_name(first_key),
connection.quote_table_name(aliased_join_table_name),
connection.quote_column_name(second_key),
as_extra
]
when reflection.options[:as] && [:has_many, :has_one].include?(reflection.macro)
" #{join_type} %s ON %s.%s = %s.%s AND %s.%s = %s" % [
table_name_and_alias,
connection.quote_table_name(aliased_table_name),
"#{reflection.options[:as]}_id",
connection.quote_table_name(parent.aliased_table_name),
parent.primary_key,
connection.quote_table_name(aliased_table_name),
"#{reflection.options[:as]}_type",
klass.quote_value(parent.active_record.base_class.name)
]
else
foreign_key = options[:foreign_key] || reflection.active_record.name.foreign_key
" #{join_type} %s ON %s.%s = %s.%s " % [
table_name_and_alias,
aliased_table_name,
foreign_key,
parent.aliased_table_name,
reflection.options[:primary_key] || parent.primary_key
]
end
when :belongs_to
" #{join_type} %s ON %s.%s = %s.%s " % [
table_name_and_alias,
connection.quote_table_name(aliased_table_name),
reflection.klass.primary_key, ##ORIGINALY: reflection.options[:primary_key] || reflection.klass.primary_key,
connection.quote_table_name(parent.aliased_table_name),
options[:foreign_key] || reflection.primary_key_name
]
else
""
end || ''
join << %(AND %s) % [
klass.send(:type_condition, aliased_table_name)] unless klass.descends_from_active_record?
[through_reflection, reflection].each do |ref|
join << "AND #{interpolate_sql(sanitize_sql(ref.options[:conditions], aliased_table_name))} " if ref && ref.options[:conditions]
end
join
end
alias_method_chain :association_join, :fix
end
end
end
end
end
module ActiveRecord
module Associations
class HasManyThroughAssociation
def construct_joins_with_fix(custom_joins = nil)
polymorphic_join = nil
if @reflection.source_reflection.macro == :belongs_to
reflection_primary_key = @reflection.klass.primary_key
source_primary_key = @reflection.source_reflection.primary_key_name
if @reflection.options[:source_type]
polymorphic_join = "AND %s.%s = %s" % [
@reflection.through_reflection.quoted_table_name, "#{@reflection.source_reflection.options[:foreign_type]}",
@owner.class.quote_value(@reflection.options[:source_type])
]
end
else
reflection_primary_key = @reflection.source_reflection.primary_key_name
source_primary_key = @reflection.source_reflection.association_foreign_key ##ORIGINALY: @reflection.through_reflection.klass.primary_key
if @reflection.source_reflection.options[:as]
polymorphic_join = "AND %s.%s = %s" % [
@reflection.quoted_table_name, "#{@reflection.source_reflection.options[:as]}_type",
@owner.class.quote_value(@reflection.through_reflection.klass.name)
]
end
end
"INNER JOIN %s ON %s.%s = %s.%s %s #{@reflection.options[:joins]} #{custom_joins}" % [
@reflection.through_reflection.quoted_table_name,
@reflection.quoted_table_name, reflection_primary_key,
@reflection.through_reflection.quoted_table_name, source_primary_key,
polymorphic_join
]
end
alias_method_chain :construct_joins, :fix
end
end
end
module ActiveRecord
module Reflection
class AssociationReflection
def association_foreign_key_with_fix
@association_foreign_key ||= @options[:primary_key] || class_name.foreign_key ##ORIGINALY: @association_foreign_key ||= @options[:association_foreign_key] || class_name.foreign_key
end
alias_method_chain :association_foreign_key, :fix
end
end
end
NOTE: this is meta programming ... see SO post Ruby on Rails: alias_method_chain, what exactly does it do?
So the Question is: What has...
module ActiveRecord
module Associations
class HasManyThroughAssociation
def construct_joins
...and...
module ActiveRecord
module Associations
module ClassMethods
class JoinDependency
class JoinAssociation
def association_join
...been refactored to and what are the equivalents of the 6 lines Marked "#ORIGINALY:" ?
As I figure I might have to build another version of rails_fix.rb
with the Rails 3.1 versions of the ActiveRecord Association methods. But I don't know what/where that current code is.
I hope this question made sense. Thank you for your time.