activerecord 3.0.0 → 4.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 +7 -0
 - data/CHANGELOG.md +2102 -0
 - data/MIT-LICENSE +20 -0
 - data/README.rdoc +35 -44
 - data/examples/performance.rb +110 -100
 - data/lib/active_record/aggregations.rb +59 -75
 - data/lib/active_record/associations/alias_tracker.rb +76 -0
 - data/lib/active_record/associations/association.rb +248 -0
 - data/lib/active_record/associations/association_scope.rb +135 -0
 - data/lib/active_record/associations/belongs_to_association.rb +60 -59
 - data/lib/active_record/associations/belongs_to_polymorphic_association.rb +16 -59
 - data/lib/active_record/associations/builder/association.rb +108 -0
 - data/lib/active_record/associations/builder/belongs_to.rb +98 -0
 - data/lib/active_record/associations/builder/collection_association.rb +89 -0
 - data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +39 -0
 - data/lib/active_record/associations/builder/has_many.rb +15 -0
 - data/lib/active_record/associations/builder/has_one.rb +25 -0
 - data/lib/active_record/associations/builder/singular_association.rb +32 -0
 - data/lib/active_record/associations/collection_association.rb +608 -0
 - data/lib/active_record/associations/collection_proxy.rb +986 -0
 - data/lib/active_record/associations/has_and_belongs_to_many_association.rb +40 -112
 - data/lib/active_record/associations/has_many_association.rb +83 -76
 - data/lib/active_record/associations/has_many_through_association.rb +147 -66
 - data/lib/active_record/associations/has_one_association.rb +67 -108
 - data/lib/active_record/associations/has_one_through_association.rb +21 -25
 - data/lib/active_record/associations/join_dependency/join_association.rb +174 -0
 - data/lib/active_record/associations/join_dependency/join_base.rb +24 -0
 - data/lib/active_record/associations/join_dependency/join_part.rb +78 -0
 - data/lib/active_record/associations/join_dependency.rb +235 -0
 - data/lib/active_record/associations/join_helper.rb +45 -0
 - data/lib/active_record/associations/preloader/association.rb +121 -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_and_belongs_to_many.rb +60 -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 +63 -0
 - data/lib/active_record/associations/preloader.rb +178 -0
 - data/lib/active_record/associations/singular_association.rb +64 -0
 - data/lib/active_record/associations/through_association.rb +87 -0
 - data/lib/active_record/associations.rb +512 -1224
 - data/lib/active_record/attribute_assignment.rb +201 -0
 - data/lib/active_record/attribute_methods/before_type_cast.rb +49 -12
 - data/lib/active_record/attribute_methods/dirty.rb +51 -28
 - data/lib/active_record/attribute_methods/primary_key.rb +94 -22
 - data/lib/active_record/attribute_methods/query.rb +5 -4
 - data/lib/active_record/attribute_methods/read.rb +63 -72
 - data/lib/active_record/attribute_methods/serialization.rb +162 -0
 - data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -41
 - data/lib/active_record/attribute_methods/write.rb +39 -13
 - data/lib/active_record/attribute_methods.rb +362 -29
 - data/lib/active_record/autosave_association.rb +132 -75
 - data/lib/active_record/base.rb +83 -1627
 - data/lib/active_record/callbacks.rb +69 -47
 - data/lib/active_record/coders/yaml_column.rb +38 -0
 - data/lib/active_record/connection_adapters/abstract/connection_pool.rb +411 -138
 - data/lib/active_record/connection_adapters/abstract/database_limits.rb +21 -11
 - data/lib/active_record/connection_adapters/abstract/database_statements.rb +234 -173
 - data/lib/active_record/connection_adapters/abstract/query_cache.rb +36 -22
 - data/lib/active_record/connection_adapters/abstract/quoting.rb +82 -25
 - data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +176 -414
 - data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +70 -0
 - data/lib/active_record/connection_adapters/abstract/schema_statements.rb +562 -232
 - data/lib/active_record/connection_adapters/abstract/transaction.rb +203 -0
 - data/lib/active_record/connection_adapters/abstract_adapter.rb +281 -53
 - data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +782 -0
 - data/lib/active_record/connection_adapters/column.rb +318 -0
 - data/lib/active_record/connection_adapters/connection_specification.rb +96 -0
 - data/lib/active_record/connection_adapters/mysql2_adapter.rb +273 -0
 - data/lib/active_record/connection_adapters/mysql_adapter.rb +365 -450
 - data/lib/active_record/connection_adapters/postgresql/array_parser.rb +97 -0
 - data/lib/active_record/connection_adapters/postgresql/cast.rb +152 -0
 - data/lib/active_record/connection_adapters/postgresql/database_statements.rb +242 -0
 - data/lib/active_record/connection_adapters/postgresql/oid.rb +366 -0
 - data/lib/active_record/connection_adapters/postgresql/quoting.rb +171 -0
 - data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
 - data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +489 -0
 - data/lib/active_record/connection_adapters/postgresql_adapter.rb +672 -752
 - data/lib/active_record/connection_adapters/schema_cache.rb +129 -0
 - data/lib/active_record/connection_adapters/sqlite3_adapter.rb +588 -17
 - data/lib/active_record/connection_adapters/statement_pool.rb +40 -0
 - data/lib/active_record/connection_handling.rb +98 -0
 - data/lib/active_record/core.rb +463 -0
 - data/lib/active_record/counter_cache.rb +108 -101
 - data/lib/active_record/dynamic_matchers.rb +131 -0
 - data/lib/active_record/errors.rb +54 -13
 - 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 +55 -0
 - data/lib/active_record/fixtures.rb +703 -785
 - data/lib/active_record/inheritance.rb +200 -0
 - data/lib/active_record/integration.rb +60 -0
 - data/lib/active_record/locale/en.yml +8 -1
 - data/lib/active_record/locking/optimistic.rb +69 -60
 - data/lib/active_record/locking/pessimistic.rb +34 -12
 - data/lib/active_record/log_subscriber.rb +40 -6
 - data/lib/active_record/migration/command_recorder.rb +164 -0
 - data/lib/active_record/migration/join_table.rb +15 -0
 - data/lib/active_record/migration.rb +614 -216
 - data/lib/active_record/model_schema.rb +345 -0
 - data/lib/active_record/nested_attributes.rb +248 -119
 - data/lib/active_record/null_relation.rb +65 -0
 - data/lib/active_record/persistence.rb +275 -57
 - data/lib/active_record/query_cache.rb +29 -9
 - data/lib/active_record/querying.rb +62 -0
 - data/lib/active_record/railtie.rb +135 -21
 - data/lib/active_record/railties/console_sandbox.rb +5 -0
 - data/lib/active_record/railties/controller_runtime.rb +17 -5
 - data/lib/active_record/railties/databases.rake +249 -359
 - data/lib/active_record/railties/jdbcmysql_error.rb +16 -0
 - data/lib/active_record/readonly_attributes.rb +30 -0
 - data/lib/active_record/reflection.rb +283 -103
 - data/lib/active_record/relation/batches.rb +38 -34
 - data/lib/active_record/relation/calculations.rb +252 -139
 - data/lib/active_record/relation/delegation.rb +125 -0
 - data/lib/active_record/relation/finder_methods.rb +182 -188
 - data/lib/active_record/relation/merger.rb +161 -0
 - data/lib/active_record/relation/predicate_builder.rb +86 -21
 - data/lib/active_record/relation/query_methods.rb +917 -134
 - data/lib/active_record/relation/spawn_methods.rb +53 -92
 - data/lib/active_record/relation.rb +405 -143
 - data/lib/active_record/result.rb +67 -0
 - data/lib/active_record/runtime_registry.rb +17 -0
 - data/lib/active_record/sanitization.rb +168 -0
 - data/lib/active_record/schema.rb +20 -14
 - data/lib/active_record/schema_dumper.rb +55 -46
 - data/lib/active_record/schema_migration.rb +39 -0
 - data/lib/active_record/scoping/default.rb +146 -0
 - data/lib/active_record/scoping/named.rb +175 -0
 - data/lib/active_record/scoping.rb +82 -0
 - data/lib/active_record/serialization.rb +8 -46
 - data/lib/active_record/serializers/xml_serializer.rb +21 -68
 - data/lib/active_record/statement_cache.rb +26 -0
 - data/lib/active_record/store.rb +156 -0
 - data/lib/active_record/tasks/database_tasks.rb +203 -0
 - data/lib/active_record/tasks/firebird_database_tasks.rb +56 -0
 - data/lib/active_record/tasks/mysql_database_tasks.rb +143 -0
 - data/lib/active_record/tasks/oracle_database_tasks.rb +45 -0
 - data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
 - data/lib/active_record/tasks/sqlite_database_tasks.rb +51 -0
 - data/lib/active_record/tasks/sqlserver_database_tasks.rb +48 -0
 - data/lib/active_record/test_case.rb +57 -28
 - data/lib/active_record/timestamp.rb +49 -18
 - data/lib/active_record/transactions.rb +106 -63
 - data/lib/active_record/translation.rb +22 -0
 - data/lib/active_record/validations/associated.rb +25 -24
 - data/lib/active_record/validations/presence.rb +65 -0
 - data/lib/active_record/validations/uniqueness.rb +123 -83
 - data/lib/active_record/validations.rb +29 -29
 - data/lib/active_record/version.rb +7 -5
 - data/lib/active_record.rb +83 -34
 - data/lib/rails/generators/active_record/migration/migration_generator.rb +46 -9
 - data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +19 -0
 - data/lib/rails/generators/active_record/migration/templates/migration.rb +30 -8
 - data/lib/rails/generators/active_record/model/model_generator.rb +15 -5
 - data/lib/rails/generators/active_record/model/templates/model.rb +7 -2
 - data/lib/rails/generators/active_record/model/templates/module.rb +3 -1
 - data/lib/rails/generators/active_record.rb +4 -8
 - metadata +163 -121
 - data/CHANGELOG +0 -6023
 - data/examples/associations.png +0 -0
 - data/lib/active_record/association_preload.rb +0 -403
 - data/lib/active_record/associations/association_collection.rb +0 -562
 - data/lib/active_record/associations/association_proxy.rb +0 -295
 - data/lib/active_record/associations/through_association_scope.rb +0 -154
 - data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -113
 - data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -401
 - data/lib/active_record/dynamic_finder_match.rb +0 -53
 - data/lib/active_record/dynamic_scope_match.rb +0 -32
 - data/lib/active_record/named_scope.rb +0 -138
 - data/lib/active_record/observer.rb +0 -140
 - data/lib/active_record/session_store.rb +0 -340
 - data/lib/rails/generators/active_record/model/templates/migration.rb +0 -16
 - data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
 - data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -2
 - data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -24
 - data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -16
 
| 
         @@ -0,0 +1,125 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'thread'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'thread_safe'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module ActiveRecord
         
     | 
| 
      
 5 
     | 
    
         
            +
              module Delegation # :nodoc:
         
     | 
| 
      
 6 
     | 
    
         
            +
                extend ActiveSupport::Concern
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                # This module creates compiled delegation methods dynamically at runtime, which makes
         
     | 
| 
      
 9 
     | 
    
         
            +
                # subsequent calls to that method faster by avoiding method_missing. The delegations
         
     | 
| 
      
 10 
     | 
    
         
            +
                # may vary depending on the klass of a relation, so we create a subclass of Relation
         
     | 
| 
      
 11 
     | 
    
         
            +
                # for each different klass, and the delegations are compiled into that subclass only.
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to_ary, :to => :to_a
         
     | 
| 
      
 14 
     | 
    
         
            +
                delegate :table_name, :quoted_table_name, :primary_key, :quoted_primary_key,
         
     | 
| 
      
 15 
     | 
    
         
            +
                         :connection, :columns_hash, :to => :klass
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                module ClassSpecificRelation # :nodoc:
         
     | 
| 
      
 18 
     | 
    
         
            +
                  extend ActiveSupport::Concern
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  included do
         
     | 
| 
      
 21 
     | 
    
         
            +
                    @delegation_mutex = Mutex.new
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  module ClassMethods # :nodoc:
         
     | 
| 
      
 25 
     | 
    
         
            +
                    def name
         
     | 
| 
      
 26 
     | 
    
         
            +
                      superclass.name
         
     | 
| 
      
 27 
     | 
    
         
            +
                    end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                    def delegate_to_scoped_klass(method)
         
     | 
| 
      
 30 
     | 
    
         
            +
                      @delegation_mutex.synchronize do
         
     | 
| 
      
 31 
     | 
    
         
            +
                        return if method_defined?(method)
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                        if method.to_s =~ /\A[a-zA-Z_]\w*[!?]?\z/
         
     | 
| 
      
 34 
     | 
    
         
            +
                          module_eval <<-RUBY, __FILE__, __LINE__ + 1
         
     | 
| 
      
 35 
     | 
    
         
            +
                            def #{method}(*args, &block)
         
     | 
| 
      
 36 
     | 
    
         
            +
                              scoping { @klass.#{method}(*args, &block) }
         
     | 
| 
      
 37 
     | 
    
         
            +
                            end
         
     | 
| 
      
 38 
     | 
    
         
            +
                          RUBY
         
     | 
| 
      
 39 
     | 
    
         
            +
                        else
         
     | 
| 
      
 40 
     | 
    
         
            +
                          define_method method do |*args, &block|
         
     | 
| 
      
 41 
     | 
    
         
            +
                            scoping { @klass.send(method, *args, &block) }
         
     | 
| 
      
 42 
     | 
    
         
            +
                          end
         
     | 
| 
      
 43 
     | 
    
         
            +
                        end
         
     | 
| 
      
 44 
     | 
    
         
            +
                      end
         
     | 
| 
      
 45 
     | 
    
         
            +
                    end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                    def delegate(method, opts = {})
         
     | 
| 
      
 48 
     | 
    
         
            +
                      @delegation_mutex.synchronize do
         
     | 
| 
      
 49 
     | 
    
         
            +
                        return if method_defined?(method)
         
     | 
| 
      
 50 
     | 
    
         
            +
                        super
         
     | 
| 
      
 51 
     | 
    
         
            +
                      end
         
     | 
| 
      
 52 
     | 
    
         
            +
                    end
         
     | 
| 
      
 53 
     | 
    
         
            +
                  end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                  protected
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  def method_missing(method, *args, &block)
         
     | 
| 
      
 58 
     | 
    
         
            +
                    if @klass.respond_to?(method)
         
     | 
| 
      
 59 
     | 
    
         
            +
                      self.class.delegate_to_scoped_klass(method)
         
     | 
| 
      
 60 
     | 
    
         
            +
                      scoping { @klass.send(method, *args, &block) }
         
     | 
| 
      
 61 
     | 
    
         
            +
                    elsif Array.method_defined?(method)
         
     | 
| 
      
 62 
     | 
    
         
            +
                      self.class.delegate method, :to => :to_a
         
     | 
| 
      
 63 
     | 
    
         
            +
                      to_a.send(method, *args, &block)
         
     | 
| 
      
 64 
     | 
    
         
            +
                    elsif arel.respond_to?(method)
         
     | 
| 
      
 65 
     | 
    
         
            +
                      self.class.delegate method, :to => :arel
         
     | 
| 
      
 66 
     | 
    
         
            +
                      arel.send(method, *args, &block)
         
     | 
| 
      
 67 
     | 
    
         
            +
                    else
         
     | 
| 
      
 68 
     | 
    
         
            +
                      super
         
     | 
| 
      
 69 
     | 
    
         
            +
                    end
         
     | 
| 
      
 70 
     | 
    
         
            +
                  end
         
     | 
| 
      
 71 
     | 
    
         
            +
                end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                module ClassMethods # :nodoc:
         
     | 
| 
      
 74 
     | 
    
         
            +
                  @@subclasses = ThreadSafe::Cache.new(:initial_capacity => 2)
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                  def new(klass, *args)
         
     | 
| 
      
 77 
     | 
    
         
            +
                    relation = relation_class_for(klass).allocate
         
     | 
| 
      
 78 
     | 
    
         
            +
                    relation.__send__(:initialize, klass, *args)
         
     | 
| 
      
 79 
     | 
    
         
            +
                    relation
         
     | 
| 
      
 80 
     | 
    
         
            +
                  end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                  # This doesn't have to be thread-safe. relation_class_for guarantees that this will only be
         
     | 
| 
      
 83 
     | 
    
         
            +
                  # called exactly once for a given const name.
         
     | 
| 
      
 84 
     | 
    
         
            +
                  def const_missing(name)
         
     | 
| 
      
 85 
     | 
    
         
            +
                    const_set(name, Class.new(self) { include ClassSpecificRelation })
         
     | 
| 
      
 86 
     | 
    
         
            +
                  end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                  private
         
     | 
| 
      
 89 
     | 
    
         
            +
                  # Cache the constants in @@subclasses because looking them up via const_get
         
     | 
| 
      
 90 
     | 
    
         
            +
                  # make instantiation significantly slower.
         
     | 
| 
      
 91 
     | 
    
         
            +
                  def relation_class_for(klass)
         
     | 
| 
      
 92 
     | 
    
         
            +
                    if klass && (klass_name = klass.name)
         
     | 
| 
      
 93 
     | 
    
         
            +
                      my_cache = @@subclasses.compute_if_absent(self) { ThreadSafe::Cache.new }
         
     | 
| 
      
 94 
     | 
    
         
            +
                      # This hash is keyed by klass.name to avoid memory leaks in development mode
         
     | 
| 
      
 95 
     | 
    
         
            +
                      my_cache.compute_if_absent(klass_name) do
         
     | 
| 
      
 96 
     | 
    
         
            +
                        # Cache#compute_if_absent guarantees that the block will only executed once for the given klass_name
         
     | 
| 
      
 97 
     | 
    
         
            +
                        const_get("#{name.gsub('::', '_')}_#{klass_name.gsub('::', '_')}", false)
         
     | 
| 
      
 98 
     | 
    
         
            +
                      end
         
     | 
| 
      
 99 
     | 
    
         
            +
                    else
         
     | 
| 
      
 100 
     | 
    
         
            +
                      ActiveRecord::Relation
         
     | 
| 
      
 101 
     | 
    
         
            +
                    end
         
     | 
| 
      
 102 
     | 
    
         
            +
                  end
         
     | 
| 
      
 103 
     | 
    
         
            +
                end
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
                def respond_to?(method, include_private = false)
         
     | 
| 
      
 106 
     | 
    
         
            +
                  super || Array.method_defined?(method) ||
         
     | 
| 
      
 107 
     | 
    
         
            +
                    @klass.respond_to?(method, include_private) ||
         
     | 
| 
      
 108 
     | 
    
         
            +
                    arel.respond_to?(method, include_private)
         
     | 
| 
      
 109 
     | 
    
         
            +
                end
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
                protected
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                def method_missing(method, *args, &block)
         
     | 
| 
      
 114 
     | 
    
         
            +
                  if @klass.respond_to?(method)
         
     | 
| 
      
 115 
     | 
    
         
            +
                    scoping { @klass.send(method, *args, &block) }
         
     | 
| 
      
 116 
     | 
    
         
            +
                  elsif Array.method_defined?(method)
         
     | 
| 
      
 117 
     | 
    
         
            +
                    to_a.send(method, *args, &block)
         
     | 
| 
      
 118 
     | 
    
         
            +
                  elsif arel.respond_to?(method)
         
     | 
| 
      
 119 
     | 
    
         
            +
                    arel.send(method, *args, &block)
         
     | 
| 
      
 120 
     | 
    
         
            +
                  else
         
     | 
| 
      
 121 
     | 
    
         
            +
                    super
         
     | 
| 
      
 122 
     | 
    
         
            +
                  end
         
     | 
| 
      
 123 
     | 
    
         
            +
                end
         
     | 
| 
      
 124 
     | 
    
         
            +
              end
         
     | 
| 
      
 125 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,150 +1,137 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require 'active_support/core_ext/object/blank'
         
     | 
| 
       2 
     | 
    
         
            -
            require 'active_support/core_ext/hash/indifferent_access'
         
     | 
| 
       3 
     | 
    
         
            -
             
     | 
| 
       4 
1 
     | 
    
         
             
            module ActiveRecord
         
     | 
| 
       5 
2 
     | 
    
         
             
              module FinderMethods
         
     | 
| 
       6 
     | 
    
         
            -
                # Find  
     | 
| 
       7 
     | 
    
         
            -
                #
         
     | 
| 
       8 
     | 
    
         
            -
                #  
     | 
| 
       9 
     | 
    
         
            -
                #   If no record can be found for all of the listed ids, then RecordNotFound will be raised.
         
     | 
| 
       10 
     | 
    
         
            -
                # * Find first - This will return the first record matched by the options used. These options can either be specific
         
     | 
| 
       11 
     | 
    
         
            -
                #   conditions or merely an order. If no record can be matched, +nil+ is returned. Use
         
     | 
| 
       12 
     | 
    
         
            -
                #   <tt>Model.find(:first, *args)</tt> or its shortcut <tt>Model.first(*args)</tt>.
         
     | 
| 
       13 
     | 
    
         
            -
                # * Find last - This will return the last record matched by the options used. These options can either be specific
         
     | 
| 
       14 
     | 
    
         
            -
                #   conditions or merely an order. If no record can be matched, +nil+ is returned. Use
         
     | 
| 
       15 
     | 
    
         
            -
                #   <tt>Model.find(:last, *args)</tt> or its shortcut <tt>Model.last(*args)</tt>.
         
     | 
| 
       16 
     | 
    
         
            -
                # * Find all - This will return all the records matched by the options used.
         
     | 
| 
       17 
     | 
    
         
            -
                #   If no records are found, an empty array is returned. Use
         
     | 
| 
       18 
     | 
    
         
            -
                #   <tt>Model.find(:all, *args)</tt> or its shortcut <tt>Model.all(*args)</tt>.
         
     | 
| 
       19 
     | 
    
         
            -
                #
         
     | 
| 
       20 
     | 
    
         
            -
                # All approaches accept an options hash as their last parameter.
         
     | 
| 
       21 
     | 
    
         
            -
                #
         
     | 
| 
       22 
     | 
    
         
            -
                # ==== Parameters
         
     | 
| 
       23 
     | 
    
         
            -
                #
         
     | 
| 
       24 
     | 
    
         
            -
                # * <tt>:conditions</tt> - An SQL fragment like "administrator = 1", <tt>[ "user_name = ?", username ]</tt>,
         
     | 
| 
       25 
     | 
    
         
            -
                #   or <tt>["user_name = :user_name", { :user_name => user_name }]</tt>. See conditions in the intro.
         
     | 
| 
       26 
     | 
    
         
            -
                # * <tt>:order</tt> - An SQL fragment like "created_at DESC, name".
         
     | 
| 
       27 
     | 
    
         
            -
                # * <tt>:group</tt> - An attribute name by which the result should be grouped. Uses the <tt>GROUP BY</tt> SQL-clause.
         
     | 
| 
       28 
     | 
    
         
            -
                # * <tt>:having</tt> - Combined with +:group+ this can be used to filter the records that a
         
     | 
| 
       29 
     | 
    
         
            -
                #   <tt>GROUP BY</tt> returns. Uses the <tt>HAVING</tt> SQL-clause.
         
     | 
| 
       30 
     | 
    
         
            -
                # * <tt>:limit</tt> - An integer determining the limit on the number of rows that should be returned.
         
     | 
| 
       31 
     | 
    
         
            -
                # * <tt>:offset</tt> - An integer determining the offset from where the rows should be fetched. So at 5,
         
     | 
| 
       32 
     | 
    
         
            -
                #   it would skip rows 0 through 4.
         
     | 
| 
       33 
     | 
    
         
            -
                # * <tt>:joins</tt> - Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed),
         
     | 
| 
       34 
     | 
    
         
            -
                #   named associations in the same form used for the <tt>:include</tt> option, which will perform an
         
     | 
| 
       35 
     | 
    
         
            -
                #   <tt>INNER JOIN</tt> on the associated table(s),
         
     | 
| 
       36 
     | 
    
         
            -
                #   or an array containing a mixture of both strings and named associations.
         
     | 
| 
       37 
     | 
    
         
            -
                #   If the value is a string, then the records will be returned read-only since they will
         
     | 
| 
       38 
     | 
    
         
            -
                #   have attributes that do not correspond to the table's columns.
         
     | 
| 
       39 
     | 
    
         
            -
                #   Pass <tt>:readonly => false</tt> to override.
         
     | 
| 
       40 
     | 
    
         
            -
                # * <tt>:include</tt> - Names associations that should be loaded alongside. The symbols named refer
         
     | 
| 
       41 
     | 
    
         
            -
                #   to already defined associations. See eager loading under Associations.
         
     | 
| 
       42 
     | 
    
         
            -
                # * <tt>:select</tt> - By default, this is "*" as in "SELECT * FROM", but can be changed if you,
         
     | 
| 
       43 
     | 
    
         
            -
                #   for example, want to do a join but not include the joined columns. Takes a string with the SELECT SQL fragment (e.g. "id, name").
         
     | 
| 
       44 
     | 
    
         
            -
                # * <tt>:from</tt> - By default, this is the table name of the class, but can be changed
         
     | 
| 
       45 
     | 
    
         
            -
                #   to an alternate table name (or even the name of a database view).
         
     | 
| 
       46 
     | 
    
         
            -
                # * <tt>:readonly</tt> - Mark the returned records read-only so they cannot be saved or updated.
         
     | 
| 
       47 
     | 
    
         
            -
                # * <tt>:lock</tt> - An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE".
         
     | 
| 
       48 
     | 
    
         
            -
                #   <tt>:lock => true</tt> gives connection's default exclusive lock, usually "FOR UPDATE".
         
     | 
| 
      
 3 
     | 
    
         
            +
                # 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]).
         
     | 
| 
      
 4 
     | 
    
         
            +
                # If no record can be found for all of the listed ids, then RecordNotFound will be raised. If the primary key
         
     | 
| 
      
 5 
     | 
    
         
            +
                # is an integer, find by id coerces its arguments using +to_i+.
         
     | 
| 
       49 
6 
     | 
    
         
             
                #
         
     | 
| 
       50 
     | 
    
         
            -
                # ==== Examples
         
     | 
| 
       51 
     | 
    
         
            -
                #
         
     | 
| 
       52 
     | 
    
         
            -
                #   # find by id
         
     | 
| 
       53 
7 
     | 
    
         
             
                #   Person.find(1)       # returns the object for ID = 1
         
     | 
| 
      
 8 
     | 
    
         
            +
                #   Person.find("1")     # returns the object for ID = 1
         
     | 
| 
       54 
9 
     | 
    
         
             
                #   Person.find(1, 2, 6) # returns an array for objects with IDs in (1, 2, 6)
         
     | 
| 
       55 
10 
     | 
    
         
             
                #   Person.find([7, 17]) # returns an array for objects with IDs in (7, 17)
         
     | 
| 
       56 
11 
     | 
    
         
             
                #   Person.find([1])     # returns an array for the object with ID = 1
         
     | 
| 
       57 
     | 
    
         
            -
                #   Person. 
     | 
| 
      
 12 
     | 
    
         
            +
                #   Person.where("administrator = 1").order("created_on DESC").find(1)
         
     | 
| 
       58 
13 
     | 
    
         
             
                #
         
     | 
| 
       59 
14 
     | 
    
         
             
                # Note that returned records may not be in the same order as the ids you
         
     | 
| 
       60 
     | 
    
         
            -
                # provide since database rows are unordered. Give an explicit <tt 
     | 
| 
      
 15 
     | 
    
         
            +
                # provide since database rows are unordered. Give an explicit <tt>order</tt>
         
     | 
| 
       61 
16 
     | 
    
         
             
                # to ensure the results are sorted.
         
     | 
| 
       62 
17 
     | 
    
         
             
                #
         
     | 
| 
       63 
     | 
    
         
            -
                # ====  
     | 
| 
       64 
     | 
    
         
            -
                #
         
     | 
| 
       65 
     | 
    
         
            -
                #   # find first
         
     | 
| 
       66 
     | 
    
         
            -
                #   Person.find(:first) # returns the first object fetched by SELECT * FROM people
         
     | 
| 
       67 
     | 
    
         
            -
                #   Person.find(:first, :conditions => [ "user_name = ?", user_name])
         
     | 
| 
       68 
     | 
    
         
            -
                #   Person.find(:first, :conditions => [ "user_name = :u", { :u => user_name }])
         
     | 
| 
       69 
     | 
    
         
            -
                #   Person.find(:first, :order => "created_on DESC", :offset => 5)
         
     | 
| 
       70 
     | 
    
         
            -
                #
         
     | 
| 
       71 
     | 
    
         
            -
                #   # find last
         
     | 
| 
       72 
     | 
    
         
            -
                #   Person.find(:last) # returns the last object fetched by SELECT * FROM people
         
     | 
| 
       73 
     | 
    
         
            -
                #   Person.find(:last, :conditions => [ "user_name = ?", user_name])
         
     | 
| 
       74 
     | 
    
         
            -
                #   Person.find(:last, :order => "created_on DESC", :offset => 5)
         
     | 
| 
       75 
     | 
    
         
            -
                #
         
     | 
| 
       76 
     | 
    
         
            -
                #   # find all
         
     | 
| 
       77 
     | 
    
         
            -
                #   Person.find(:all) # returns an array of objects for all the rows fetched by SELECT * FROM people
         
     | 
| 
       78 
     | 
    
         
            -
                #   Person.find(:all, :conditions => [ "category IN (?)", categories], :limit => 50)
         
     | 
| 
       79 
     | 
    
         
            -
                #   Person.find(:all, :conditions => { :friends => ["Bob", "Steve", "Fred"] }
         
     | 
| 
       80 
     | 
    
         
            -
                #   Person.find(:all, :offset => 10, :limit => 10)
         
     | 
| 
       81 
     | 
    
         
            -
                #   Person.find(:all, :include => [ :account, :friends ])
         
     | 
| 
       82 
     | 
    
         
            -
                #   Person.find(:all, :group => "category")
         
     | 
| 
      
 18 
     | 
    
         
            +
                # ==== Find with lock
         
     | 
| 
       83 
19 
     | 
    
         
             
                #
         
     | 
| 
       84 
20 
     | 
    
         
             
                # Example for find with a lock: Imagine two concurrent transactions:
         
     | 
| 
       85 
21 
     | 
    
         
             
                # each will read <tt>person.visits == 2</tt>, add 1 to it, and save, resulting
         
     | 
| 
       86 
     | 
    
         
            -
                # in two saves of <tt>person.visits = 3</tt>. 
     | 
| 
      
 22 
     | 
    
         
            +
                # in two saves of <tt>person.visits = 3</tt>. By locking the row, the second
         
     | 
| 
       87 
23 
     | 
    
         
             
                # transaction has to wait until the first is finished; we get the
         
     | 
| 
       88 
24 
     | 
    
         
             
                # expected <tt>person.visits == 4</tt>.
         
     | 
| 
       89 
25 
     | 
    
         
             
                #
         
     | 
| 
       90 
26 
     | 
    
         
             
                #   Person.transaction do
         
     | 
| 
       91 
     | 
    
         
            -
                #     person = Person.find(1 
     | 
| 
      
 27 
     | 
    
         
            +
                #     person = Person.lock(true).find(1)
         
     | 
| 
       92 
28 
     | 
    
         
             
                #     person.visits += 1
         
     | 
| 
       93 
29 
     | 
    
         
             
                #     person.save!
         
     | 
| 
       94 
30 
     | 
    
         
             
                #   end
         
     | 
| 
       95 
31 
     | 
    
         
             
                def find(*args)
         
     | 
| 
       96 
     | 
    
         
            -
                   
     | 
| 
       97 
     | 
    
         
            -
             
     | 
| 
       98 
     | 
    
         
            -
                  options = args.extract_options!
         
     | 
| 
       99 
     | 
    
         
            -
             
     | 
| 
       100 
     | 
    
         
            -
                  if options.present?
         
     | 
| 
       101 
     | 
    
         
            -
                    apply_finder_options(options).find(*args)
         
     | 
| 
      
 32 
     | 
    
         
            +
                  if block_given?
         
     | 
| 
      
 33 
     | 
    
         
            +
                    to_a.find { |*block_args| yield(*block_args) }
         
     | 
| 
       102 
34 
     | 
    
         
             
                  else
         
     | 
| 
       103 
     | 
    
         
            -
                     
     | 
| 
       104 
     | 
    
         
            -
                    when :first, :last, :all
         
     | 
| 
       105 
     | 
    
         
            -
                      send(args.first)
         
     | 
| 
       106 
     | 
    
         
            -
                    else
         
     | 
| 
       107 
     | 
    
         
            -
                      find_with_ids(*args)
         
     | 
| 
       108 
     | 
    
         
            -
                    end
         
     | 
| 
      
 35 
     | 
    
         
            +
                    find_with_ids(*args)
         
     | 
| 
       109 
36 
     | 
    
         
             
                  end
         
     | 
| 
       110 
37 
     | 
    
         
             
                end
         
     | 
| 
       111 
38 
     | 
    
         | 
| 
       112 
     | 
    
         
            -
                #  
     | 
| 
       113 
     | 
    
         
            -
                #  
     | 
| 
       114 
     | 
    
         
            -
                 
     | 
| 
       115 
     | 
    
         
            -
             
     | 
| 
       116 
     | 
    
         
            -
             
     | 
| 
       117 
     | 
    
         
            -
             
     | 
| 
      
 39 
     | 
    
         
            +
                # Finds the first record matching the specified conditions. There
         
     | 
| 
      
 40 
     | 
    
         
            +
                # is no implied ordering so if order matters, you should specify it
         
     | 
| 
      
 41 
     | 
    
         
            +
                # yourself.
         
     | 
| 
      
 42 
     | 
    
         
            +
                #
         
     | 
| 
      
 43 
     | 
    
         
            +
                # If no record is found, returns <tt>nil</tt>.
         
     | 
| 
      
 44 
     | 
    
         
            +
                #
         
     | 
| 
      
 45 
     | 
    
         
            +
                #   Post.find_by name: 'Spartacus', rating: 4
         
     | 
| 
      
 46 
     | 
    
         
            +
                #   Post.find_by "published_at < ?", 2.weeks.ago
         
     | 
| 
      
 47 
     | 
    
         
            +
                def find_by(*args)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  where(*args).take
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                # Like <tt>find_by</tt>, except that if no record is found, raises
         
     | 
| 
      
 52 
     | 
    
         
            +
                # an <tt>ActiveRecord::RecordNotFound</tt> error.
         
     | 
| 
      
 53 
     | 
    
         
            +
                def find_by!(*args)
         
     | 
| 
      
 54 
     | 
    
         
            +
                  where(*args).take!
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                # Gives a record (or N records if a parameter is supplied) without any implied
         
     | 
| 
      
 58 
     | 
    
         
            +
                # order. The order will depend on the database implementation.
         
     | 
| 
      
 59 
     | 
    
         
            +
                # If an order is supplied it will be respected.
         
     | 
| 
      
 60 
     | 
    
         
            +
                #
         
     | 
| 
      
 61 
     | 
    
         
            +
                #   Person.take # returns an object fetched by SELECT * FROM people LIMIT 1
         
     | 
| 
      
 62 
     | 
    
         
            +
                #   Person.take(5) # returns 5 objects fetched by SELECT * FROM people LIMIT 5
         
     | 
| 
      
 63 
     | 
    
         
            +
                #   Person.where(["name LIKE '%?'", name]).take
         
     | 
| 
      
 64 
     | 
    
         
            +
                def take(limit = nil)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  limit ? limit(limit).to_a : find_take
         
     | 
| 
      
 66 
     | 
    
         
            +
                end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                # Same as +take+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
         
     | 
| 
      
 69 
     | 
    
         
            +
                # is found. Note that <tt>take!</tt> accepts no arguments.
         
     | 
| 
      
 70 
     | 
    
         
            +
                def take!
         
     | 
| 
      
 71 
     | 
    
         
            +
                  take or raise RecordNotFound
         
     | 
| 
      
 72 
     | 
    
         
            +
                end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                # Find the first record (or first N records if a parameter is supplied).
         
     | 
| 
      
 75 
     | 
    
         
            +
                # If no order is defined it will order by primary key.
         
     | 
| 
      
 76 
     | 
    
         
            +
                #
         
     | 
| 
      
 77 
     | 
    
         
            +
                #   Person.first # returns the first object fetched by SELECT * FROM people
         
     | 
| 
      
 78 
     | 
    
         
            +
                #   Person.where(["user_name = ?", user_name]).first
         
     | 
| 
      
 79 
     | 
    
         
            +
                #   Person.where(["user_name = :u", { u: user_name }]).first
         
     | 
| 
      
 80 
     | 
    
         
            +
                #   Person.order("created_on DESC").offset(5).first
         
     | 
| 
      
 81 
     | 
    
         
            +
                #   Person.first(3) # returns the first three objects fetched by SELECT * FROM people LIMIT 3
         
     | 
| 
      
 82 
     | 
    
         
            +
                def first(limit = nil)
         
     | 
| 
      
 83 
     | 
    
         
            +
                  if limit
         
     | 
| 
      
 84 
     | 
    
         
            +
                    if order_values.empty? && primary_key
         
     | 
| 
      
 85 
     | 
    
         
            +
                      order(arel_table[primary_key].asc).limit(limit).to_a
         
     | 
| 
       118 
86 
     | 
    
         
             
                    else
         
     | 
| 
       119 
     | 
    
         
            -
                       
     | 
| 
      
 87 
     | 
    
         
            +
                      limit(limit).to_a
         
     | 
| 
       120 
88 
     | 
    
         
             
                    end
         
     | 
| 
       121 
89 
     | 
    
         
             
                  else
         
     | 
| 
       122 
90 
     | 
    
         
             
                    find_first
         
     | 
| 
       123 
91 
     | 
    
         
             
                  end
         
     | 
| 
       124 
92 
     | 
    
         
             
                end
         
     | 
| 
       125 
93 
     | 
    
         | 
| 
       126 
     | 
    
         
            -
                #  
     | 
| 
       127 
     | 
    
         
            -
                #  
     | 
| 
       128 
     | 
    
         
            -
                def  
     | 
| 
       129 
     | 
    
         
            -
                   
     | 
| 
       130 
     | 
    
         
            -
             
     | 
| 
       131 
     | 
    
         
            -
             
     | 
| 
      
 94 
     | 
    
         
            +
                # Same as +first+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
         
     | 
| 
      
 95 
     | 
    
         
            +
                # is found. Note that <tt>first!</tt> accepts no arguments.
         
     | 
| 
      
 96 
     | 
    
         
            +
                def first!
         
     | 
| 
      
 97 
     | 
    
         
            +
                  first or raise RecordNotFound
         
     | 
| 
      
 98 
     | 
    
         
            +
                end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                # Find the last record (or last N records if a parameter is supplied).
         
     | 
| 
      
 101 
     | 
    
         
            +
                # If no order is defined it will order by primary key.
         
     | 
| 
      
 102 
     | 
    
         
            +
                #
         
     | 
| 
      
 103 
     | 
    
         
            +
                #   Person.last # returns the last object fetched by SELECT * FROM people
         
     | 
| 
      
 104 
     | 
    
         
            +
                #   Person.where(["user_name = ?", user_name]).last
         
     | 
| 
      
 105 
     | 
    
         
            +
                #   Person.order("created_on DESC").offset(5).last
         
     | 
| 
      
 106 
     | 
    
         
            +
                #   Person.last(3) # returns the last three objects fetched by SELECT * FROM people.
         
     | 
| 
      
 107 
     | 
    
         
            +
                #
         
     | 
| 
      
 108 
     | 
    
         
            +
                # Take note that in that last case, the results are sorted in ascending order:
         
     | 
| 
      
 109 
     | 
    
         
            +
                #
         
     | 
| 
      
 110 
     | 
    
         
            +
                #   [#<Person id:2>, #<Person id:3>, #<Person id:4>]
         
     | 
| 
      
 111 
     | 
    
         
            +
                #
         
     | 
| 
      
 112 
     | 
    
         
            +
                # and not:
         
     | 
| 
      
 113 
     | 
    
         
            +
                #
         
     | 
| 
      
 114 
     | 
    
         
            +
                #   [#<Person id:4>, #<Person id:3>, #<Person id:2>]
         
     | 
| 
      
 115 
     | 
    
         
            +
                def last(limit = nil)
         
     | 
| 
      
 116 
     | 
    
         
            +
                  if limit
         
     | 
| 
      
 117 
     | 
    
         
            +
                    if order_values.empty? && primary_key
         
     | 
| 
      
 118 
     | 
    
         
            +
                      order(arel_table[primary_key].desc).limit(limit).reverse
         
     | 
| 
       132 
119 
     | 
    
         
             
                    else
         
     | 
| 
       133 
     | 
    
         
            -
                       
     | 
| 
      
 120 
     | 
    
         
            +
                      to_a.last(limit)
         
     | 
| 
       134 
121 
     | 
    
         
             
                    end
         
     | 
| 
       135 
122 
     | 
    
         
             
                  else
         
     | 
| 
       136 
123 
     | 
    
         
             
                    find_last
         
     | 
| 
       137 
124 
     | 
    
         
             
                  end
         
     | 
| 
       138 
125 
     | 
    
         
             
                end
         
     | 
| 
       139 
126 
     | 
    
         | 
| 
       140 
     | 
    
         
            -
                #  
     | 
| 
       141 
     | 
    
         
            -
                #  
     | 
| 
       142 
     | 
    
         
            -
                def  
     | 
| 
       143 
     | 
    
         
            -
                   
     | 
| 
      
 127 
     | 
    
         
            +
                # Same as +last+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record
         
     | 
| 
      
 128 
     | 
    
         
            +
                # is found. Note that <tt>last!</tt> accepts no arguments.
         
     | 
| 
      
 129 
     | 
    
         
            +
                def last!
         
     | 
| 
      
 130 
     | 
    
         
            +
                  last or raise RecordNotFound
         
     | 
| 
       144 
131 
     | 
    
         
             
                end
         
     | 
| 
       145 
132 
     | 
    
         | 
| 
       146 
     | 
    
         
            -
                # Returns  
     | 
| 
       147 
     | 
    
         
            -
                # conditions given, or  
     | 
| 
      
 133 
     | 
    
         
            +
                # Returns truthy if a record exists in the table that matches the +id+ or
         
     | 
| 
      
 134 
     | 
    
         
            +
                # conditions given, or falsy otherwise. The argument can take six forms:
         
     | 
| 
       148 
135 
     | 
    
         
             
                #
         
     | 
| 
       149 
136 
     | 
    
         
             
                # * Integer - Finds the record with this primary key.
         
     | 
| 
       150 
137 
     | 
    
         
             
                # * String - Finds the record with a primary key corresponding to this
         
     | 
| 
         @@ -152,8 +139,9 @@ module ActiveRecord 
     | 
|
| 
       152 
139 
     | 
    
         
             
                # * Array - Finds the record that matches these +find+-style conditions
         
     | 
| 
       153 
140 
     | 
    
         
             
                #   (such as <tt>['color = ?', 'red']</tt>).
         
     | 
| 
       154 
141 
     | 
    
         
             
                # * Hash - Finds the record that matches these +find+-style conditions
         
     | 
| 
       155 
     | 
    
         
            -
                #   (such as <tt>{: 
     | 
| 
       156 
     | 
    
         
            -
                # *  
     | 
| 
      
 142 
     | 
    
         
            +
                #   (such as <tt>{color: 'red'}</tt>).
         
     | 
| 
      
 143 
     | 
    
         
            +
                # * +false+ - Returns always +false+.
         
     | 
| 
      
 144 
     | 
    
         
            +
                # * No args - Returns +false+ if the table is empty, +true+ otherwise.
         
     | 
| 
       157 
145 
     | 
    
         
             
                #
         
     | 
| 
       158 
146 
     | 
    
         
             
                # For more information about specifying conditions as a Hash or Array,
         
     | 
| 
       159 
147 
     | 
    
         
             
                # see the Conditions section in the introduction to ActiveRecord::Base.
         
     | 
| 
         @@ -162,50 +150,84 @@ module ActiveRecord 
     | 
|
| 
       162 
150 
     | 
    
         
             
                # 'Jamie'</tt>), since it would be sanitized and then queried against
         
     | 
| 
       163 
151 
     | 
    
         
             
                # the primary key column, like <tt>id = 'name = \'Jamie\''</tt>.
         
     | 
| 
       164 
152 
     | 
    
         
             
                #
         
     | 
| 
       165 
     | 
    
         
            -
                # ==== Examples
         
     | 
| 
       166 
153 
     | 
    
         
             
                #   Person.exists?(5)
         
     | 
| 
       167 
154 
     | 
    
         
             
                #   Person.exists?('5')
         
     | 
| 
       168 
     | 
    
         
            -
                #   Person.exists?(:name => "David")
         
     | 
| 
       169 
155 
     | 
    
         
             
                #   Person.exists?(['name LIKE ?', "%#{query}%"])
         
     | 
| 
      
 156 
     | 
    
         
            +
                #   Person.exists?(name: 'David')
         
     | 
| 
      
 157 
     | 
    
         
            +
                #   Person.exists?(false)
         
     | 
| 
       170 
158 
     | 
    
         
             
                #   Person.exists?
         
     | 
| 
       171 
     | 
    
         
            -
                def exists?( 
     | 
| 
       172 
     | 
    
         
            -
                   
     | 
| 
      
 159 
     | 
    
         
            +
                def exists?(conditions = :none)
         
     | 
| 
      
 160 
     | 
    
         
            +
                  conditions = conditions.id if Base === conditions
         
     | 
| 
      
 161 
     | 
    
         
            +
                  return false if !conditions
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
                  join_dependency = construct_join_dependency_for_association_find
         
     | 
| 
      
 164 
     | 
    
         
            +
                  relation = construct_relation_for_association_find(join_dependency)
         
     | 
| 
      
 165 
     | 
    
         
            +
                  relation = relation.except(:select, :order).select("1 AS one").limit(1)
         
     | 
| 
       173 
166 
     | 
    
         | 
| 
       174 
     | 
    
         
            -
                  case  
     | 
| 
      
 167 
     | 
    
         
            +
                  case conditions
         
     | 
| 
       175 
168 
     | 
    
         
             
                  when Array, Hash
         
     | 
| 
       176 
     | 
    
         
            -
                    where( 
     | 
| 
      
 169 
     | 
    
         
            +
                    relation = relation.where(conditions)
         
     | 
| 
      
 170 
     | 
    
         
            +
                  else
         
     | 
| 
      
 171 
     | 
    
         
            +
                    relation = relation.where(table[primary_key].eq(conditions)) if conditions != :none
         
     | 
| 
      
 172 
     | 
    
         
            +
                  end
         
     | 
| 
      
 173 
     | 
    
         
            +
             
     | 
| 
      
 174 
     | 
    
         
            +
                  connection.select_value(relation, "#{name} Exists", relation.bind_values)
         
     | 
| 
      
 175 
     | 
    
         
            +
                rescue ThrowResult
         
     | 
| 
      
 176 
     | 
    
         
            +
                  false
         
     | 
| 
      
 177 
     | 
    
         
            +
                end
         
     | 
| 
      
 178 
     | 
    
         
            +
             
     | 
| 
      
 179 
     | 
    
         
            +
                # This method is called whenever no records are found with either a single
         
     | 
| 
      
 180 
     | 
    
         
            +
                # id or multiple ids and raises a +ActiveRecord::RecordNotFound+ exception.
         
     | 
| 
      
 181 
     | 
    
         
            +
                #
         
     | 
| 
      
 182 
     | 
    
         
            +
                # The error message is different depending on whether a single id or
         
     | 
| 
      
 183 
     | 
    
         
            +
                # multiple ids are provided. If multiple ids are provided, then the number
         
     | 
| 
      
 184 
     | 
    
         
            +
                # of results obtained should be provided in the +result_size+ argument and
         
     | 
| 
      
 185 
     | 
    
         
            +
                # the expected number of results should be provided in the +expected_size+
         
     | 
| 
      
 186 
     | 
    
         
            +
                # argument.
         
     | 
| 
      
 187 
     | 
    
         
            +
                def raise_record_not_found_exception!(ids, result_size, expected_size) #:nodoc:
         
     | 
| 
      
 188 
     | 
    
         
            +
                  conditions = arel.where_sql
         
     | 
| 
      
 189 
     | 
    
         
            +
                  conditions = " [#{conditions}]" if conditions
         
     | 
| 
      
 190 
     | 
    
         
            +
             
     | 
| 
      
 191 
     | 
    
         
            +
                  if Array(ids).size == 1
         
     | 
| 
      
 192 
     | 
    
         
            +
                    error = "Couldn't find #{@klass.name} with #{primary_key}=#{ids}#{conditions}"
         
     | 
| 
       177 
193 
     | 
    
         
             
                  else
         
     | 
| 
       178 
     | 
    
         
            -
                     
     | 
| 
       179 
     | 
    
         
            -
                     
     | 
| 
       180 
     | 
    
         
            -
                    relation.first ? true : false
         
     | 
| 
      
 194 
     | 
    
         
            +
                    error = "Couldn't find all #{@klass.name.pluralize} with IDs "
         
     | 
| 
      
 195 
     | 
    
         
            +
                    error << "(#{ids.join(", ")})#{conditions} (found #{result_size} results, but was looking for #{expected_size})"
         
     | 
| 
       181 
196 
     | 
    
         
             
                  end
         
     | 
| 
      
 197 
     | 
    
         
            +
             
     | 
| 
      
 198 
     | 
    
         
            +
                  raise RecordNotFound, error
         
     | 
| 
       182 
199 
     | 
    
         
             
                end
         
     | 
| 
       183 
200 
     | 
    
         | 
| 
       184 
201 
     | 
    
         
             
                protected
         
     | 
| 
       185 
202 
     | 
    
         | 
| 
       186 
203 
     | 
    
         
             
                def find_with_associations
         
     | 
| 
       187 
     | 
    
         
            -
                   
     | 
| 
       188 
     | 
    
         
            -
                   
     | 
| 
       189 
     | 
    
         
            -
                  rows =  
     | 
| 
      
 204 
     | 
    
         
            +
                  join_dependency = construct_join_dependency_for_association_find
         
     | 
| 
      
 205 
     | 
    
         
            +
                  relation = construct_relation_for_association_find(join_dependency)
         
     | 
| 
      
 206 
     | 
    
         
            +
                  rows = connection.select_all(relation, 'SQL', relation.bind_values.dup)
         
     | 
| 
       190 
207 
     | 
    
         
             
                  join_dependency.instantiate(rows)
         
     | 
| 
       191 
208 
     | 
    
         
             
                rescue ThrowResult
         
     | 
| 
       192 
209 
     | 
    
         
             
                  []
         
     | 
| 
       193 
210 
     | 
    
         
             
                end
         
     | 
| 
       194 
211 
     | 
    
         | 
| 
      
 212 
     | 
    
         
            +
                def construct_join_dependency_for_association_find
         
     | 
| 
      
 213 
     | 
    
         
            +
                  including = (eager_load_values + includes_values).uniq
         
     | 
| 
      
 214 
     | 
    
         
            +
                  ActiveRecord::Associations::JoinDependency.new(@klass, including, [])
         
     | 
| 
      
 215 
     | 
    
         
            +
                end
         
     | 
| 
      
 216 
     | 
    
         
            +
             
     | 
| 
       195 
217 
     | 
    
         
             
                def construct_relation_for_association_calculations
         
     | 
| 
       196 
     | 
    
         
            -
                  including = ( 
     | 
| 
       197 
     | 
    
         
            -
                  join_dependency = ActiveRecord::Associations:: 
     | 
| 
      
 218 
     | 
    
         
            +
                  including = (eager_load_values + includes_values).uniq
         
     | 
| 
      
 219 
     | 
    
         
            +
                  join_dependency = ActiveRecord::Associations::JoinDependency.new(@klass, including, arel.froms.first)
         
     | 
| 
       198 
220 
     | 
    
         
             
                  relation = except(:includes, :eager_load, :preload)
         
     | 
| 
       199 
221 
     | 
    
         
             
                  apply_join_dependency(relation, join_dependency)
         
     | 
| 
       200 
222 
     | 
    
         
             
                end
         
     | 
| 
       201 
223 
     | 
    
         | 
| 
       202 
224 
     | 
    
         
             
                def construct_relation_for_association_find(join_dependency)
         
     | 
| 
       203 
     | 
    
         
            -
                  relation = except(:includes, :eager_load, :preload, :select).select( 
     | 
| 
      
 225 
     | 
    
         
            +
                  relation = except(:includes, :eager_load, :preload, :select).select(join_dependency.columns)
         
     | 
| 
       204 
226 
     | 
    
         
             
                  apply_join_dependency(relation, join_dependency)
         
     | 
| 
       205 
227 
     | 
    
         
             
                end
         
     | 
| 
       206 
228 
     | 
    
         | 
| 
       207 
229 
     | 
    
         
             
                def apply_join_dependency(relation, join_dependency)
         
     | 
| 
       208 
     | 
    
         
            -
                   
     | 
| 
      
 230 
     | 
    
         
            +
                  join_dependency.join_associations.each do |association|
         
     | 
| 
       209 
231 
     | 
    
         
             
                    relation = association.join_relation(relation)
         
     | 
| 
       210 
232 
     | 
    
         
             
                  end
         
     | 
| 
       211 
233 
     | 
    
         | 
| 
         @@ -222,53 +244,18 @@ module ActiveRecord 
     | 
|
| 
       222 
244 
     | 
    
         
             
                end
         
     | 
| 
       223 
245 
     | 
    
         | 
| 
       224 
246 
     | 
    
         
             
                def construct_limited_ids_condition(relation)
         
     | 
| 
       225 
     | 
    
         
            -
                  orders = relation.order_values. 
     | 
| 
       226 
     | 
    
         
            -
                  values = @klass.connection.distinct("#{ 
     | 
| 
       227 
     | 
    
         
            -
             
     | 
| 
       228 
     | 
    
         
            -
                  ids_array = relation.select(values).collect {|row| row[@klass.primary_key]}
         
     | 
| 
       229 
     | 
    
         
            -
                  ids_array.empty? ? raise(ThrowResult) : primary_key.in(ids_array)
         
     | 
| 
       230 
     | 
    
         
            -
                end
         
     | 
| 
       231 
     | 
    
         
            -
             
     | 
| 
       232 
     | 
    
         
            -
                def find_by_attributes(match, attributes, *args)
         
     | 
| 
       233 
     | 
    
         
            -
                  conditions = attributes.inject({}) {|h, a| h[a] = args[attributes.index(a)]; h}
         
     | 
| 
       234 
     | 
    
         
            -
                  result = where(conditions).send(match.finder)
         
     | 
| 
       235 
     | 
    
         
            -
             
     | 
| 
       236 
     | 
    
         
            -
                  if match.bang? && result.blank?
         
     | 
| 
       237 
     | 
    
         
            -
                    raise RecordNotFound, "Couldn't find #{@klass.name} with #{conditions.to_a.collect {|p| p.join(' = ')}.join(', ')}"
         
     | 
| 
       238 
     | 
    
         
            -
                  else
         
     | 
| 
       239 
     | 
    
         
            -
                    result
         
     | 
| 
       240 
     | 
    
         
            -
                  end
         
     | 
| 
       241 
     | 
    
         
            -
                end
         
     | 
| 
       242 
     | 
    
         
            -
             
     | 
| 
       243 
     | 
    
         
            -
                def find_or_instantiator_by_attributes(match, attributes, *args)
         
     | 
| 
       244 
     | 
    
         
            -
                  protected_attributes_for_create, unprotected_attributes_for_create = {}, {}
         
     | 
| 
       245 
     | 
    
         
            -
                  args.each_with_index do |arg, i|
         
     | 
| 
       246 
     | 
    
         
            -
                    if arg.is_a?(Hash)
         
     | 
| 
       247 
     | 
    
         
            -
                      protected_attributes_for_create = args[i].with_indifferent_access
         
     | 
| 
       248 
     | 
    
         
            -
                    else
         
     | 
| 
       249 
     | 
    
         
            -
                      unprotected_attributes_for_create[attributes[i]] = args[i]
         
     | 
| 
       250 
     | 
    
         
            -
                    end
         
     | 
| 
       251 
     | 
    
         
            -
                  end
         
     | 
| 
      
 247 
     | 
    
         
            +
                  orders = relation.order_values.map { |val| val.presence }.compact
         
     | 
| 
      
 248 
     | 
    
         
            +
                  values = @klass.connection.distinct("#{quoted_table_name}.#{primary_key}", orders)
         
     | 
| 
       252 
249 
     | 
    
         | 
| 
       253 
     | 
    
         
            -
                   
     | 
| 
      
 250 
     | 
    
         
            +
                  relation = relation.dup.select(values)
         
     | 
| 
       254 
251 
     | 
    
         | 
| 
       255 
     | 
    
         
            -
                   
     | 
| 
      
 252 
     | 
    
         
            +
                  id_rows = @klass.connection.select_all(relation.arel, 'SQL', relation.bind_values)
         
     | 
| 
      
 253 
     | 
    
         
            +
                  ids_array = id_rows.map {|row| row[primary_key]}
         
     | 
| 
       256 
254 
     | 
    
         | 
| 
       257 
     | 
    
         
            -
                   
     | 
| 
       258 
     | 
    
         
            -
                    record = @klass.new do |r|
         
     | 
| 
       259 
     | 
    
         
            -
                      r.send(:attributes=, protected_attributes_for_create, true) unless protected_attributes_for_create.empty?
         
     | 
| 
       260 
     | 
    
         
            -
                      r.send(:attributes=, unprotected_attributes_for_create, false) unless unprotected_attributes_for_create.empty?
         
     | 
| 
       261 
     | 
    
         
            -
                    end
         
     | 
| 
       262 
     | 
    
         
            -
                    yield(record) if block_given?
         
     | 
| 
       263 
     | 
    
         
            -
                    record.save if match.instantiator == :create
         
     | 
| 
       264 
     | 
    
         
            -
                  end
         
     | 
| 
       265 
     | 
    
         
            -
             
     | 
| 
       266 
     | 
    
         
            -
                  record
         
     | 
| 
      
 255 
     | 
    
         
            +
                  ids_array.empty? ? raise(ThrowResult) : table[primary_key].in(ids_array)
         
     | 
| 
       267 
256 
     | 
    
         
             
                end
         
     | 
| 
       268 
257 
     | 
    
         | 
| 
       269 
258 
     | 
    
         
             
                def find_with_ids(*ids)
         
     | 
| 
       270 
     | 
    
         
            -
                  return to_a.find { |*block_args| yield(*block_args) } if block_given?
         
     | 
| 
       271 
     | 
    
         
            -
             
     | 
| 
       272 
259 
     | 
    
         
             
                  expects_array = ids.first.kind_of?(Array)
         
     | 
| 
       273 
260 
     | 
    
         
             
                  return ids.first if expects_array && ids.first.empty?
         
     | 
| 
       274 
261 
     | 
    
         | 
| 
         @@ -288,41 +275,44 @@ module ActiveRecord 
     | 
|
| 
       288 
275 
     | 
    
         
             
                def find_one(id)
         
     | 
| 
       289 
276 
     | 
    
         
             
                  id = id.id if ActiveRecord::Base === id
         
     | 
| 
       290 
277 
     | 
    
         | 
| 
       291 
     | 
    
         
            -
                   
     | 
| 
      
 278 
     | 
    
         
            +
                  column = columns_hash[primary_key]
         
     | 
| 
      
 279 
     | 
    
         
            +
                  substitute = connection.substitute_at(column, bind_values.length)
         
     | 
| 
      
 280 
     | 
    
         
            +
                  relation = where(table[primary_key].eq(substitute))
         
     | 
| 
      
 281 
     | 
    
         
            +
                  relation.bind_values += [[column, id]]
         
     | 
| 
      
 282 
     | 
    
         
            +
                  record = relation.take
         
     | 
| 
       292 
283 
     | 
    
         | 
| 
       293 
     | 
    
         
            -
                  unless record
         
     | 
| 
       294 
     | 
    
         
            -
                    conditions = arel.wheres.map { |x| x.value }.join(', ')
         
     | 
| 
       295 
     | 
    
         
            -
                    conditions = " [WHERE #{conditions}]" if conditions.present?
         
     | 
| 
       296 
     | 
    
         
            -
                    raise RecordNotFound, "Couldn't find #{@klass.name} with ID=#{id}#{conditions}"
         
     | 
| 
       297 
     | 
    
         
            -
                  end
         
     | 
| 
      
 284 
     | 
    
         
            +
                  raise_record_not_found_exception!(id, 0, 1) unless record
         
     | 
| 
       298 
285 
     | 
    
         | 
| 
       299 
286 
     | 
    
         
             
                  record
         
     | 
| 
       300 
287 
     | 
    
         
             
                end
         
     | 
| 
       301 
288 
     | 
    
         | 
| 
       302 
289 
     | 
    
         
             
                def find_some(ids)
         
     | 
| 
       303 
     | 
    
         
            -
                  result = where(primary_key.in(ids)). 
     | 
| 
      
 290 
     | 
    
         
            +
                  result = where(table[primary_key].in(ids)).to_a
         
     | 
| 
       304 
291 
     | 
    
         | 
| 
       305 
292 
     | 
    
         
             
                  expected_size =
         
     | 
| 
       306 
     | 
    
         
            -
                    if  
     | 
| 
       307 
     | 
    
         
            -
                       
     | 
| 
      
 293 
     | 
    
         
            +
                    if limit_value && ids.size > limit_value
         
     | 
| 
      
 294 
     | 
    
         
            +
                      limit_value
         
     | 
| 
       308 
295 
     | 
    
         
             
                    else
         
     | 
| 
       309 
296 
     | 
    
         
             
                      ids.size
         
     | 
| 
       310 
297 
     | 
    
         
             
                    end
         
     | 
| 
       311 
298 
     | 
    
         | 
| 
       312 
299 
     | 
    
         
             
                  # 11 ids with limit 3, offset 9 should give 2 results.
         
     | 
| 
       313 
     | 
    
         
            -
                  if  
     | 
| 
       314 
     | 
    
         
            -
                    expected_size = ids.size -  
     | 
| 
      
 300 
     | 
    
         
            +
                  if offset_value && (ids.size - offset_value < expected_size)
         
     | 
| 
      
 301 
     | 
    
         
            +
                    expected_size = ids.size - offset_value
         
     | 
| 
       315 
302 
     | 
    
         
             
                  end
         
     | 
| 
       316 
303 
     | 
    
         | 
| 
       317 
304 
     | 
    
         
             
                  if result.size == expected_size
         
     | 
| 
       318 
305 
     | 
    
         
             
                    result
         
     | 
| 
       319 
306 
     | 
    
         
             
                  else
         
     | 
| 
       320 
     | 
    
         
            -
                     
     | 
| 
       321 
     | 
    
         
            -
             
     | 
| 
      
 307 
     | 
    
         
            +
                    raise_record_not_found_exception!(ids, result.size, expected_size)
         
     | 
| 
      
 308 
     | 
    
         
            +
                  end
         
     | 
| 
      
 309 
     | 
    
         
            +
                end
         
     | 
| 
       322 
310 
     | 
    
         | 
| 
       323 
     | 
    
         
            -
             
     | 
| 
       324 
     | 
    
         
            -
             
     | 
| 
       325 
     | 
    
         
            -
                     
     | 
| 
      
 311 
     | 
    
         
            +
                def find_take
         
     | 
| 
      
 312 
     | 
    
         
            +
                  if loaded?
         
     | 
| 
      
 313 
     | 
    
         
            +
                    @records.first
         
     | 
| 
      
 314 
     | 
    
         
            +
                  else
         
     | 
| 
      
 315 
     | 
    
         
            +
                    @take ||= limit(1).to_a.first
         
     | 
| 
       326 
316 
     | 
    
         
             
                  end
         
     | 
| 
       327 
317 
     | 
    
         
             
                end
         
     | 
| 
       328 
318 
     | 
    
         | 
| 
         @@ -330,7 +320,12 @@ module ActiveRecord 
     | 
|
| 
       330 
320 
     | 
    
         
             
                  if loaded?
         
     | 
| 
       331 
321 
     | 
    
         
             
                    @records.first
         
     | 
| 
       332 
322 
     | 
    
         
             
                  else
         
     | 
| 
       333 
     | 
    
         
            -
                    @first ||= 
     | 
| 
      
 323 
     | 
    
         
            +
                    @first ||=
         
     | 
| 
      
 324 
     | 
    
         
            +
                      if with_default_scope.order_values.empty? && primary_key
         
     | 
| 
      
 325 
     | 
    
         
            +
                        order(arel_table[primary_key].asc).limit(1).to_a.first
         
     | 
| 
      
 326 
     | 
    
         
            +
                      else
         
     | 
| 
      
 327 
     | 
    
         
            +
                        limit(1).to_a.first
         
     | 
| 
      
 328 
     | 
    
         
            +
                      end
         
     | 
| 
       334 
329 
     | 
    
         
             
                  end
         
     | 
| 
       335 
330 
     | 
    
         
             
                end
         
     | 
| 
       336 
331 
     | 
    
         | 
| 
         @@ -338,18 +333,17 @@ module ActiveRecord 
     | 
|
| 
       338 
333 
     | 
    
         
             
                  if loaded?
         
     | 
| 
       339 
334 
     | 
    
         
             
                    @records.last
         
     | 
| 
       340 
335 
     | 
    
         
             
                  else
         
     | 
| 
       341 
     | 
    
         
            -
                    @last ||= 
     | 
| 
      
 336 
     | 
    
         
            +
                    @last ||=
         
     | 
| 
      
 337 
     | 
    
         
            +
                      if offset_value || limit_value
         
     | 
| 
      
 338 
     | 
    
         
            +
                        to_a.last
         
     | 
| 
      
 339 
     | 
    
         
            +
                      else
         
     | 
| 
      
 340 
     | 
    
         
            +
                        reverse_order.limit(1).to_a.first
         
     | 
| 
      
 341 
     | 
    
         
            +
                      end
         
     | 
| 
       342 
342 
     | 
    
         
             
                  end
         
     | 
| 
       343 
343 
     | 
    
         
             
                end
         
     | 
| 
       344 
344 
     | 
    
         | 
| 
       345 
     | 
    
         
            -
                def column_aliases(join_dependency)
         
     | 
| 
       346 
     | 
    
         
            -
                  join_dependency.joins.collect{|join| join.column_names_with_alias.collect{|column_name, aliased_name|
         
     | 
| 
       347 
     | 
    
         
            -
                      "#{connection.quote_table_name join.aliased_table_name}.#{connection.quote_column_name column_name} AS #{aliased_name}"}}.flatten.join(", ")
         
     | 
| 
       348 
     | 
    
         
            -
                end
         
     | 
| 
       349 
     | 
    
         
            -
             
     | 
| 
       350 
345 
     | 
    
         
             
                def using_limitable_reflections?(reflections)
         
     | 
| 
       351 
346 
     | 
    
         
             
                  reflections.none? { |r| r.collection? }
         
     | 
| 
       352 
347 
     | 
    
         
             
                end
         
     | 
| 
       353 
     | 
    
         
            -
             
     | 
| 
       354 
348 
     | 
    
         
             
              end
         
     | 
| 
       355 
349 
     | 
    
         
             
            end
         
     |