aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/associations.rb
diff options
context:
space:
mode:
authorPratik Naik <pratiknaik@gmail.com>2010-01-14 13:36:33 +0530
committerPratik Naik <pratiknaik@gmail.com>2010-01-16 00:02:46 +0530
commitbed9179aa1496f6d28891cf515af0d7e515ebbab (patch)
treeb0c551489b45f93f66c0d726c55fe000b59803ea /activerecord/lib/active_record/associations.rb
parent1c30ec23fef2479cd037945e57a74e5c89c9ece1 (diff)
downloadrails-bed9179aa1496f6d28891cf515af0d7e515ebbab.tar.gz
rails-bed9179aa1496f6d28891cf515af0d7e515ebbab.tar.bz2
rails-bed9179aa1496f6d28891cf515af0d7e515ebbab.zip
Make scopes use relations under the hood
Diffstat (limited to 'activerecord/lib/active_record/associations.rb')
-rwxr-xr-xactiverecord/lib/active_record/associations.rb219
1 files changed, 96 insertions, 123 deletions
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index 50fd4aafec..d6ecd0a5e3 100755
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1703,24 +1703,30 @@ module ActiveRecord
end
def construct_finder_arel_with_included_associations(options, join_dependency)
- scope = scope(:find)
-
relation = active_relation
for association in join_dependency.join_associations
relation = association.join_relation(relation)
end
- relation = relation.joins(construct_join(options[:joins], scope)).
+ relation = relation.joins(options[:joins]).
select(column_aliases(join_dependency)).
- group(options[:group] || (scope && scope[:group])).
- having(options[:having] || (scope && scope[:having])).
- order(construct_order(options[:order], scope)).
- where(construct_conditions(options[:conditions], scope)).
- from((scope && scope[:from]) || options[:from])
+ group(options[:group]).
+ having(options[:having]).
+ order(options[:order]).
+ where(options[:conditions]).
+ from(options[:from])
+
+ scoped_relation = current_scoped_methods
+ scoped_relation_limit = scoped_relation.taken if scoped_relation
+
+ relation = current_scoped_methods.except(:limit).merge(relation) if current_scoped_methods
- relation = relation.where(construct_arel_limited_ids_condition(options, join_dependency)) if !using_limitable_reflections?(join_dependency.reflections) && ((scope && scope[:limit]) || options[:limit])
- relation = relation.limit(construct_limit(options[:limit], scope)) if using_limitable_reflections?(join_dependency.reflections)
+ if !using_limitable_reflections?(join_dependency.reflections) && ((scoped_relation && scoped_relation.taken) || options[:limit])
+ relation = relation.where(construct_arel_limited_ids_condition(options, join_dependency))
+ end
+
+ relation = relation.limit(options[:limit] || scoped_relation_limit) if using_limitable_reflections?(join_dependency.reflections)
relation
end
@@ -1748,23 +1754,23 @@ module ActiveRecord
end
def construct_finder_sql_for_association_limiting(options, join_dependency)
- scope = scope(:find)
-
relation = active_relation
for association in join_dependency.join_associations
relation = association.join_relation(relation)
end
- relation = relation.joins(construct_join(options[:joins], scope)).
- where(construct_conditions(options[:conditions], scope)).
- group(options[:group] || (scope && scope[:group])).
- having(options[:having] || (scope && scope[:having])).
- order(construct_order(options[:order], scope)).
- limit(construct_limit(options[:limit], scope)).
- offset(construct_limit(options[:offset], scope)).
- from(options[:from]).
- select(connection.distinct("#{connection.quote_table_name table_name}.#{primary_key}", construct_order(options[:order], scope(:find)).join(",")))
+ relation = relation.joins(options[:joins]).
+ where(options[:conditions]).
+ group(options[:group]).
+ having(options[:having]).
+ order(options[:order]).
+ limit(options[:limit]).
+ offset(options[:offset]).
+ from(options[:from])
+
+ relation = current_scoped_methods.except(:select, :includes, :eager_load).merge(relation) if current_scoped_methods
+ relation = relation.select(connection.distinct("#{connection.quote_table_name table_name}.#{primary_key}", options[:order]))
relation.to_sql
end
@@ -2030,118 +2036,85 @@ module ActiveRecord
def association_join
return @join if @join
- connection = reflection.active_record.connection
+
+ aliased_table = Arel::Table.new(table_name, :as => @aliased_table_name, :engine => active_relation_engine)
+ parent_table = Arel::Table.new(parent.table_name, :as => parent.aliased_table_name, :engine => active_relation_engine)
+
@join = case reflection.macro
- when :has_and_belongs_to_many
- ["%s.%s = %s.%s " % [
- 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],
- "%s.%s = %s.%s " % [
- 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
- if reflection.options[:through]
- 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)
- ]
+ when :has_and_belongs_to_many
+ join_table = Arel::Table.new(options[:join_table], :as => aliased_join_table_name, :engine => active_relation_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])
+ ]
+ 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 => active_relation_engine)
+ 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 = join_table[through_reflection.options[:as].to_s + '_type'].eq(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 = aliased_table["#{source_reflection.options[:as]}_type"].eq(source_reflection.active_record.base_class.name)
else
- jt_foreign_key = through_reflection.primary_key_name
+ first_key = through_reflection.klass.base_class.to_s.foreign_key
+ second_key = options[:foreign_key] || primary_key
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 = 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 = " 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
+ 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
-
- ["(%s.%s = %s.%s%s%s%s) " % [
- connection.quote_table_name(parent.aliased_table_name),
- connection.quote_column_name(parent.primary_key),
- connection.quote_table_name(aliased_join_table_name),
- connection.quote_column_name(jt_foreign_key),
- jt_as_extra, jt_source_extra, jt_sti_extra],
- "(%s.%s = %s.%s%s) " % [
- 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]
- ]
-
- elsif reflection.options[:as]
- "%s.%s = %s.%s AND %s.%s = %s" % [
- 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
- "%s.%s = %s.%s " % [
- aliased_table_name,
- foreign_key,
- parent.aliased_table_name,
- reflection.options[:primary_key] || parent.primary_key
- ]
end
- when :belongs_to
- "%s.%s = %s.%s " % [
- connection.quote_table_name(aliased_table_name),
- reflection.klass.primary_key,
- connection.quote_table_name(parent.aliased_table_name),
- options[:foreign_key] || reflection.primary_key_name
+
+ [
+ [parent_table[parent.primary_key].eq(join_table[jt_foreign_key]), jt_as_extra, jt_source_extra, jt_sti_extra].reject{|x| x.blank? },
+ aliased_table[first_key].eq(join_table[second_key])
]
+ 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]
+ 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])]
+ end
+ when :belongs_to
+ [aliased_table[reflection.klass.primary_key].eq(parent_table[options[:foreign_key] || reflection.primary_key_name])]
+ end
+
+ unless klass.descends_from_active_record?
+ sti_column = aliased_table[klass.inheritance_column]
+ sti_condition = sti_column.eq(klass.sti_name)
+ klass.send(:subclasses).each {|subclass| sti_condition = sti_condition.or(sti_column.eq(subclass.sti_name)) }
+
+ @join << sti_condition
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]
+ if ref && ref.options[:conditions]
+ @join << interpolate_sql(sanitize_sql(ref.options[:conditions], aliased_table_name))
+ end
end
@join