activerecord 4.2.11.1 → 5.0.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 +5 -5
- data/CHANGELOG.md +1282 -1195
- data/MIT-LICENSE +2 -2
- data/README.rdoc +7 -8
- data/examples/performance.rb +2 -3
- data/examples/simple.rb +0 -1
- data/lib/active_record.rb +8 -4
- data/lib/active_record/aggregations.rb +35 -24
- data/lib/active_record/association_relation.rb +3 -3
- data/lib/active_record/associations.rb +317 -209
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +11 -9
- data/lib/active_record/associations/association_scope.rb +73 -102
- data/lib/active_record/associations/belongs_to_association.rb +21 -32
- data/lib/active_record/associations/builder/association.rb +28 -34
- data/lib/active_record/associations/builder/belongs_to.rb +43 -18
- data/lib/active_record/associations/builder/collection_association.rb +7 -19
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +14 -11
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +11 -6
- data/lib/active_record/associations/builder/singular_association.rb +3 -10
- data/lib/active_record/associations/collection_association.rb +49 -41
- data/lib/active_record/associations/collection_proxy.rb +67 -27
- data/lib/active_record/associations/foreign_association.rb +1 -1
- data/lib/active_record/associations/has_many_association.rb +20 -71
- data/lib/active_record/associations/has_many_through_association.rb +8 -47
- data/lib/active_record/associations/has_one_association.rb +12 -5
- data/lib/active_record/associations/join_dependency.rb +29 -19
- data/lib/active_record/associations/join_dependency/join_association.rb +16 -10
- data/lib/active_record/associations/preloader.rb +14 -4
- data/lib/active_record/associations/preloader/association.rb +46 -52
- data/lib/active_record/associations/preloader/collection_association.rb +0 -6
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/has_one.rb +0 -8
- data/lib/active_record/associations/preloader/through_association.rb +27 -14
- data/lib/active_record/associations/singular_association.rb +7 -1
- data/lib/active_record/associations/through_association.rb +11 -3
- data/lib/active_record/attribute.rb +68 -18
- data/lib/active_record/attribute/user_provided_default.rb +28 -0
- data/lib/active_record/attribute_assignment.rb +19 -140
- data/lib/active_record/attribute_decorators.rb +6 -5
- data/lib/active_record/attribute_methods.rb +76 -47
- data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
- data/lib/active_record/attribute_methods/dirty.rb +46 -86
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +31 -59
- data/lib/active_record/attribute_methods/serialization.rb +13 -16
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
- data/lib/active_record/attribute_methods/write.rb +13 -37
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set.rb +30 -3
- data/lib/active_record/attribute_set/builder.rb +6 -4
- data/lib/active_record/attributes.rb +199 -81
- data/lib/active_record/autosave_association.rb +49 -16
- data/lib/active_record/base.rb +32 -23
- data/lib/active_record/callbacks.rb +39 -43
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +20 -8
- data/lib/active_record/collection_cache_key.rb +40 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +452 -182
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -61
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -10
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -185
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +380 -141
- data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
- data/lib/active_record/connection_adapters/abstract_adapter.rb +141 -59
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +401 -370
- data/lib/active_record/connection_adapters/column.rb +28 -43
- data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +29 -166
- data/lib/active_record/connection_adapters/postgresql/column.rb +5 -10
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +10 -72
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +27 -57
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -18
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +234 -148
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +248 -160
- data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +149 -192
- data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
- data/lib/active_record/connection_handling.rb +37 -14
- data/lib/active_record/core.rb +89 -107
- data/lib/active_record/counter_cache.rb +13 -24
- data/lib/active_record/dynamic_matchers.rb +1 -20
- data/lib/active_record/enum.rb +113 -76
- data/lib/active_record/errors.rb +87 -48
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +26 -5
- data/lib/active_record/fixtures.rb +76 -40
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +32 -40
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/internal_metadata.rb +56 -0
- data/lib/active_record/legacy_yaml_adapter.rb +18 -2
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +15 -15
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +43 -21
- data/lib/active_record/migration.rb +363 -133
- data/lib/active_record/migration/command_recorder.rb +59 -18
- data/lib/active_record/migration/compatibility.rb +126 -0
- data/lib/active_record/model_schema.rb +129 -41
- data/lib/active_record/nested_attributes.rb +58 -29
- data/lib/active_record/null_relation.rb +16 -8
- data/lib/active_record/persistence.rb +121 -80
- data/lib/active_record/query_cache.rb +15 -18
- data/lib/active_record/querying.rb +10 -9
- data/lib/active_record/railtie.rb +23 -16
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +69 -46
- data/lib/active_record/readonly_attributes.rb +1 -1
- data/lib/active_record/reflection.rb +282 -115
- data/lib/active_record/relation.rb +176 -116
- data/lib/active_record/relation/batches.rb +139 -34
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/calculations.rb +79 -108
- data/lib/active_record/relation/delegation.rb +7 -20
- data/lib/active_record/relation/finder_methods.rb +163 -81
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +16 -42
- data/lib/active_record/relation/predicate_builder.rb +120 -107
- data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +308 -244
- data/lib/active_record/relation/record_fetch_warning.rb +49 -0
- data/lib/active_record/relation/spawn_methods.rb +4 -7
- data/lib/active_record/relation/where_clause.rb +174 -0
- data/lib/active_record/relation/where_clause_factory.rb +38 -0
- data/lib/active_record/result.rb +4 -3
- data/lib/active_record/runtime_registry.rb +1 -1
- data/lib/active_record/sanitization.rb +95 -66
- data/lib/active_record/schema.rb +26 -22
- data/lib/active_record/schema_dumper.rb +62 -38
- data/lib/active_record/schema_migration.rb +11 -14
- data/lib/active_record/scoping.rb +32 -15
- data/lib/active_record/scoping/default.rb +23 -9
- data/lib/active_record/scoping/named.rb +49 -28
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +2 -4
- data/lib/active_record/statement_cache.rb +16 -14
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +58 -0
- data/lib/active_record/table_metadata.rb +68 -0
- data/lib/active_record/tasks/database_tasks.rb +57 -43
- data/lib/active_record/tasks/mysql_database_tasks.rb +6 -14
- data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -2
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +20 -9
- data/lib/active_record/touch_later.rb +58 -0
- data/lib/active_record/transactions.rb +138 -56
- data/lib/active_record/type.rb +66 -17
- data/lib/active_record/type/adapter_specific_registry.rb +130 -0
- data/lib/active_record/type/date.rb +2 -45
- data/lib/active_record/type/date_time.rb +2 -49
- data/lib/active_record/type/internal/abstract_json.rb +29 -0
- data/lib/active_record/type/internal/timezone.rb +15 -0
- data/lib/active_record/type/serialized.rb +15 -14
- data/lib/active_record/type/time.rb +10 -16
- data/lib/active_record/type/type_map.rb +4 -4
- data/lib/active_record/type_caster.rb +7 -0
- data/lib/active_record/type_caster/connection.rb +29 -0
- data/lib/active_record/type_caster/map.rb +19 -0
- data/lib/active_record/validations.rb +33 -32
- data/lib/active_record/validations/absence.rb +23 -0
- data/lib/active_record/validations/associated.rb +10 -3
- data/lib/active_record/validations/length.rb +24 -0
- data/lib/active_record/validations/presence.rb +11 -12
- data/lib/active_record/validations/uniqueness.rb +30 -29
- data/lib/rails/generators/active_record/migration.rb +7 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
- data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +32 -15
- data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
- metadata +59 -34
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/serializers/xml_serializer.rb +0 -193
- data/lib/active_record/type/big_integer.rb +0 -13
- data/lib/active_record/type/binary.rb +0 -50
- data/lib/active_record/type/boolean.rb +0 -31
- data/lib/active_record/type/decimal.rb +0 -64
- data/lib/active_record/type/decimal_without_scale.rb +0 -11
- data/lib/active_record/type/decorator.rb +0 -14
- data/lib/active_record/type/float.rb +0 -19
- data/lib/active_record/type/integer.rb +0 -59
- data/lib/active_record/type/mutable.rb +0 -16
- data/lib/active_record/type/numeric.rb +0 -36
- data/lib/active_record/type/string.rb +0 -40
- data/lib/active_record/type/text.rb +0 -11
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/unsigned_integer.rb +0 -15
- data/lib/active_record/type/value.rb +0 -110
| @@ -1,15 +1,13 @@ | |
| 1 | 
            -
            require 'set'
         | 
| 2 1 | 
             
            require 'active_support/concern'
         | 
| 3 | 
            -
            require 'active_support/deprecation'
         | 
| 4 2 |  | 
| 5 3 | 
             
            module ActiveRecord
         | 
| 6 4 | 
             
              module Delegation # :nodoc:
         | 
| 7 | 
            -
                module DelegateCache
         | 
| 8 | 
            -
                  def relation_delegate_class(klass) | 
| 5 | 
            +
                module DelegateCache # :nodoc:
         | 
| 6 | 
            +
                  def relation_delegate_class(klass)
         | 
| 9 7 | 
             
                    @relation_delegate_cache[klass]
         | 
| 10 8 | 
             
                  end
         | 
| 11 9 |  | 
| 12 | 
            -
                  def initialize_relation_delegate_cache | 
| 10 | 
            +
                  def initialize_relation_delegate_cache
         | 
| 13 11 | 
             
                    @relation_delegate_cache = cache = {}
         | 
| 14 12 | 
             
                    [
         | 
| 15 13 | 
             
                      ActiveRecord::Relation,
         | 
| @@ -19,7 +17,7 @@ module ActiveRecord | |
| 19 17 | 
             
                      delegate = Class.new(klass) {
         | 
| 20 18 | 
             
                        include ClassSpecificRelation
         | 
| 21 19 | 
             
                      }
         | 
| 22 | 
            -
                      const_set klass.name.gsub('::', '_'), delegate
         | 
| 20 | 
            +
                      const_set klass.name.gsub('::'.freeze, '_'.freeze), delegate
         | 
| 23 21 | 
             
                      cache[klass] = delegate
         | 
| 24 22 | 
             
                    end
         | 
| 25 23 | 
             
                  end
         | 
| @@ -37,13 +35,9 @@ module ActiveRecord | |
| 37 35 | 
             
                # may vary depending on the klass of a relation, so we create a subclass of Relation
         | 
| 38 36 | 
             
                # for each different klass, and the delegations are compiled into that subclass only.
         | 
| 39 37 |  | 
| 40 | 
            -
                 | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
                  :keep_if, :pop, :shift, :delete_at, :select!
         | 
| 44 | 
            -
                ].to_set # :nodoc:
         | 
| 45 | 
            -
             | 
| 46 | 
            -
                delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to_ary, :join, to: :to_a
         | 
| 38 | 
            +
                delegate :to_xml, :encode_with, :length, :collect, :map, :each, :all?, :include?, :to_ary, :join,
         | 
| 39 | 
            +
                         :[], :&, :|, :+, :-, :sample, :reverse, :compact, :in_groups, :in_groups_of,
         | 
| 40 | 
            +
                         :shuffle, :split, to: :records
         | 
| 47 41 |  | 
| 48 42 | 
             
                delegate :table_name, :quoted_table_name, :primary_key, :quoted_primary_key,
         | 
| 49 43 | 
             
                         :connection, :columns_hash, :to => :klass
         | 
| @@ -115,21 +109,14 @@ module ActiveRecord | |
| 115 109 |  | 
| 116 110 | 
             
                def respond_to?(method, include_private = false)
         | 
| 117 111 | 
             
                  super || @klass.respond_to?(method, include_private) ||
         | 
| 118 | 
            -
                    array_delegable?(method) ||
         | 
| 119 112 | 
             
                    arel.respond_to?(method, include_private)
         | 
| 120 113 | 
             
                end
         | 
| 121 114 |  | 
| 122 115 | 
             
                protected
         | 
| 123 116 |  | 
| 124 | 
            -
                def array_delegable?(method)
         | 
| 125 | 
            -
                  Array.method_defined?(method) && BLACKLISTED_ARRAY_METHODS.exclude?(method)
         | 
| 126 | 
            -
                end
         | 
| 127 | 
            -
             | 
| 128 117 | 
             
                def method_missing(method, *args, &block)
         | 
| 129 118 | 
             
                  if @klass.respond_to?(method)
         | 
| 130 119 | 
             
                    scoping { @klass.public_send(method, *args, &block) }
         | 
| 131 | 
            -
                  elsif array_delegable?(method)
         | 
| 132 | 
            -
                    to_a.public_send(method, *args, &block)
         | 
| 133 120 | 
             
                  elsif arel.respond_to?(method)
         | 
| 134 121 | 
             
                    arel.public_send(method, *args, &block)
         | 
| 135 122 | 
             
                  else
         | 
| @@ -1,4 +1,3 @@ | |
| 1 | 
            -
            require 'active_support/deprecation'
         | 
| 2 1 | 
             
            require 'active_support/core_ext/string/filters'
         | 
| 3 2 |  | 
| 4 3 | 
             
            module ActiveRecord
         | 
| @@ -6,7 +5,7 @@ module ActiveRecord | |
| 6 5 | 
             
                ONE_AS_ONE = '1 AS one'
         | 
| 7 6 |  | 
| 8 7 | 
             
                # Find by id - This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]).
         | 
| 9 | 
            -
                # If  | 
| 8 | 
            +
                # If one or more records can not be found for the requested ids, then RecordNotFound will be raised. If the primary key
         | 
| 10 9 | 
             
                # is an integer, find by id coerces its arguments using +to_i+.
         | 
| 11 10 | 
             
                #
         | 
| 12 11 | 
             
                #   Person.find(1)          # returns the object for ID = 1
         | 
| @@ -17,10 +16,8 @@ module ActiveRecord | |
| 17 16 | 
             
                #   Person.find([1])        # returns an array for the object with ID = 1
         | 
| 18 17 | 
             
                #   Person.where("administrator = 1").order("created_on DESC").find(1)
         | 
| 19 18 | 
             
                #
         | 
| 20 | 
            -
                # <tt>ActiveRecord::RecordNotFound</tt> will be raised if one or more ids are not found.
         | 
| 21 | 
            -
                #
         | 
| 22 19 | 
             
                # NOTE: The returned records may not be in the same order as the ids you
         | 
| 23 | 
            -
                # provide since database rows are unordered. You'd need to provide an explicit  | 
| 20 | 
            +
                # provide since database rows are unordered. You'd need to provide an explicit QueryMethods#order
         | 
| 24 21 | 
             
                # option if you want the results are sorted.
         | 
| 25 22 | 
             
                #
         | 
| 26 23 | 
             
                # ==== Find with lock
         | 
| @@ -37,7 +34,7 @@ module ActiveRecord | |
| 37 34 | 
             
                #     person.save!
         | 
| 38 35 | 
             
                #   end
         | 
| 39 36 | 
             
                #
         | 
| 40 | 
            -
                # ==== Variations of  | 
| 37 | 
            +
                # ==== Variations of #find
         | 
| 41 38 | 
             
                #
         | 
| 42 39 | 
             
                #   Person.where(name: 'Spartacus', rating: 4)
         | 
| 43 40 | 
             
                #   # returns a chainable list (which can be empty).
         | 
| @@ -45,13 +42,13 @@ module ActiveRecord | |
| 45 42 | 
             
                #   Person.find_by(name: 'Spartacus', rating: 4)
         | 
| 46 43 | 
             
                #   # returns the first item or nil.
         | 
| 47 44 | 
             
                #
         | 
| 48 | 
            -
                #   Person. | 
| 45 | 
            +
                #   Person.find_or_initialize_by(name: 'Spartacus', rating: 4)
         | 
| 49 46 | 
             
                #   # returns the first item or returns a new instance (requires you call .save to persist against the database).
         | 
| 50 47 | 
             
                #
         | 
| 51 | 
            -
                #   Person. | 
| 52 | 
            -
                #   # returns the first item or creates it and returns it | 
| 48 | 
            +
                #   Person.find_or_create_by(name: 'Spartacus', rating: 4)
         | 
| 49 | 
            +
                #   # returns the first item or creates it and returns it.
         | 
| 53 50 | 
             
                #
         | 
| 54 | 
            -
                # ==== Alternatives for  | 
| 51 | 
            +
                # ==== Alternatives for #find
         | 
| 55 52 | 
             
                #
         | 
| 56 53 | 
             
                #   Person.where(name: 'Spartacus', rating: 4).exists?(conditions = :none)
         | 
| 57 54 | 
             
                #   # returns a boolean indicating if any record with the given conditions exist.
         | 
| @@ -60,16 +57,13 @@ module ActiveRecord | |
| 60 57 | 
             
                #   # returns a chainable list of instances with only the mentioned fields.
         | 
| 61 58 | 
             
                #
         | 
| 62 59 | 
             
                #   Person.where(name: 'Spartacus', rating: 4).ids
         | 
| 63 | 
            -
                #   # returns an Array of ids | 
| 60 | 
            +
                #   # returns an Array of ids.
         | 
| 64 61 | 
             
                #
         | 
| 65 62 | 
             
                #   Person.where(name: 'Spartacus', rating: 4).pluck(:field1, :field2)
         | 
| 66 | 
            -
                #   # returns an Array of the required fields | 
| 63 | 
            +
                #   # returns an Array of the required fields.
         | 
| 67 64 | 
             
                def find(*args)
         | 
| 68 | 
            -
                  if block_given?
         | 
| 69 | 
            -
             | 
| 70 | 
            -
                  else
         | 
| 71 | 
            -
                    find_with_ids(*args)
         | 
| 72 | 
            -
                  end
         | 
| 65 | 
            +
                  return super if block_given?
         | 
| 66 | 
            +
                  find_with_ids(*args)
         | 
| 73 67 | 
             
                end
         | 
| 74 68 |  | 
| 75 69 | 
             
                # Finds the first record matching the specified conditions. There
         | 
| @@ -80,18 +74,19 @@ module ActiveRecord | |
| 80 74 | 
             
                #
         | 
| 81 75 | 
             
                #   Post.find_by name: 'Spartacus', rating: 4
         | 
| 82 76 | 
             
                #   Post.find_by "published_at < ?", 2.weeks.ago
         | 
| 83 | 
            -
                def find_by(*args)
         | 
| 84 | 
            -
                  where(*args).take
         | 
| 77 | 
            +
                def find_by(arg, *args)
         | 
| 78 | 
            +
                  where(arg, *args).take
         | 
| 85 79 | 
             
                rescue RangeError
         | 
| 86 80 | 
             
                  nil
         | 
| 87 81 | 
             
                end
         | 
| 88 82 |  | 
| 89 | 
            -
                # Like  | 
| 90 | 
            -
                # an  | 
| 91 | 
            -
                def find_by!(*args)
         | 
| 92 | 
            -
                  where(*args).take!
         | 
| 83 | 
            +
                # Like #find_by, except that if no record is found, raises
         | 
| 84 | 
            +
                # an ActiveRecord::RecordNotFound error.
         | 
| 85 | 
            +
                def find_by!(arg, *args)
         | 
| 86 | 
            +
                  where(arg, *args).take!
         | 
| 93 87 | 
             
                rescue RangeError
         | 
| 94 | 
            -
                  raise RecordNotFound | 
| 88 | 
            +
                  raise RecordNotFound.new("Couldn't find #{@klass.name} with an out of range value",
         | 
| 89 | 
            +
                                           @klass.name)
         | 
| 95 90 | 
             
                end
         | 
| 96 91 |  | 
| 97 92 | 
             
                # Gives a record (or N records if a parameter is supplied) without any implied
         | 
| @@ -105,10 +100,10 @@ module ActiveRecord | |
| 105 100 | 
             
                  limit ? limit(limit).to_a : find_take
         | 
| 106 101 | 
             
                end
         | 
| 107 102 |  | 
| 108 | 
            -
                # Same as  | 
| 109 | 
            -
                # is found. Note that  | 
| 103 | 
            +
                # Same as #take but raises ActiveRecord::RecordNotFound if no record
         | 
| 104 | 
            +
                # is found. Note that #take! accepts no arguments.
         | 
| 110 105 | 
             
                def take!
         | 
| 111 | 
            -
                  take or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql}]")
         | 
| 106 | 
            +
                  take or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]")
         | 
| 112 107 | 
             
                end
         | 
| 113 108 |  | 
| 114 109 | 
             
                # Find the first record (or first N records if a parameter is supplied).
         | 
| @@ -122,14 +117,14 @@ module ActiveRecord | |
| 122 117 | 
             
                #
         | 
| 123 118 | 
             
                def first(limit = nil)
         | 
| 124 119 | 
             
                  if limit
         | 
| 125 | 
            -
                     | 
| 120 | 
            +
                    find_nth_with_limit_and_offset(0, limit, offset: offset_index)
         | 
| 126 121 | 
             
                  else
         | 
| 127 | 
            -
                    find_nth | 
| 122 | 
            +
                    find_nth 0
         | 
| 128 123 | 
             
                  end
         | 
| 129 124 | 
             
                end
         | 
| 130 125 |  | 
| 131 | 
            -
                # Same as  | 
| 132 | 
            -
                # is found. Note that  | 
| 126 | 
            +
                # Same as #first but raises ActiveRecord::RecordNotFound if no record
         | 
| 127 | 
            +
                # is found. Note that #first! accepts no arguments.
         | 
| 133 128 | 
             
                def first!
         | 
| 134 129 | 
             
                  find_nth! 0
         | 
| 135 130 | 
             
                end
         | 
| @@ -150,21 +145,27 @@ module ActiveRecord | |
| 150 145 | 
             
                #
         | 
| 151 146 | 
             
                #   [#<Person id:4>, #<Person id:3>, #<Person id:2>]
         | 
| 152 147 | 
             
                def last(limit = nil)
         | 
| 153 | 
            -
                  if  | 
| 154 | 
            -
             | 
| 155 | 
            -
             | 
| 156 | 
            -
             | 
| 157 | 
            -
             | 
| 158 | 
            -
             | 
| 159 | 
            -
                   | 
| 160 | 
            -
             | 
| 161 | 
            -
                   | 
| 148 | 
            +
                  return find_last(limit) if loaded? || limit_value
         | 
| 149 | 
            +
             | 
| 150 | 
            +
                  result = limit(limit || 1)
         | 
| 151 | 
            +
                  result.order!(arel_attribute(primary_key)) if order_values.empty? && primary_key
         | 
| 152 | 
            +
                  result = result.reverse_order!
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                  limit ? result.reverse : result.first
         | 
| 155 | 
            +
                rescue ActiveRecord::IrreversibleOrderError
         | 
| 156 | 
            +
                  ActiveSupport::Deprecation.warn(<<-WARNING.squish)
         | 
| 157 | 
            +
                      Finding a last element by loading the relation when SQL ORDER
         | 
| 158 | 
            +
                      can not be reversed is deprecated.
         | 
| 159 | 
            +
                      Rails 5.1 will raise ActiveRecord::IrreversibleOrderError in this case.
         | 
| 160 | 
            +
                      Please call `to_a.last` if you still want to load the relation.
         | 
| 161 | 
            +
                  WARNING
         | 
| 162 | 
            +
                  find_last(limit)
         | 
| 162 163 | 
             
                end
         | 
| 163 164 |  | 
| 164 | 
            -
                # Same as  | 
| 165 | 
            -
                # is found. Note that  | 
| 165 | 
            +
                # Same as #last but raises ActiveRecord::RecordNotFound if no record
         | 
| 166 | 
            +
                # is found. Note that #last! accepts no arguments.
         | 
| 166 167 | 
             
                def last!
         | 
| 167 | 
            -
                  last or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql}]")
         | 
| 168 | 
            +
                  last or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]")
         | 
| 168 169 | 
             
                end
         | 
| 169 170 |  | 
| 170 171 | 
             
                # Find the second record.
         | 
| @@ -174,10 +175,10 @@ module ActiveRecord | |
| 174 175 | 
             
                #   Person.offset(3).second # returns the second object from OFFSET 3 (which is OFFSET 4)
         | 
| 175 176 | 
             
                #   Person.where(["user_name = :u", { u: user_name }]).second
         | 
| 176 177 | 
             
                def second
         | 
| 177 | 
            -
                  find_nth | 
| 178 | 
            +
                  find_nth 1
         | 
| 178 179 | 
             
                end
         | 
| 179 180 |  | 
| 180 | 
            -
                # Same as  | 
| 181 | 
            +
                # Same as #second but raises ActiveRecord::RecordNotFound if no record
         | 
| 181 182 | 
             
                # is found.
         | 
| 182 183 | 
             
                def second!
         | 
| 183 184 | 
             
                  find_nth! 1
         | 
| @@ -190,10 +191,10 @@ module ActiveRecord | |
| 190 191 | 
             
                #   Person.offset(3).third # returns the third object from OFFSET 3 (which is OFFSET 5)
         | 
| 191 192 | 
             
                #   Person.where(["user_name = :u", { u: user_name }]).third
         | 
| 192 193 | 
             
                def third
         | 
| 193 | 
            -
                  find_nth | 
| 194 | 
            +
                  find_nth 2
         | 
| 194 195 | 
             
                end
         | 
| 195 196 |  | 
| 196 | 
            -
                # Same as  | 
| 197 | 
            +
                # Same as #third but raises ActiveRecord::RecordNotFound if no record
         | 
| 197 198 | 
             
                # is found.
         | 
| 198 199 | 
             
                def third!
         | 
| 199 200 | 
             
                  find_nth! 2
         | 
| @@ -206,10 +207,10 @@ module ActiveRecord | |
| 206 207 | 
             
                #   Person.offset(3).fourth # returns the fourth object from OFFSET 3 (which is OFFSET 6)
         | 
| 207 208 | 
             
                #   Person.where(["user_name = :u", { u: user_name }]).fourth
         | 
| 208 209 | 
             
                def fourth
         | 
| 209 | 
            -
                  find_nth | 
| 210 | 
            +
                  find_nth 3
         | 
| 210 211 | 
             
                end
         | 
| 211 212 |  | 
| 212 | 
            -
                # Same as  | 
| 213 | 
            +
                # Same as #fourth but raises ActiveRecord::RecordNotFound if no record
         | 
| 213 214 | 
             
                # is found.
         | 
| 214 215 | 
             
                def fourth!
         | 
| 215 216 | 
             
                  find_nth! 3
         | 
| @@ -222,10 +223,10 @@ module ActiveRecord | |
| 222 223 | 
             
                #   Person.offset(3).fifth # returns the fifth object from OFFSET 3 (which is OFFSET 7)
         | 
| 223 224 | 
             
                #   Person.where(["user_name = :u", { u: user_name }]).fifth
         | 
| 224 225 | 
             
                def fifth
         | 
| 225 | 
            -
                  find_nth | 
| 226 | 
            +
                  find_nth 4
         | 
| 226 227 | 
             
                end
         | 
| 227 228 |  | 
| 228 | 
            -
                # Same as  | 
| 229 | 
            +
                # Same as #fifth but raises ActiveRecord::RecordNotFound if no record
         | 
| 229 230 | 
             
                # is found.
         | 
| 230 231 | 
             
                def fifth!
         | 
| 231 232 | 
             
                  find_nth! 4
         | 
| @@ -238,17 +239,49 @@ module ActiveRecord | |
| 238 239 | 
             
                #   Person.offset(3).forty_two # returns the forty-second object from OFFSET 3 (which is OFFSET 44)
         | 
| 239 240 | 
             
                #   Person.where(["user_name = :u", { u: user_name }]).forty_two
         | 
| 240 241 | 
             
                def forty_two
         | 
| 241 | 
            -
                  find_nth | 
| 242 | 
            +
                  find_nth 41
         | 
| 242 243 | 
             
                end
         | 
| 243 244 |  | 
| 244 | 
            -
                # Same as  | 
| 245 | 
            +
                # Same as #forty_two but raises ActiveRecord::RecordNotFound if no record
         | 
| 245 246 | 
             
                # is found.
         | 
| 246 247 | 
             
                def forty_two!
         | 
| 247 248 | 
             
                  find_nth! 41
         | 
| 248 249 | 
             
                end
         | 
| 249 250 |  | 
| 250 | 
            -
                #  | 
| 251 | 
            -
                #  | 
| 251 | 
            +
                # Find the third-to-last record.
         | 
| 252 | 
            +
                # If no order is defined it will order by primary key.
         | 
| 253 | 
            +
                #
         | 
| 254 | 
            +
                #   Person.third_to_last # returns the third-to-last object fetched by SELECT * FROM people
         | 
| 255 | 
            +
                #   Person.offset(3).third_to_last # returns the third-to-last object from OFFSET 3
         | 
| 256 | 
            +
                #   Person.where(["user_name = :u", { u: user_name }]).third_to_last
         | 
| 257 | 
            +
                def third_to_last
         | 
| 258 | 
            +
                  find_nth_from_last 3
         | 
| 259 | 
            +
                end
         | 
| 260 | 
            +
             | 
| 261 | 
            +
                # Same as #third_to_last but raises ActiveRecord::RecordNotFound if no record
         | 
| 262 | 
            +
                # is found.
         | 
| 263 | 
            +
                def third_to_last!
         | 
| 264 | 
            +
                  find_nth_from_last 3 or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]")
         | 
| 265 | 
            +
                end
         | 
| 266 | 
            +
             | 
| 267 | 
            +
                # Find the second-to-last record.
         | 
| 268 | 
            +
                # If no order is defined it will order by primary key.
         | 
| 269 | 
            +
                #
         | 
| 270 | 
            +
                #   Person.second_to_last # returns the second-to-last object fetched by SELECT * FROM people
         | 
| 271 | 
            +
                #   Person.offset(3).second_to_last # returns the second-to-last object from OFFSET 3
         | 
| 272 | 
            +
                #   Person.where(["user_name = :u", { u: user_name }]).second_to_last
         | 
| 273 | 
            +
                def second_to_last
         | 
| 274 | 
            +
                  find_nth_from_last 2
         | 
| 275 | 
            +
                end
         | 
| 276 | 
            +
             | 
| 277 | 
            +
                # Same as #second_to_last but raises ActiveRecord::RecordNotFound if no record
         | 
| 278 | 
            +
                # is found.
         | 
| 279 | 
            +
                def second_to_last!
         | 
| 280 | 
            +
                  find_nth_from_last 2 or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]")
         | 
| 281 | 
            +
                end
         | 
| 282 | 
            +
             | 
| 283 | 
            +
                # Returns true if a record exists in the table that matches the +id+ or
         | 
| 284 | 
            +
                # conditions given, or false otherwise. The argument can take six forms:
         | 
| 252 285 | 
             
                #
         | 
| 253 286 | 
             
                # * Integer - Finds the record with this primary key.
         | 
| 254 287 | 
             
                # * String - Finds the record with a primary key corresponding to this
         | 
| @@ -261,7 +294,7 @@ module ActiveRecord | |
| 261 294 | 
             
                # * No args - Returns +false+ if the table is empty, +true+ otherwise.
         | 
| 262 295 | 
             
                #
         | 
| 263 296 | 
             
                # For more information about specifying conditions as a hash or array,
         | 
| 264 | 
            -
                # see the Conditions section in the introduction to  | 
| 297 | 
            +
                # see the Conditions section in the introduction to ActiveRecord::Base.
         | 
| 265 298 | 
             
                #
         | 
| 266 299 | 
             
                # Note: You can't pass in a condition as a string (like <tt>name =
         | 
| 267 300 | 
             
                # 'Jamie'</tt>), since it would be sanitized and then queried against
         | 
| @@ -279,7 +312,7 @@ module ActiveRecord | |
| 279 312 | 
             
                    conditions = conditions.id
         | 
| 280 313 | 
             
                    ActiveSupport::Deprecation.warn(<<-MSG.squish)
         | 
| 281 314 | 
             
                      You are passing an instance of ActiveRecord::Base to `exists?`.
         | 
| 282 | 
            -
                      Please pass the id of the object by calling `.id | 
| 315 | 
            +
                      Please pass the id of the object by calling `.id`.
         | 
| 283 316 | 
             
                    MSG
         | 
| 284 317 | 
             
                  end
         | 
| 285 318 |  | 
| @@ -299,11 +332,11 @@ module ActiveRecord | |
| 299 332 | 
             
                    end
         | 
| 300 333 | 
             
                  end
         | 
| 301 334 |  | 
| 302 | 
            -
                  connection.select_value(relation, "#{name} Exists", relation. | 
| 335 | 
            +
                  connection.select_value(relation, "#{name} Exists", relation.bound_attributes) ? true : false
         | 
| 303 336 | 
             
                end
         | 
| 304 337 |  | 
| 305 338 | 
             
                # This method is called whenever no records are found with either a single
         | 
| 306 | 
            -
                # id or multiple ids and raises  | 
| 339 | 
            +
                # id or multiple ids and raises an ActiveRecord::RecordNotFound exception.
         | 
| 307 340 | 
             
                #
         | 
| 308 341 | 
             
                # The error message is different depending on whether a single id or
         | 
| 309 342 | 
             
                # multiple ids are provided. If multiple ids are provided, then the number
         | 
| @@ -311,7 +344,7 @@ module ActiveRecord | |
| 311 344 | 
             
                # the expected number of results should be provided in the +expected_size+
         | 
| 312 345 | 
             
                # argument.
         | 
| 313 346 | 
             
                def raise_record_not_found_exception!(ids, result_size, expected_size) #:nodoc:
         | 
| 314 | 
            -
                  conditions = arel.where_sql
         | 
| 347 | 
            +
                  conditions = arel.where_sql(@klass.arel_engine)
         | 
| 315 348 | 
             
                  conditions = " [#{conditions}]" if conditions
         | 
| 316 349 |  | 
| 317 350 | 
             
                  if Array(ids).size == 1
         | 
| @@ -353,7 +386,7 @@ module ActiveRecord | |
| 353 386 | 
             
                      []
         | 
| 354 387 | 
             
                    else
         | 
| 355 388 | 
             
                      arel = relation.arel
         | 
| 356 | 
            -
                      rows = connection.select_all(arel, 'SQL',  | 
| 389 | 
            +
                      rows = connection.select_all(arel, 'SQL', relation.bound_attributes)
         | 
| 357 390 | 
             
                      join_dependency.instantiate(rows, aliases)
         | 
| 358 391 | 
             
                    end
         | 
| 359 392 | 
             
                  end
         | 
| @@ -385,7 +418,7 @@ module ActiveRecord | |
| 385 418 | 
             
                  else
         | 
| 386 419 | 
             
                    if relation.limit_value
         | 
| 387 420 | 
             
                      limited_ids = limited_ids_for(relation)
         | 
| 388 | 
            -
                      limited_ids.empty? ? relation.none! : relation.where!( | 
| 421 | 
            +
                      limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
         | 
| 389 422 | 
             
                    end
         | 
| 390 423 | 
             
                    relation.except(:limit, :offset)
         | 
| 391 424 | 
             
                  end
         | 
| @@ -398,12 +431,12 @@ module ActiveRecord | |
| 398 431 | 
             
                  relation = relation.except(:select).select(values).distinct!
         | 
| 399 432 | 
             
                  arel = relation.arel
         | 
| 400 433 |  | 
| 401 | 
            -
                  id_rows = @klass.connection.select_all(arel, 'SQL',  | 
| 434 | 
            +
                  id_rows = @klass.connection.select_all(arel, 'SQL', relation.bound_attributes)
         | 
| 402 435 | 
             
                  id_rows.map {|row| row[primary_key]}
         | 
| 403 436 | 
             
                end
         | 
| 404 437 |  | 
| 405 438 | 
             
                def using_limitable_reflections?(reflections)
         | 
| 406 | 
            -
                  reflections.none? | 
| 439 | 
            +
                  reflections.none?(&:collection?)
         | 
| 407 440 | 
             
                end
         | 
| 408 441 |  | 
| 409 442 | 
             
                protected
         | 
| @@ -434,7 +467,7 @@ module ActiveRecord | |
| 434 467 | 
             
                    id = id.id
         | 
| 435 468 | 
             
                    ActiveSupport::Deprecation.warn(<<-MSG.squish)
         | 
| 436 469 | 
             
                      You are passing an instance of ActiveRecord::Base to `find`.
         | 
| 437 | 
            -
                      Please pass the id of the object by calling `.id | 
| 470 | 
            +
                      Please pass the id of the object by calling `.id`.
         | 
| 438 471 | 
             
                    MSG
         | 
| 439 472 | 
             
                  end
         | 
| 440 473 |  | 
| @@ -447,6 +480,8 @@ module ActiveRecord | |
| 447 480 | 
             
                end
         | 
| 448 481 |  | 
| 449 482 | 
             
                def find_some(ids)
         | 
| 483 | 
            +
                  return find_some_ordered(ids) unless order_values.present?
         | 
| 484 | 
            +
             | 
| 450 485 | 
             
                  result = where(primary_key => ids).to_a
         | 
| 451 486 |  | 
| 452 487 | 
             
                  expected_size =
         | 
| @@ -468,49 +503,96 @@ module ActiveRecord | |
| 468 503 | 
             
                  end
         | 
| 469 504 | 
             
                end
         | 
| 470 505 |  | 
| 506 | 
            +
                def find_some_ordered(ids)
         | 
| 507 | 
            +
                  ids = ids.slice(offset_value || 0, limit_value || ids.size) || []
         | 
| 508 | 
            +
             | 
| 509 | 
            +
                  result = except(:limit, :offset).where(primary_key => ids).records
         | 
| 510 | 
            +
             | 
| 511 | 
            +
                  if result.size == ids.size
         | 
| 512 | 
            +
                    pk_type = @klass.type_for_attribute(primary_key)
         | 
| 513 | 
            +
             | 
| 514 | 
            +
                    records_by_id = result.index_by(&:id)
         | 
| 515 | 
            +
                    ids.map { |id| records_by_id.fetch(pk_type.cast(id)) }
         | 
| 516 | 
            +
                  else
         | 
| 517 | 
            +
                    raise_record_not_found_exception!(ids, result.size, ids.size)
         | 
| 518 | 
            +
                  end
         | 
| 519 | 
            +
                end
         | 
| 520 | 
            +
             | 
| 471 521 | 
             
                def find_take
         | 
| 472 522 | 
             
                  if loaded?
         | 
| 473 523 | 
             
                    @records.first
         | 
| 474 524 | 
             
                  else
         | 
| 475 | 
            -
                    @take ||= limit(1). | 
| 525 | 
            +
                    @take ||= limit(1).records.first
         | 
| 476 526 | 
             
                  end
         | 
| 477 527 | 
             
                end
         | 
| 478 528 |  | 
| 479 | 
            -
                def find_nth(index, offset)
         | 
| 529 | 
            +
                def find_nth(index, offset = nil)
         | 
| 530 | 
            +
                  # TODO: once the offset argument is removed we rely on offset_index
         | 
| 531 | 
            +
                  # within find_nth_with_limit, rather than pass it in via
         | 
| 532 | 
            +
                  # find_nth_with_limit_and_offset
         | 
| 533 | 
            +
                  if offset
         | 
| 534 | 
            +
                    ActiveSupport::Deprecation.warn(<<-MSG.squish)
         | 
| 535 | 
            +
                      Passing an offset argument to find_nth is deprecated,
         | 
| 536 | 
            +
                      please use Relation#offset instead.
         | 
| 537 | 
            +
                    MSG
         | 
| 538 | 
            +
                  end
         | 
| 480 539 | 
             
                  if loaded?
         | 
| 481 540 | 
             
                    @records[index]
         | 
| 482 541 | 
             
                  else
         | 
| 483 | 
            -
                    offset  | 
| 484 | 
            -
                    @offsets[offset] ||=  | 
| 542 | 
            +
                    offset ||= offset_index
         | 
| 543 | 
            +
                    @offsets[offset + index] ||= find_nth_with_limit_and_offset(index, 1, offset: offset).first
         | 
| 485 544 | 
             
                  end
         | 
| 486 545 | 
             
                end
         | 
| 487 546 |  | 
| 488 547 | 
             
                def find_nth!(index)
         | 
| 489 | 
            -
                  find_nth(index | 
| 548 | 
            +
                  find_nth(index) or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]")
         | 
| 490 549 | 
             
                end
         | 
| 491 550 |  | 
| 492 | 
            -
                def find_nth_with_limit( | 
| 551 | 
            +
                def find_nth_with_limit(index, limit)
         | 
| 552 | 
            +
                  # TODO: once the offset argument is removed from find_nth,
         | 
| 553 | 
            +
                  # find_nth_with_limit_and_offset can be merged into this method
         | 
| 493 554 | 
             
                  relation = if order_values.empty? && primary_key
         | 
| 494 | 
            -
                               order( | 
| 555 | 
            +
                               order(arel_attribute(primary_key).asc)
         | 
| 495 556 | 
             
                             else
         | 
| 496 557 | 
             
                               self
         | 
| 497 558 | 
             
                             end
         | 
| 498 559 |  | 
| 499 | 
            -
                  relation = relation.offset( | 
| 560 | 
            +
                  relation = relation.offset(index) unless index.zero?
         | 
| 500 561 | 
             
                  relation.limit(limit).to_a
         | 
| 501 562 | 
             
                end
         | 
| 502 563 |  | 
| 503 | 
            -
                def  | 
| 564 | 
            +
                def find_nth_from_last(index)
         | 
| 504 565 | 
             
                  if loaded?
         | 
| 505 | 
            -
                    @records | 
| 566 | 
            +
                    @records[-index]
         | 
| 506 567 | 
             
                  else
         | 
| 507 | 
            -
                     | 
| 508 | 
            -
             | 
| 509 | 
            -
             | 
| 510 | 
            -
             | 
| 511 | 
            -
             | 
| 512 | 
            -
             | 
| 568 | 
            +
                    relation = if order_values.empty? && primary_key
         | 
| 569 | 
            +
                                 order(arel_attribute(primary_key).asc)
         | 
| 570 | 
            +
                               else
         | 
| 571 | 
            +
                                 self
         | 
| 572 | 
            +
                               end
         | 
| 573 | 
            +
             | 
| 574 | 
            +
                    relation.to_a[-index]
         | 
| 575 | 
            +
                    # TODO: can be made more performant on large result sets by
         | 
| 576 | 
            +
                    # for instance, last(index)[-index] (which would require
         | 
| 577 | 
            +
                    # refactoring the last(n) finder method to make test suite pass),
         | 
| 578 | 
            +
                    # or by using a combination of reverse_order, limit, and offset,
         | 
| 579 | 
            +
                    # e.g., reverse_order.offset(index-1).first
         | 
| 513 580 | 
             
                  end
         | 
| 514 581 | 
             
                end
         | 
| 582 | 
            +
                
         | 
| 583 | 
            +
                private
         | 
| 584 | 
            +
             | 
| 585 | 
            +
                def find_nth_with_limit_and_offset(index, limit, offset:) # :nodoc:
         | 
| 586 | 
            +
                  if loaded?
         | 
| 587 | 
            +
                    @records[index, limit]
         | 
| 588 | 
            +
                  else
         | 
| 589 | 
            +
                    index += offset
         | 
| 590 | 
            +
                    find_nth_with_limit(index, limit)
         | 
| 591 | 
            +
                  end
         | 
| 592 | 
            +
                end
         | 
| 593 | 
            +
             | 
| 594 | 
            +
                def find_last(limit)
         | 
| 595 | 
            +
                  limit ? records.last(limit) : records.last
         | 
| 596 | 
            +
                end
         | 
| 515 597 | 
             
              end
         | 
| 516 598 | 
             
            end
         |