rails/activerecord/lib/active_record.rb
Jon Leighton d7abe91cc7 Set the inverse when association queries are refined
Suppose Man has_many interests, and inverse_of is used.

Man.first.interests.first.man will correctly execute two queries,
avoiding the need for a third query when Interest#man is called. This is
because CollectionAssociation#first calls set_inverse_instance.

However Man.first.interests.where("1=1").first.man will execute three
queries, even though this is obviously a subset of the records in the
association.

This is because calling where("1=1") spawns a new Relation object from
the CollectionProxy object, and the Relation has no knowledge of the
association, so it cannot set the inverse instance.

This commit solves the problem by making relations spawned from
CollectionProxies return a new Relation subclass called
AssociationRelation, which does know about associations. Records loaded
from this class will get the inverse instance set properly.

Fixes #5717.

Live commit from La Conf! 
2013-05-10 10:36:26 +02:00

175 lines
4.7 KiB
Ruby

#--
# Copyright (c) 2004-2013 David Heinemeier Hansson
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
require 'active_support'
require 'active_support/rails'
require 'active_model'
require 'arel'
require 'active_record/deprecated_finders'
require 'active_record/version'
module ActiveRecord
extend ActiveSupport::Autoload
autoload :Base
autoload :Callbacks
autoload :Core
autoload :ConnectionHandling
autoload :CounterCache
autoload :DynamicMatchers
autoload :Explain
autoload :Inheritance
autoload :Integration
autoload :Migration
autoload :Migrator, 'active_record/migration'
autoload :ModelSchema
autoload :NestedAttributes
autoload :Persistence
autoload :QueryCache
autoload :Querying
autoload :ReadonlyAttributes
autoload :Reflection
autoload :RuntimeRegistry
autoload :Sanitization
autoload :Schema
autoload :SchemaDumper
autoload :SchemaMigration
autoload :Scoping
autoload :Serialization
autoload :StatementCache
autoload :Store
autoload :Timestamp
autoload :Transactions
autoload :Translation
autoload :Validations
eager_autoload do
autoload :ActiveRecordError, 'active_record/errors'
autoload :ConnectionNotEstablished, 'active_record/errors'
autoload :ConnectionAdapters, 'active_record/connection_adapters/abstract_adapter'
autoload :Aggregations
autoload :Associations
autoload :AttributeAssignment
autoload :AttributeMethods
autoload :AutosaveAssociation
autoload :Relation
autoload :AssociationRelation
autoload :NullRelation
autoload_under 'relation' do
autoload :QueryMethods
autoload :FinderMethods
autoload :Calculations
autoload :PredicateBuilder
autoload :SpawnMethods
autoload :Batches
autoload :Delegation
end
autoload :Result
end
module Coders
autoload :YAMLColumn, 'active_record/coders/yaml_column'
end
module AttributeMethods
extend ActiveSupport::Autoload
eager_autoload do
autoload :BeforeTypeCast
autoload :Dirty
autoload :PrimaryKey
autoload :Query
autoload :Read
autoload :TimeZoneConversion
autoload :Write
autoload :Serialization
end
end
module Locking
extend ActiveSupport::Autoload
eager_autoload do
autoload :Optimistic
autoload :Pessimistic
end
end
module ConnectionAdapters
extend ActiveSupport::Autoload
eager_autoload do
autoload :AbstractAdapter
autoload :ConnectionManagement, "active_record/connection_adapters/abstract/connection_pool"
end
end
module Scoping
extend ActiveSupport::Autoload
eager_autoload do
autoload :Named
autoload :Default
end
end
module Tasks
extend ActiveSupport::Autoload
autoload :DatabaseTasks
autoload :SQLiteDatabaseTasks, 'active_record/tasks/sqlite_database_tasks'
autoload :MySQLDatabaseTasks, 'active_record/tasks/mysql_database_tasks'
autoload :PostgreSQLDatabaseTasks,
'active_record/tasks/postgresql_database_tasks'
autoload :FirebirdDatabaseTasks, 'active_record/tasks/firebird_database_tasks'
autoload :SqlserverDatabaseTasks, 'active_record/tasks/sqlserver_database_tasks'
autoload :OracleDatabaseTasks, 'active_record/tasks/oracle_database_tasks'
end
autoload :TestCase
autoload :TestFixtures, 'active_record/fixtures'
def self.eager_load!
super
ActiveRecord::Locking.eager_load!
ActiveRecord::Scoping.eager_load!
ActiveRecord::Associations.eager_load!
ActiveRecord::AttributeMethods.eager_load!
ActiveRecord::ConnectionAdapters.eager_load!
end
end
ActiveSupport.on_load(:active_record) do
Arel::Table.engine = self
end
ActiveSupport.on_load(:i18n) do
I18n.load_path << File.dirname(__FILE__) + '/active_record/locale/en.yml'
end