activerecord 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +7 -0
 - data/CHANGELOG.md +1372 -0
 - data/MIT-LICENSE +20 -0
 - data/README.rdoc +218 -0
 - data/examples/performance.rb +184 -0
 - data/examples/simple.rb +14 -0
 - data/lib/active_record.rb +173 -0
 - data/lib/active_record/aggregations.rb +266 -0
 - data/lib/active_record/association_relation.rb +22 -0
 - data/lib/active_record/associations.rb +1724 -0
 - data/lib/active_record/associations/alias_tracker.rb +87 -0
 - data/lib/active_record/associations/association.rb +253 -0
 - data/lib/active_record/associations/association_scope.rb +194 -0
 - data/lib/active_record/associations/belongs_to_association.rb +111 -0
 - data/lib/active_record/associations/belongs_to_polymorphic_association.rb +40 -0
 - data/lib/active_record/associations/builder/association.rb +149 -0
 - data/lib/active_record/associations/builder/belongs_to.rb +116 -0
 - data/lib/active_record/associations/builder/collection_association.rb +91 -0
 - data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +124 -0
 - data/lib/active_record/associations/builder/has_many.rb +15 -0
 - data/lib/active_record/associations/builder/has_one.rb +23 -0
 - data/lib/active_record/associations/builder/singular_association.rb +38 -0
 - data/lib/active_record/associations/collection_association.rb +634 -0
 - data/lib/active_record/associations/collection_proxy.rb +1027 -0
 - data/lib/active_record/associations/has_many_association.rb +184 -0
 - data/lib/active_record/associations/has_many_through_association.rb +238 -0
 - data/lib/active_record/associations/has_one_association.rb +105 -0
 - data/lib/active_record/associations/has_one_through_association.rb +36 -0
 - data/lib/active_record/associations/join_dependency.rb +282 -0
 - data/lib/active_record/associations/join_dependency/join_association.rb +122 -0
 - data/lib/active_record/associations/join_dependency/join_base.rb +22 -0
 - data/lib/active_record/associations/join_dependency/join_part.rb +71 -0
 - data/lib/active_record/associations/preloader.rb +203 -0
 - data/lib/active_record/associations/preloader/association.rb +162 -0
 - data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
 - data/lib/active_record/associations/preloader/collection_association.rb +24 -0
 - data/lib/active_record/associations/preloader/has_many.rb +17 -0
 - data/lib/active_record/associations/preloader/has_many_through.rb +19 -0
 - data/lib/active_record/associations/preloader/has_one.rb +23 -0
 - data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
 - data/lib/active_record/associations/preloader/singular_association.rb +21 -0
 - data/lib/active_record/associations/preloader/through_association.rb +96 -0
 - data/lib/active_record/associations/singular_association.rb +86 -0
 - data/lib/active_record/associations/through_association.rb +96 -0
 - data/lib/active_record/attribute.rb +149 -0
 - data/lib/active_record/attribute_assignment.rb +212 -0
 - data/lib/active_record/attribute_decorators.rb +66 -0
 - data/lib/active_record/attribute_methods.rb +439 -0
 - data/lib/active_record/attribute_methods/before_type_cast.rb +71 -0
 - data/lib/active_record/attribute_methods/dirty.rb +181 -0
 - data/lib/active_record/attribute_methods/primary_key.rb +128 -0
 - data/lib/active_record/attribute_methods/query.rb +40 -0
 - data/lib/active_record/attribute_methods/read.rb +103 -0
 - data/lib/active_record/attribute_methods/serialization.rb +70 -0
 - data/lib/active_record/attribute_methods/time_zone_conversion.rb +65 -0
 - data/lib/active_record/attribute_methods/write.rb +83 -0
 - data/lib/active_record/attribute_set.rb +77 -0
 - data/lib/active_record/attribute_set/builder.rb +86 -0
 - data/lib/active_record/attributes.rb +139 -0
 - data/lib/active_record/autosave_association.rb +439 -0
 - data/lib/active_record/base.rb +317 -0
 - data/lib/active_record/callbacks.rb +313 -0
 - data/lib/active_record/coders/json.rb +13 -0
 - data/lib/active_record/coders/yaml_column.rb +38 -0
 - data/lib/active_record/connection_adapters/abstract/connection_pool.rb +659 -0
 - data/lib/active_record/connection_adapters/abstract/database_limits.rb +67 -0
 - data/lib/active_record/connection_adapters/abstract/database_statements.rb +373 -0
 - data/lib/active_record/connection_adapters/abstract/query_cache.rb +95 -0
 - data/lib/active_record/connection_adapters/abstract/quoting.rb +133 -0
 - data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
 - data/lib/active_record/connection_adapters/abstract/schema_creation.rb +125 -0
 - data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +574 -0
 - data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +50 -0
 - data/lib/active_record/connection_adapters/abstract/schema_statements.rb +991 -0
 - data/lib/active_record/connection_adapters/abstract/transaction.rb +219 -0
 - data/lib/active_record/connection_adapters/abstract_adapter.rb +487 -0
 - data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +883 -0
 - data/lib/active_record/connection_adapters/column.rb +82 -0
 - data/lib/active_record/connection_adapters/connection_specification.rb +275 -0
 - data/lib/active_record/connection_adapters/mysql2_adapter.rb +282 -0
 - data/lib/active_record/connection_adapters/mysql_adapter.rb +491 -0
 - data/lib/active_record/connection_adapters/postgresql/array_parser.rb +93 -0
 - data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
 - data/lib/active_record/connection_adapters/postgresql/database_statements.rb +232 -0
 - data/lib/active_record/connection_adapters/postgresql/oid.rb +36 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/array.rb +99 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +14 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +27 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +17 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +97 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
 - data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
 - data/lib/active_record/connection_adapters/postgresql/quoting.rb +108 -0
 - data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
 - data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
 - data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +588 -0
 - data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
 - data/lib/active_record/connection_adapters/postgresql_adapter.rb +754 -0
 - data/lib/active_record/connection_adapters/schema_cache.rb +94 -0
 - data/lib/active_record/connection_adapters/sqlite3_adapter.rb +628 -0
 - data/lib/active_record/connection_adapters/statement_pool.rb +40 -0
 - data/lib/active_record/connection_handling.rb +132 -0
 - data/lib/active_record/core.rb +566 -0
 - data/lib/active_record/counter_cache.rb +175 -0
 - data/lib/active_record/dynamic_matchers.rb +140 -0
 - data/lib/active_record/enum.rb +198 -0
 - data/lib/active_record/errors.rb +252 -0
 - data/lib/active_record/explain.rb +38 -0
 - data/lib/active_record/explain_registry.rb +30 -0
 - data/lib/active_record/explain_subscriber.rb +29 -0
 - data/lib/active_record/fixture_set/file.rb +56 -0
 - data/lib/active_record/fixtures.rb +1007 -0
 - data/lib/active_record/gem_version.rb +15 -0
 - data/lib/active_record/inheritance.rb +247 -0
 - data/lib/active_record/integration.rb +113 -0
 - data/lib/active_record/locale/en.yml +47 -0
 - data/lib/active_record/locking/optimistic.rb +204 -0
 - data/lib/active_record/locking/pessimistic.rb +77 -0
 - data/lib/active_record/log_subscriber.rb +75 -0
 - data/lib/active_record/migration.rb +1051 -0
 - data/lib/active_record/migration/command_recorder.rb +197 -0
 - data/lib/active_record/migration/join_table.rb +15 -0
 - data/lib/active_record/model_schema.rb +340 -0
 - data/lib/active_record/nested_attributes.rb +548 -0
 - data/lib/active_record/no_touching.rb +52 -0
 - data/lib/active_record/null_relation.rb +81 -0
 - data/lib/active_record/persistence.rb +532 -0
 - data/lib/active_record/query_cache.rb +56 -0
 - data/lib/active_record/querying.rb +68 -0
 - data/lib/active_record/railtie.rb +162 -0
 - data/lib/active_record/railties/console_sandbox.rb +5 -0
 - data/lib/active_record/railties/controller_runtime.rb +50 -0
 - data/lib/active_record/railties/databases.rake +391 -0
 - data/lib/active_record/railties/jdbcmysql_error.rb +16 -0
 - data/lib/active_record/readonly_attributes.rb +23 -0
 - data/lib/active_record/reflection.rb +881 -0
 - data/lib/active_record/relation.rb +681 -0
 - data/lib/active_record/relation/batches.rb +138 -0
 - data/lib/active_record/relation/calculations.rb +403 -0
 - data/lib/active_record/relation/delegation.rb +140 -0
 - data/lib/active_record/relation/finder_methods.rb +528 -0
 - data/lib/active_record/relation/merger.rb +170 -0
 - data/lib/active_record/relation/predicate_builder.rb +126 -0
 - data/lib/active_record/relation/predicate_builder/array_handler.rb +47 -0
 - data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
 - data/lib/active_record/relation/query_methods.rb +1176 -0
 - data/lib/active_record/relation/spawn_methods.rb +75 -0
 - data/lib/active_record/result.rb +131 -0
 - data/lib/active_record/runtime_registry.rb +22 -0
 - data/lib/active_record/sanitization.rb +191 -0
 - data/lib/active_record/schema.rb +64 -0
 - data/lib/active_record/schema_dumper.rb +251 -0
 - data/lib/active_record/schema_migration.rb +56 -0
 - data/lib/active_record/scoping.rb +87 -0
 - data/lib/active_record/scoping/default.rb +134 -0
 - data/lib/active_record/scoping/named.rb +164 -0
 - data/lib/active_record/serialization.rb +22 -0
 - data/lib/active_record/serializers/xml_serializer.rb +193 -0
 - data/lib/active_record/statement_cache.rb +111 -0
 - data/lib/active_record/store.rb +205 -0
 - data/lib/active_record/tasks/database_tasks.rb +296 -0
 - data/lib/active_record/tasks/mysql_database_tasks.rb +145 -0
 - data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
 - data/lib/active_record/tasks/sqlite_database_tasks.rb +55 -0
 - data/lib/active_record/timestamp.rb +121 -0
 - data/lib/active_record/transactions.rb +417 -0
 - data/lib/active_record/translation.rb +22 -0
 - data/lib/active_record/type.rb +23 -0
 - data/lib/active_record/type/big_integer.rb +13 -0
 - data/lib/active_record/type/binary.rb +50 -0
 - data/lib/active_record/type/boolean.rb +30 -0
 - data/lib/active_record/type/date.rb +46 -0
 - data/lib/active_record/type/date_time.rb +43 -0
 - data/lib/active_record/type/decimal.rb +40 -0
 - data/lib/active_record/type/decimal_without_scale.rb +11 -0
 - data/lib/active_record/type/decorator.rb +14 -0
 - data/lib/active_record/type/float.rb +19 -0
 - data/lib/active_record/type/hash_lookup_type_map.rb +17 -0
 - data/lib/active_record/type/integer.rb +55 -0
 - data/lib/active_record/type/mutable.rb +16 -0
 - data/lib/active_record/type/numeric.rb +36 -0
 - data/lib/active_record/type/serialized.rb +56 -0
 - data/lib/active_record/type/string.rb +36 -0
 - data/lib/active_record/type/text.rb +11 -0
 - data/lib/active_record/type/time.rb +26 -0
 - data/lib/active_record/type/time_value.rb +38 -0
 - data/lib/active_record/type/type_map.rb +64 -0
 - data/lib/active_record/type/unsigned_integer.rb +15 -0
 - data/lib/active_record/type/value.rb +101 -0
 - data/lib/active_record/validations.rb +90 -0
 - data/lib/active_record/validations/associated.rb +51 -0
 - data/lib/active_record/validations/presence.rb +67 -0
 - data/lib/active_record/validations/uniqueness.rb +229 -0
 - data/lib/active_record/version.rb +8 -0
 - data/lib/rails/generators/active_record.rb +17 -0
 - data/lib/rails/generators/active_record/migration.rb +18 -0
 - data/lib/rails/generators/active_record/migration/migration_generator.rb +70 -0
 - data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +22 -0
 - data/lib/rails/generators/active_record/migration/templates/migration.rb +45 -0
 - data/lib/rails/generators/active_record/model/model_generator.rb +52 -0
 - data/lib/rails/generators/active_record/model/templates/model.rb +10 -0
 - data/lib/rails/generators/active_record/model/templates/module.rb +7 -0
 - metadata +309 -0
 
| 
         @@ -0,0 +1,71 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module ActiveRecord
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Associations
         
     | 
| 
      
 3 
     | 
    
         
            +
                class JoinDependency # :nodoc:
         
     | 
| 
      
 4 
     | 
    
         
            +
                  # A JoinPart represents a part of a JoinDependency. It is inherited
         
     | 
| 
      
 5 
     | 
    
         
            +
                  # by JoinBase and JoinAssociation. A JoinBase represents the Active Record which
         
     | 
| 
      
 6 
     | 
    
         
            +
                  # everything else is being joined onto. A JoinAssociation represents an association which
         
     | 
| 
      
 7 
     | 
    
         
            +
                  # is joining to the base. A JoinAssociation may result in more than one actual join
         
     | 
| 
      
 8 
     | 
    
         
            +
                  # operations (for example a has_and_belongs_to_many JoinAssociation would result in
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # two; one for the join table and one for the target table).
         
     | 
| 
      
 10 
     | 
    
         
            +
                  class JoinPart # :nodoc:
         
     | 
| 
      
 11 
     | 
    
         
            +
                    include Enumerable
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                    # The Active Record class which this join part is associated 'about'; for a JoinBase
         
     | 
| 
      
 14 
     | 
    
         
            +
                    # this is the actual base model, for a JoinAssociation this is the target model of the
         
     | 
| 
      
 15 
     | 
    
         
            +
                    # association.
         
     | 
| 
      
 16 
     | 
    
         
            +
                    attr_reader :base_klass, :children
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                    delegate :table_name, :column_names, :primary_key, :to => :base_klass
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    def initialize(base_klass, children)
         
     | 
| 
      
 21 
     | 
    
         
            +
                      @base_klass = base_klass
         
     | 
| 
      
 22 
     | 
    
         
            +
                      @children = children
         
     | 
| 
      
 23 
     | 
    
         
            +
                    end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                    def name
         
     | 
| 
      
 26 
     | 
    
         
            +
                      reflection.name
         
     | 
| 
      
 27 
     | 
    
         
            +
                    end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                    def match?(other)
         
     | 
| 
      
 30 
     | 
    
         
            +
                      self.class == other.class
         
     | 
| 
      
 31 
     | 
    
         
            +
                    end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                    def each(&block)
         
     | 
| 
      
 34 
     | 
    
         
            +
                      yield self
         
     | 
| 
      
 35 
     | 
    
         
            +
                      children.each { |child| child.each(&block) }
         
     | 
| 
      
 36 
     | 
    
         
            +
                    end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                    # An Arel::Table for the active_record
         
     | 
| 
      
 39 
     | 
    
         
            +
                    def table
         
     | 
| 
      
 40 
     | 
    
         
            +
                      raise NotImplementedError
         
     | 
| 
      
 41 
     | 
    
         
            +
                    end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                    # The alias for the active_record's table
         
     | 
| 
      
 44 
     | 
    
         
            +
                    def aliased_table_name
         
     | 
| 
      
 45 
     | 
    
         
            +
                      raise NotImplementedError
         
     | 
| 
      
 46 
     | 
    
         
            +
                    end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                    def extract_record(row, column_names_with_alias)
         
     | 
| 
      
 49 
     | 
    
         
            +
                      # This code is performance critical as it is called per row.
         
     | 
| 
      
 50 
     | 
    
         
            +
                      # see: https://github.com/rails/rails/pull/12185
         
     | 
| 
      
 51 
     | 
    
         
            +
                      hash = {}
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                      index = 0
         
     | 
| 
      
 54 
     | 
    
         
            +
                      length = column_names_with_alias.length
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                      while index < length
         
     | 
| 
      
 57 
     | 
    
         
            +
                        column_name, alias_name = column_names_with_alias[index]
         
     | 
| 
      
 58 
     | 
    
         
            +
                        hash[column_name] = row[alias_name]
         
     | 
| 
      
 59 
     | 
    
         
            +
                        index += 1
         
     | 
| 
      
 60 
     | 
    
         
            +
                      end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                      hash
         
     | 
| 
      
 63 
     | 
    
         
            +
                    end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                    def instantiate(row, aliases)
         
     | 
| 
      
 66 
     | 
    
         
            +
                      base_klass.instantiate(extract_record(row, aliases))
         
     | 
| 
      
 67 
     | 
    
         
            +
                    end
         
     | 
| 
      
 68 
     | 
    
         
            +
                  end
         
     | 
| 
      
 69 
     | 
    
         
            +
                end
         
     | 
| 
      
 70 
     | 
    
         
            +
              end
         
     | 
| 
      
 71 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,203 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module ActiveRecord
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Associations
         
     | 
| 
      
 3 
     | 
    
         
            +
                # Implements the details of eager loading of Active Record associations.
         
     | 
| 
      
 4 
     | 
    
         
            +
                #
         
     | 
| 
      
 5 
     | 
    
         
            +
                # Suppose that you have the following two Active Record models:
         
     | 
| 
      
 6 
     | 
    
         
            +
                #
         
     | 
| 
      
 7 
     | 
    
         
            +
                #   class Author < ActiveRecord::Base
         
     | 
| 
      
 8 
     | 
    
         
            +
                #     # columns: name, age
         
     | 
| 
      
 9 
     | 
    
         
            +
                #     has_many :books
         
     | 
| 
      
 10 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 11 
     | 
    
         
            +
                #
         
     | 
| 
      
 12 
     | 
    
         
            +
                #   class Book < ActiveRecord::Base
         
     | 
| 
      
 13 
     | 
    
         
            +
                #     # columns: title, sales
         
     | 
| 
      
 14 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 15 
     | 
    
         
            +
                #
         
     | 
| 
      
 16 
     | 
    
         
            +
                # When you load an author with all associated books Active Record will make
         
     | 
| 
      
 17 
     | 
    
         
            +
                # multiple queries like this:
         
     | 
| 
      
 18 
     | 
    
         
            +
                #
         
     | 
| 
      
 19 
     | 
    
         
            +
                #   Author.includes(:books).where(:name => ['bell hooks', 'Homer').to_a
         
     | 
| 
      
 20 
     | 
    
         
            +
                #
         
     | 
| 
      
 21 
     | 
    
         
            +
                #   => SELECT `authors`.* FROM `authors` WHERE `name` IN ('bell hooks', 'Homer')
         
     | 
| 
      
 22 
     | 
    
         
            +
                #   => SELECT `books`.* FROM `books` WHERE `author_id` IN (2, 5)
         
     | 
| 
      
 23 
     | 
    
         
            +
                #
         
     | 
| 
      
 24 
     | 
    
         
            +
                # Active Record saves the ids of the records from the first query to use in
         
     | 
| 
      
 25 
     | 
    
         
            +
                # the second. Depending on the number of associations involved there can be
         
     | 
| 
      
 26 
     | 
    
         
            +
                # arbitrarily many SQL queries made.
         
     | 
| 
      
 27 
     | 
    
         
            +
                #
         
     | 
| 
      
 28 
     | 
    
         
            +
                # However, if there is a WHERE clause that spans across tables Active
         
     | 
| 
      
 29 
     | 
    
         
            +
                # Record will fall back to a slightly more resource-intensive single query:
         
     | 
| 
      
 30 
     | 
    
         
            +
                #
         
     | 
| 
      
 31 
     | 
    
         
            +
                #   Author.includes(:books).where(books: {title: 'Illiad'}).to_a
         
     | 
| 
      
 32 
     | 
    
         
            +
                #   => SELECT `authors`.`id` AS t0_r0, `authors`.`name` AS t0_r1, `authors`.`age` AS t0_r2,
         
     | 
| 
      
 33 
     | 
    
         
            +
                #             `books`.`id`   AS t1_r0, `books`.`title`  AS t1_r1, `books`.`sales` AS t1_r2
         
     | 
| 
      
 34 
     | 
    
         
            +
                #      FROM `authors`
         
     | 
| 
      
 35 
     | 
    
         
            +
                #      LEFT OUTER JOIN `books` ON `authors`.`id` =  `books`.`author_id`
         
     | 
| 
      
 36 
     | 
    
         
            +
                #      WHERE `books`.`title` = 'Illiad'
         
     | 
| 
      
 37 
     | 
    
         
            +
                #
         
     | 
| 
      
 38 
     | 
    
         
            +
                # This could result in many rows that contain redundant data and it performs poorly at scale
         
     | 
| 
      
 39 
     | 
    
         
            +
                # and is therefore only used when necessary.
         
     | 
| 
      
 40 
     | 
    
         
            +
                #
         
     | 
| 
      
 41 
     | 
    
         
            +
                class Preloader #:nodoc:
         
     | 
| 
      
 42 
     | 
    
         
            +
                  extend ActiveSupport::Autoload
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                  eager_autoload do
         
     | 
| 
      
 45 
     | 
    
         
            +
                    autoload :Association,           'active_record/associations/preloader/association'
         
     | 
| 
      
 46 
     | 
    
         
            +
                    autoload :SingularAssociation,   'active_record/associations/preloader/singular_association'
         
     | 
| 
      
 47 
     | 
    
         
            +
                    autoload :CollectionAssociation, 'active_record/associations/preloader/collection_association'
         
     | 
| 
      
 48 
     | 
    
         
            +
                    autoload :ThroughAssociation,    'active_record/associations/preloader/through_association'
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                    autoload :HasMany,             'active_record/associations/preloader/has_many'
         
     | 
| 
      
 51 
     | 
    
         
            +
                    autoload :HasManyThrough,      'active_record/associations/preloader/has_many_through'
         
     | 
| 
      
 52 
     | 
    
         
            +
                    autoload :HasOne,              'active_record/associations/preloader/has_one'
         
     | 
| 
      
 53 
     | 
    
         
            +
                    autoload :HasOneThrough,       'active_record/associations/preloader/has_one_through'
         
     | 
| 
      
 54 
     | 
    
         
            +
                    autoload :BelongsTo,           'active_record/associations/preloader/belongs_to'
         
     | 
| 
      
 55 
     | 
    
         
            +
                  end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  # Eager loads the named associations for the given Active Record record(s).
         
     | 
| 
      
 58 
     | 
    
         
            +
                  #
         
     | 
| 
      
 59 
     | 
    
         
            +
                  # In this description, 'association name' shall refer to the name passed
         
     | 
| 
      
 60 
     | 
    
         
            +
                  # to an association creation method. For example, a model that specifies
         
     | 
| 
      
 61 
     | 
    
         
            +
                  # <tt>belongs_to :author</tt>, <tt>has_many :buyers</tt> has association
         
     | 
| 
      
 62 
     | 
    
         
            +
                  # names +:author+ and +:buyers+.
         
     | 
| 
      
 63 
     | 
    
         
            +
                  #
         
     | 
| 
      
 64 
     | 
    
         
            +
                  # == Parameters
         
     | 
| 
      
 65 
     | 
    
         
            +
                  # +records+ is an array of ActiveRecord::Base. This array needs not be flat,
         
     | 
| 
      
 66 
     | 
    
         
            +
                  # i.e. +records+ itself may also contain arrays of records. In any case,
         
     | 
| 
      
 67 
     | 
    
         
            +
                  # +preload_associations+ will preload the all associations records by
         
     | 
| 
      
 68 
     | 
    
         
            +
                  # flattening +records+.
         
     | 
| 
      
 69 
     | 
    
         
            +
                  #
         
     | 
| 
      
 70 
     | 
    
         
            +
                  # +associations+ specifies one or more associations that you want to
         
     | 
| 
      
 71 
     | 
    
         
            +
                  # preload. It may be:
         
     | 
| 
      
 72 
     | 
    
         
            +
                  # - a Symbol or a String which specifies a single association name. For
         
     | 
| 
      
 73 
     | 
    
         
            +
                  #   example, specifying +:books+ allows this method to preload all books
         
     | 
| 
      
 74 
     | 
    
         
            +
                  #   for an Author.
         
     | 
| 
      
 75 
     | 
    
         
            +
                  # - an Array which specifies multiple association names. This array
         
     | 
| 
      
 76 
     | 
    
         
            +
                  #   is processed recursively. For example, specifying <tt>[:avatar, :books]</tt>
         
     | 
| 
      
 77 
     | 
    
         
            +
                  #   allows this method to preload an author's avatar as well as all of his
         
     | 
| 
      
 78 
     | 
    
         
            +
                  #   books.
         
     | 
| 
      
 79 
     | 
    
         
            +
                  # - a Hash which specifies multiple association names, as well as
         
     | 
| 
      
 80 
     | 
    
         
            +
                  #   association names for the to-be-preloaded association objects. For
         
     | 
| 
      
 81 
     | 
    
         
            +
                  #   example, specifying <tt>{ author: :avatar }</tt> will preload a
         
     | 
| 
      
 82 
     | 
    
         
            +
                  #   book's author, as well as that author's avatar.
         
     | 
| 
      
 83 
     | 
    
         
            +
                  #
         
     | 
| 
      
 84 
     | 
    
         
            +
                  # +:associations+ has the same format as the +:include+ option for
         
     | 
| 
      
 85 
     | 
    
         
            +
                  # <tt>ActiveRecord::Base.find</tt>. So +associations+ could look like this:
         
     | 
| 
      
 86 
     | 
    
         
            +
                  #
         
     | 
| 
      
 87 
     | 
    
         
            +
                  #   :books
         
     | 
| 
      
 88 
     | 
    
         
            +
                  #   [ :books, :author ]
         
     | 
| 
      
 89 
     | 
    
         
            +
                  #   { author: :avatar }
         
     | 
| 
      
 90 
     | 
    
         
            +
                  #   [ :books, { author: :avatar } ]
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                  NULL_RELATION = Struct.new(:values, :bind_values).new({}, [])
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                  def preload(records, associations, preload_scope = nil)
         
     | 
| 
      
 95 
     | 
    
         
            +
                    records       = Array.wrap(records).compact.uniq
         
     | 
| 
      
 96 
     | 
    
         
            +
                    associations  = Array.wrap(associations)
         
     | 
| 
      
 97 
     | 
    
         
            +
                    preload_scope = preload_scope || NULL_RELATION
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                    if records.empty?
         
     | 
| 
      
 100 
     | 
    
         
            +
                      []
         
     | 
| 
      
 101 
     | 
    
         
            +
                    else
         
     | 
| 
      
 102 
     | 
    
         
            +
                      associations.flat_map { |association|
         
     | 
| 
      
 103 
     | 
    
         
            +
                        preloaders_on association, records, preload_scope
         
     | 
| 
      
 104 
     | 
    
         
            +
                      }
         
     | 
| 
      
 105 
     | 
    
         
            +
                    end
         
     | 
| 
      
 106 
     | 
    
         
            +
                  end
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                  private
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                  def preloaders_on(association, records, scope)
         
     | 
| 
      
 111 
     | 
    
         
            +
                    case association
         
     | 
| 
      
 112 
     | 
    
         
            +
                    when Hash
         
     | 
| 
      
 113 
     | 
    
         
            +
                      preloaders_for_hash(association, records, scope)
         
     | 
| 
      
 114 
     | 
    
         
            +
                    when Symbol
         
     | 
| 
      
 115 
     | 
    
         
            +
                      preloaders_for_one(association, records, scope)
         
     | 
| 
      
 116 
     | 
    
         
            +
                    when String
         
     | 
| 
      
 117 
     | 
    
         
            +
                      preloaders_for_one(association.to_sym, records, scope)
         
     | 
| 
      
 118 
     | 
    
         
            +
                    else
         
     | 
| 
      
 119 
     | 
    
         
            +
                      raise ArgumentError, "#{association.inspect} was not recognised for preload"
         
     | 
| 
      
 120 
     | 
    
         
            +
                    end
         
     | 
| 
      
 121 
     | 
    
         
            +
                  end
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
                  def preloaders_for_hash(association, records, scope)
         
     | 
| 
      
 124 
     | 
    
         
            +
                    association.flat_map { |parent, child|
         
     | 
| 
      
 125 
     | 
    
         
            +
                      loaders = preloaders_for_one parent, records, scope
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
                      recs = loaders.flat_map(&:preloaded_records).uniq
         
     | 
| 
      
 128 
     | 
    
         
            +
                      loaders.concat Array.wrap(child).flat_map { |assoc|
         
     | 
| 
      
 129 
     | 
    
         
            +
                        preloaders_on assoc, recs, scope
         
     | 
| 
      
 130 
     | 
    
         
            +
                      }
         
     | 
| 
      
 131 
     | 
    
         
            +
                      loaders
         
     | 
| 
      
 132 
     | 
    
         
            +
                    }
         
     | 
| 
      
 133 
     | 
    
         
            +
                  end
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
                  # Not all records have the same class, so group then preload group on the reflection
         
     | 
| 
      
 136 
     | 
    
         
            +
                  # itself so that if various subclass share the same association then we do not split
         
     | 
| 
      
 137 
     | 
    
         
            +
                  # them unnecessarily
         
     | 
| 
      
 138 
     | 
    
         
            +
                  #
         
     | 
| 
      
 139 
     | 
    
         
            +
                  # Additionally, polymorphic belongs_to associations can have multiple associated
         
     | 
| 
      
 140 
     | 
    
         
            +
                  # classes, depending on the polymorphic_type field. So we group by the classes as
         
     | 
| 
      
 141 
     | 
    
         
            +
                  # well.
         
     | 
| 
      
 142 
     | 
    
         
            +
                  def preloaders_for_one(association, records, scope)
         
     | 
| 
      
 143 
     | 
    
         
            +
                    grouped_records(association, records).flat_map do |reflection, klasses|
         
     | 
| 
      
 144 
     | 
    
         
            +
                      klasses.map do |rhs_klass, rs|
         
     | 
| 
      
 145 
     | 
    
         
            +
                        loader = preloader_for(reflection, rs, rhs_klass).new(rhs_klass, rs, reflection, scope)
         
     | 
| 
      
 146 
     | 
    
         
            +
                        loader.run self
         
     | 
| 
      
 147 
     | 
    
         
            +
                        loader
         
     | 
| 
      
 148 
     | 
    
         
            +
                      end
         
     | 
| 
      
 149 
     | 
    
         
            +
                    end
         
     | 
| 
      
 150 
     | 
    
         
            +
                  end
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
                  def grouped_records(association, records)
         
     | 
| 
      
 153 
     | 
    
         
            +
                    h = {}
         
     | 
| 
      
 154 
     | 
    
         
            +
                    records.each do |record|
         
     | 
| 
      
 155 
     | 
    
         
            +
                      next unless record
         
     | 
| 
      
 156 
     | 
    
         
            +
                      assoc = record.association(association)
         
     | 
| 
      
 157 
     | 
    
         
            +
                      klasses = h[assoc.reflection] ||= {}
         
     | 
| 
      
 158 
     | 
    
         
            +
                      (klasses[assoc.klass] ||= []) << record
         
     | 
| 
      
 159 
     | 
    
         
            +
                    end
         
     | 
| 
      
 160 
     | 
    
         
            +
                    h
         
     | 
| 
      
 161 
     | 
    
         
            +
                  end
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
                  class AlreadyLoaded
         
     | 
| 
      
 164 
     | 
    
         
            +
                    attr_reader :owners, :reflection
         
     | 
| 
      
 165 
     | 
    
         
            +
             
     | 
| 
      
 166 
     | 
    
         
            +
                    def initialize(klass, owners, reflection, preload_scope)
         
     | 
| 
      
 167 
     | 
    
         
            +
                      @owners = owners
         
     | 
| 
      
 168 
     | 
    
         
            +
                      @reflection = reflection
         
     | 
| 
      
 169 
     | 
    
         
            +
                    end
         
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
      
 171 
     | 
    
         
            +
                    def run(preloader); end
         
     | 
| 
      
 172 
     | 
    
         
            +
             
     | 
| 
      
 173 
     | 
    
         
            +
                    def preloaded_records
         
     | 
| 
      
 174 
     | 
    
         
            +
                      owners.flat_map { |owner| owner.association(reflection.name).target }
         
     | 
| 
      
 175 
     | 
    
         
            +
                    end
         
     | 
| 
      
 176 
     | 
    
         
            +
                  end
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
                  class NullPreloader
         
     | 
| 
      
 179 
     | 
    
         
            +
                    def self.new(klass, owners, reflection, preload_scope); self; end
         
     | 
| 
      
 180 
     | 
    
         
            +
                    def self.run(preloader); end
         
     | 
| 
      
 181 
     | 
    
         
            +
                    def self.preloaded_records; []; end
         
     | 
| 
      
 182 
     | 
    
         
            +
                  end
         
     | 
| 
      
 183 
     | 
    
         
            +
             
     | 
| 
      
 184 
     | 
    
         
            +
                  def preloader_for(reflection, owners, rhs_klass)
         
     | 
| 
      
 185 
     | 
    
         
            +
                    return NullPreloader unless rhs_klass
         
     | 
| 
      
 186 
     | 
    
         
            +
             
     | 
| 
      
 187 
     | 
    
         
            +
                    if owners.first.association(reflection.name).loaded?
         
     | 
| 
      
 188 
     | 
    
         
            +
                      return AlreadyLoaded
         
     | 
| 
      
 189 
     | 
    
         
            +
                    end
         
     | 
| 
      
 190 
     | 
    
         
            +
                    reflection.check_preloadable!
         
     | 
| 
      
 191 
     | 
    
         
            +
             
     | 
| 
      
 192 
     | 
    
         
            +
                    case reflection.macro
         
     | 
| 
      
 193 
     | 
    
         
            +
                    when :has_many
         
     | 
| 
      
 194 
     | 
    
         
            +
                      reflection.options[:through] ? HasManyThrough : HasMany
         
     | 
| 
      
 195 
     | 
    
         
            +
                    when :has_one
         
     | 
| 
      
 196 
     | 
    
         
            +
                      reflection.options[:through] ? HasOneThrough : HasOne
         
     | 
| 
      
 197 
     | 
    
         
            +
                    when :belongs_to
         
     | 
| 
      
 198 
     | 
    
         
            +
                      BelongsTo
         
     | 
| 
      
 199 
     | 
    
         
            +
                    end
         
     | 
| 
      
 200 
     | 
    
         
            +
                  end
         
     | 
| 
      
 201 
     | 
    
         
            +
                end
         
     | 
| 
      
 202 
     | 
    
         
            +
              end
         
     | 
| 
      
 203 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,162 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module ActiveRecord
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Associations
         
     | 
| 
      
 3 
     | 
    
         
            +
                class Preloader
         
     | 
| 
      
 4 
     | 
    
         
            +
                  class Association #:nodoc:
         
     | 
| 
      
 5 
     | 
    
         
            +
                    attr_reader :owners, :reflection, :preload_scope, :model, :klass
         
     | 
| 
      
 6 
     | 
    
         
            +
                    attr_reader :preloaded_records
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                    def initialize(klass, owners, reflection, preload_scope)
         
     | 
| 
      
 9 
     | 
    
         
            +
                      @klass         = klass
         
     | 
| 
      
 10 
     | 
    
         
            +
                      @owners        = owners
         
     | 
| 
      
 11 
     | 
    
         
            +
                      @reflection    = reflection
         
     | 
| 
      
 12 
     | 
    
         
            +
                      @preload_scope = preload_scope
         
     | 
| 
      
 13 
     | 
    
         
            +
                      @model         = owners.first && owners.first.class
         
     | 
| 
      
 14 
     | 
    
         
            +
                      @scope         = nil
         
     | 
| 
      
 15 
     | 
    
         
            +
                      @owners_by_key = nil
         
     | 
| 
      
 16 
     | 
    
         
            +
                      @preloaded_records = []
         
     | 
| 
      
 17 
     | 
    
         
            +
                    end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                    def run(preloader)
         
     | 
| 
      
 20 
     | 
    
         
            +
                      preload(preloader)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                    def preload(preloader)
         
     | 
| 
      
 24 
     | 
    
         
            +
                      raise NotImplementedError
         
     | 
| 
      
 25 
     | 
    
         
            +
                    end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                    def scope
         
     | 
| 
      
 28 
     | 
    
         
            +
                      @scope ||= build_scope
         
     | 
| 
      
 29 
     | 
    
         
            +
                    end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                    def records_for(ids)
         
     | 
| 
      
 32 
     | 
    
         
            +
                      query_scope(ids)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                    def query_scope(ids)
         
     | 
| 
      
 36 
     | 
    
         
            +
                      scope.where(association_key.in(ids))
         
     | 
| 
      
 37 
     | 
    
         
            +
                    end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                    def table
         
     | 
| 
      
 40 
     | 
    
         
            +
                      klass.arel_table
         
     | 
| 
      
 41 
     | 
    
         
            +
                    end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                    # The name of the key on the associated records
         
     | 
| 
      
 44 
     | 
    
         
            +
                    def association_key_name
         
     | 
| 
      
 45 
     | 
    
         
            +
                      raise NotImplementedError
         
     | 
| 
      
 46 
     | 
    
         
            +
                    end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                    # This is overridden by HABTM as the condition should be on the foreign_key column in
         
     | 
| 
      
 49 
     | 
    
         
            +
                    # the join table
         
     | 
| 
      
 50 
     | 
    
         
            +
                    def association_key
         
     | 
| 
      
 51 
     | 
    
         
            +
                      table[association_key_name]
         
     | 
| 
      
 52 
     | 
    
         
            +
                    end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                    # The name of the key on the model which declares the association
         
     | 
| 
      
 55 
     | 
    
         
            +
                    def owner_key_name
         
     | 
| 
      
 56 
     | 
    
         
            +
                      raise NotImplementedError
         
     | 
| 
      
 57 
     | 
    
         
            +
                    end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                    def owners_by_key
         
     | 
| 
      
 60 
     | 
    
         
            +
                      @owners_by_key ||= if key_conversion_required?
         
     | 
| 
      
 61 
     | 
    
         
            +
                                           owners.group_by do |owner|
         
     | 
| 
      
 62 
     | 
    
         
            +
                                             owner[owner_key_name].to_s
         
     | 
| 
      
 63 
     | 
    
         
            +
                                           end
         
     | 
| 
      
 64 
     | 
    
         
            +
                                         else
         
     | 
| 
      
 65 
     | 
    
         
            +
                                           owners.group_by do |owner|
         
     | 
| 
      
 66 
     | 
    
         
            +
                                             owner[owner_key_name]
         
     | 
| 
      
 67 
     | 
    
         
            +
                                           end
         
     | 
| 
      
 68 
     | 
    
         
            +
                                         end
         
     | 
| 
      
 69 
     | 
    
         
            +
                    end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                    def options
         
     | 
| 
      
 72 
     | 
    
         
            +
                      reflection.options
         
     | 
| 
      
 73 
     | 
    
         
            +
                    end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                    private
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                    def associated_records_by_owner(preloader)
         
     | 
| 
      
 78 
     | 
    
         
            +
                      owners_map = owners_by_key
         
     | 
| 
      
 79 
     | 
    
         
            +
                      owner_keys = owners_map.keys.compact
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                      # Each record may have multiple owners, and vice-versa
         
     | 
| 
      
 82 
     | 
    
         
            +
                      records_by_owner = owners.each_with_object({}) do |owner,h|
         
     | 
| 
      
 83 
     | 
    
         
            +
                        h[owner] = []
         
     | 
| 
      
 84 
     | 
    
         
            +
                      end
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                      if owner_keys.any?
         
     | 
| 
      
 87 
     | 
    
         
            +
                        # Some databases impose a limit on the number of ids in a list (in Oracle it's 1000)
         
     | 
| 
      
 88 
     | 
    
         
            +
                        # Make several smaller queries if necessary or make one query if the adapter supports it
         
     | 
| 
      
 89 
     | 
    
         
            +
                        sliced  = owner_keys.each_slice(klass.connection.in_clause_length || owner_keys.size)
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                        records = load_slices sliced
         
     | 
| 
      
 92 
     | 
    
         
            +
                        records.each do |record, owner_key|
         
     | 
| 
      
 93 
     | 
    
         
            +
                          owners_map[owner_key].each do |owner|
         
     | 
| 
      
 94 
     | 
    
         
            +
                            records_by_owner[owner] << record
         
     | 
| 
      
 95 
     | 
    
         
            +
                          end
         
     | 
| 
      
 96 
     | 
    
         
            +
                        end
         
     | 
| 
      
 97 
     | 
    
         
            +
                      end
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                      records_by_owner
         
     | 
| 
      
 100 
     | 
    
         
            +
                    end
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                    def key_conversion_required?
         
     | 
| 
      
 103 
     | 
    
         
            +
                      association_key_type != owner_key_type
         
     | 
| 
      
 104 
     | 
    
         
            +
                    end
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                    def association_key_type
         
     | 
| 
      
 107 
     | 
    
         
            +
                      @klass.type_for_attribute(association_key_name.to_s).type
         
     | 
| 
      
 108 
     | 
    
         
            +
                    end
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                    def owner_key_type
         
     | 
| 
      
 111 
     | 
    
         
            +
                      @model.type_for_attribute(owner_key_name.to_s).type
         
     | 
| 
      
 112 
     | 
    
         
            +
                    end
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
                    def load_slices(slices)
         
     | 
| 
      
 115 
     | 
    
         
            +
                      @preloaded_records = slices.flat_map { |slice|
         
     | 
| 
      
 116 
     | 
    
         
            +
                        records_for(slice)
         
     | 
| 
      
 117 
     | 
    
         
            +
                      }
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
                      @preloaded_records.map { |record|
         
     | 
| 
      
 120 
     | 
    
         
            +
                        key = record[association_key_name]
         
     | 
| 
      
 121 
     | 
    
         
            +
                        key = key.to_s if key_conversion_required?
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
                        [record, key]
         
     | 
| 
      
 124 
     | 
    
         
            +
                      }
         
     | 
| 
      
 125 
     | 
    
         
            +
                    end
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
                    def reflection_scope
         
     | 
| 
      
 128 
     | 
    
         
            +
                      @reflection_scope ||= reflection.scope ? klass.unscoped.instance_exec(nil, &reflection.scope) : klass.unscoped
         
     | 
| 
      
 129 
     | 
    
         
            +
                    end
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
                    def build_scope
         
     | 
| 
      
 132 
     | 
    
         
            +
                      scope = klass.unscoped
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
                      values         = reflection_scope.values
         
     | 
| 
      
 135 
     | 
    
         
            +
                      reflection_binds = reflection_scope.bind_values
         
     | 
| 
      
 136 
     | 
    
         
            +
                      preload_values = preload_scope.values
         
     | 
| 
      
 137 
     | 
    
         
            +
                      preload_binds  = preload_scope.bind_values
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
                      scope.where_values      = Array(values[:where])      + Array(preload_values[:where])
         
     | 
| 
      
 140 
     | 
    
         
            +
                      scope.references_values = Array(values[:references]) + Array(preload_values[:references])
         
     | 
| 
      
 141 
     | 
    
         
            +
                      scope.bind_values       = (reflection_binds + preload_binds)
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
                      scope._select!   preload_values[:select] || values[:select] || table[Arel.star]
         
     | 
| 
      
 144 
     | 
    
         
            +
                      scope.includes! preload_values[:includes] || values[:includes]
         
     | 
| 
      
 145 
     | 
    
         
            +
                      scope.joins! preload_values[:joins] || values[:joins]
         
     | 
| 
      
 146 
     | 
    
         
            +
                      scope.order! preload_values[:order] || values[:order]
         
     | 
| 
      
 147 
     | 
    
         
            +
             
     | 
| 
      
 148 
     | 
    
         
            +
                      if preload_values[:readonly] || values[:readonly]
         
     | 
| 
      
 149 
     | 
    
         
            +
                        scope.readonly!
         
     | 
| 
      
 150 
     | 
    
         
            +
                      end
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
                      if options[:as]
         
     | 
| 
      
 153 
     | 
    
         
            +
                        scope.where!(klass.table_name => { reflection.type => model.base_class.sti_name })
         
     | 
| 
      
 154 
     | 
    
         
            +
                      end
         
     | 
| 
      
 155 
     | 
    
         
            +
             
     | 
| 
      
 156 
     | 
    
         
            +
                      scope.unscope_values = Array(values[:unscope])
         
     | 
| 
      
 157 
     | 
    
         
            +
                      klass.default_scoped.merge(scope)
         
     | 
| 
      
 158 
     | 
    
         
            +
                    end
         
     | 
| 
      
 159 
     | 
    
         
            +
                  end
         
     | 
| 
      
 160 
     | 
    
         
            +
                end
         
     | 
| 
      
 161 
     | 
    
         
            +
              end
         
     | 
| 
      
 162 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module ActiveRecord
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Associations
         
     | 
| 
      
 3 
     | 
    
         
            +
                class Preloader
         
     | 
| 
      
 4 
     | 
    
         
            +
                  class BelongsTo < SingularAssociation #:nodoc:
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                    def association_key_name
         
     | 
| 
      
 7 
     | 
    
         
            +
                      reflection.options[:primary_key] || klass && klass.primary_key
         
     | 
| 
      
 8 
     | 
    
         
            +
                    end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                    def owner_key_name
         
     | 
| 
      
 11 
     | 
    
         
            +
                      reflection.foreign_key
         
     | 
| 
      
 12 
     | 
    
         
            +
                    end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     |