activerecord 4.0.13 → 4.1.0.beta1
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 +4 -4
- data/CHANGELOG.md +745 -2700
- data/README.rdoc +2 -2
- data/examples/performance.rb +30 -18
- data/examples/simple.rb +4 -4
- data/lib/active_record.rb +2 -6
- data/lib/active_record/aggregations.rb +2 -1
- data/lib/active_record/association_relation.rb +0 -4
- data/lib/active_record/associations.rb +87 -43
- data/lib/active_record/associations/alias_tracker.rb +1 -3
- data/lib/active_record/associations/association.rb +8 -16
- data/lib/active_record/associations/association_scope.rb +5 -16
- data/lib/active_record/associations/belongs_to_association.rb +34 -25
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +78 -54
- data/lib/active_record/associations/builder/belongs_to.rb +91 -58
- data/lib/active_record/associations/builder/collection_association.rb +47 -45
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +107 -25
- data/lib/active_record/associations/builder/has_many.rb +2 -2
- data/lib/active_record/associations/builder/has_one.rb +5 -7
- data/lib/active_record/associations/builder/singular_association.rb +6 -7
- data/lib/active_record/associations/collection_association.rb +68 -105
- data/lib/active_record/associations/collection_proxy.rb +12 -15
- data/lib/active_record/associations/has_many_association.rb +11 -9
- data/lib/active_record/associations/has_many_through_association.rb +16 -12
- data/lib/active_record/associations/has_one_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +204 -165
- data/lib/active_record/associations/join_dependency/join_association.rb +43 -101
- data/lib/active_record/associations/join_dependency/join_base.rb +6 -8
- data/lib/active_record/associations/join_dependency/join_part.rb +18 -37
- data/lib/active_record/associations/join_helper.rb +2 -11
- data/lib/active_record/associations/preloader.rb +89 -34
- data/lib/active_record/associations/preloader/association.rb +43 -25
- data/lib/active_record/associations/preloader/collection_association.rb +2 -2
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/singular_association.rb +3 -3
- data/lib/active_record/associations/preloader/through_association.rb +58 -26
- data/lib/active_record/associations/singular_association.rb +6 -5
- data/lib/active_record/associations/through_association.rb +2 -2
- data/lib/active_record/attribute_assignment.rb +5 -2
- data/lib/active_record/attribute_methods.rb +45 -40
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -1
- data/lib/active_record/attribute_methods/dirty.rb +8 -22
- data/lib/active_record/attribute_methods/primary_key.rb +1 -7
- data/lib/active_record/attribute_methods/read.rb +55 -28
- data/lib/active_record/attribute_methods/serialization.rb +12 -33
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -13
- data/lib/active_record/attribute_methods/write.rb +37 -12
- data/lib/active_record/autosave_association.rb +207 -207
- data/lib/active_record/base.rb +5 -1
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +2 -7
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +11 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +12 -14
- data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -5
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +84 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +9 -8
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +52 -83
- data/lib/active_record/connection_adapters/abstract/transaction.rb +0 -5
- data/lib/active_record/connection_adapters/abstract_adapter.rb +14 -97
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +58 -60
- data/lib/active_record/connection_adapters/column.rb +1 -35
- data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +3 -4
- data/lib/active_record/connection_adapters/mysql_adapter.rb +16 -15
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +24 -18
- data/lib/active_record/connection_adapters/postgresql/cast.rb +20 -16
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +23 -43
- data/lib/active_record/connection_adapters/postgresql/oid.rb +19 -12
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +28 -23
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +8 -30
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +92 -75
- data/lib/active_record/connection_adapters/schema_cache.rb +8 -29
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +31 -64
- data/lib/active_record/connection_handling.rb +2 -2
- data/lib/active_record/core.rb +22 -43
- data/lib/active_record/counter_cache.rb +7 -7
- data/lib/active_record/enum.rb +100 -0
- data/lib/active_record/errors.rb +10 -5
- data/lib/active_record/fixture_set/file.rb +2 -1
- data/lib/active_record/fixtures.rb +171 -74
- data/lib/active_record/inheritance.rb +16 -22
- data/lib/active_record/integration.rb +52 -1
- data/lib/active_record/locking/optimistic.rb +7 -2
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +5 -12
- data/lib/active_record/migration.rb +62 -46
- data/lib/active_record/migration/command_recorder.rb +7 -13
- data/lib/active_record/model_schema.rb +7 -14
- data/lib/active_record/nested_attributes.rb +10 -8
- data/lib/active_record/no_touching.rb +52 -0
- data/lib/active_record/null_relation.rb +3 -3
- data/lib/active_record/persistence.rb +16 -34
- data/lib/active_record/querying.rb +14 -12
- data/lib/active_record/railtie.rb +0 -50
- data/lib/active_record/railties/databases.rake +12 -15
- data/lib/active_record/readonly_attributes.rb +0 -6
- data/lib/active_record/reflection.rb +189 -75
- data/lib/active_record/relation.rb +69 -94
- data/lib/active_record/relation/batches.rb +57 -23
- data/lib/active_record/relation/calculations.rb +36 -43
- data/lib/active_record/relation/delegation.rb +54 -39
- data/lib/active_record/relation/finder_methods.rb +107 -62
- data/lib/active_record/relation/merger.rb +7 -20
- data/lib/active_record/relation/predicate_builder.rb +57 -38
- data/lib/active_record/relation/predicate_builder/array_handler.rb +29 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
- data/lib/active_record/relation/query_methods.rb +110 -98
- data/lib/active_record/relation/spawn_methods.rb +1 -2
- data/lib/active_record/result.rb +45 -6
- data/lib/active_record/runtime_registry.rb +5 -0
- data/lib/active_record/sanitization.rb +6 -8
- data/lib/active_record/schema_dumper.rb +16 -5
- data/lib/active_record/schema_migration.rb +24 -25
- data/lib/active_record/scoping/default.rb +5 -18
- data/lib/active_record/scoping/named.rb +8 -29
- data/lib/active_record/store.rb +56 -28
- data/lib/active_record/tasks/database_tasks.rb +8 -4
- data/lib/active_record/timestamp.rb +4 -4
- data/lib/active_record/transactions.rb +8 -10
- data/lib/active_record/validations/presence.rb +1 -1
- data/lib/active_record/validations/uniqueness.rb +1 -6
- data/lib/active_record/version.rb +1 -1
- data/lib/rails/generators/active_record.rb +2 -8
- data/lib/rails/generators/active_record/migration.rb +18 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +4 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +4 -0
- metadata +32 -45
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -65
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
- data/lib/active_record/tasks/firebird_database_tasks.rb +0 -56
- data/lib/active_record/tasks/oracle_database_tasks.rb +0 -45
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +0 -48
- data/lib/active_record/test_case.rb +0 -102
| @@ -0,0 +1,100 @@ | |
| 1 | 
            +
            module ActiveRecord
         | 
| 2 | 
            +
              # Declare an enum attribute where the values map to integers in the database, but can be queried by name. Example:
         | 
| 3 | 
            +
              #
         | 
| 4 | 
            +
              #   class Conversation < ActiveRecord::Base
         | 
| 5 | 
            +
              #     enum status: [ :active, :archived ]
         | 
| 6 | 
            +
              #   end
         | 
| 7 | 
            +
              #
         | 
| 8 | 
            +
              #   # conversation.update! status: 0
         | 
| 9 | 
            +
              #   conversation.active!
         | 
| 10 | 
            +
              #   conversation.active? # => true
         | 
| 11 | 
            +
              #   conversation.status  # => "active"
         | 
| 12 | 
            +
              #
         | 
| 13 | 
            +
              #   # conversation.update! status: 1
         | 
| 14 | 
            +
              #   conversation.archived!
         | 
| 15 | 
            +
              #   conversation.archived? # => true
         | 
| 16 | 
            +
              #   conversation.status    # => "archived"
         | 
| 17 | 
            +
              #
         | 
| 18 | 
            +
              #   # conversation.update! status: 1
         | 
| 19 | 
            +
              #   conversation.status = "archived"
         | 
| 20 | 
            +
              #
         | 
| 21 | 
            +
              # You can set the default value from the database declaration, like:
         | 
| 22 | 
            +
              #
         | 
| 23 | 
            +
              #   create_table :conversations do |t|
         | 
| 24 | 
            +
              #     t.column :status, :integer, default: 0
         | 
| 25 | 
            +
              #   end
         | 
| 26 | 
            +
              #
         | 
| 27 | 
            +
              # Good practice is to let the first declared status be the default.
         | 
| 28 | 
            +
              #
         | 
| 29 | 
            +
              # Finally, it's also possible to explicitly map the relation between attribute and
         | 
| 30 | 
            +
              # database integer with a +Hash+:
         | 
| 31 | 
            +
              #
         | 
| 32 | 
            +
              #   class Conversation < ActiveRecord::Base
         | 
| 33 | 
            +
              #     enum status: { active: 0, archived: 1 }
         | 
| 34 | 
            +
              #   end
         | 
| 35 | 
            +
              #
         | 
| 36 | 
            +
              # Note that when an +Array+ is used, the implicit mapping from the values to database
         | 
| 37 | 
            +
              # integers is derived from the order the values appear in the array. In the example,
         | 
| 38 | 
            +
              # <tt>:active</tt> is mapped to +0+ as it's the first element, and <tt>:archived</tt>
         | 
| 39 | 
            +
              # is mapped to +1+. In general, the +i+-th element is mapped to <tt>i-1</tt> in the
         | 
| 40 | 
            +
              # database.
         | 
| 41 | 
            +
              #
         | 
| 42 | 
            +
              # Therefore, once a value is added to the enum array, its position in the array must
         | 
| 43 | 
            +
              # be maintained, and new values should only be added to the end of the array. To
         | 
| 44 | 
            +
              # remove unused values, the explicit +Hash+ syntax should be used.
         | 
| 45 | 
            +
              #
         | 
| 46 | 
            +
              # In rare circumstances you might need to access the mapping directly.
         | 
| 47 | 
            +
              # The mappings are exposed through a constant with the attributes name:
         | 
| 48 | 
            +
              #
         | 
| 49 | 
            +
              #   Conversation::STATUS # => { "active" => 0, "archived" => 1 }
         | 
| 50 | 
            +
              #
         | 
| 51 | 
            +
              # Use that constant when you need to know the ordinal value of an enum:
         | 
| 52 | 
            +
              #
         | 
| 53 | 
            +
              #   Conversation.where("status <> ?", Conversation::STATUS[:archived])
         | 
| 54 | 
            +
              module Enum
         | 
| 55 | 
            +
                def enum(definitions)
         | 
| 56 | 
            +
                  klass = self
         | 
| 57 | 
            +
                  definitions.each do |name, values|
         | 
| 58 | 
            +
                    # DIRECTION = { }
         | 
| 59 | 
            +
                    enum_values = _enum_methods_module.const_set name.to_s.upcase, ActiveSupport::HashWithIndifferentAccess.new
         | 
| 60 | 
            +
                    name        = name.to_sym
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                    _enum_methods_module.module_eval do
         | 
| 63 | 
            +
                      # def direction=(value) self[:direction] = DIRECTION[value] end
         | 
| 64 | 
            +
                      define_method("#{name}=") { |value|
         | 
| 65 | 
            +
                        unless enum_values.has_key?(value)
         | 
| 66 | 
            +
                          raise ArgumentError, "'#{value}' is not a valid #{name}"
         | 
| 67 | 
            +
                        end
         | 
| 68 | 
            +
                        self[name] = enum_values[value]
         | 
| 69 | 
            +
                      }
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                      # def direction() DIRECTION.key self[:direction] end
         | 
| 72 | 
            +
                      define_method(name) { enum_values.key self[name] }
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                      pairs = values.respond_to?(:each_pair) ? values.each_pair : values.each_with_index
         | 
| 75 | 
            +
                      pairs.each do |value, i|
         | 
| 76 | 
            +
                        enum_values[value] = i
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                        # scope :incoming, -> { where direction: 0 }
         | 
| 79 | 
            +
                        klass.scope value, -> { klass.where name => i }
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                        # def incoming?() direction == 0 end
         | 
| 82 | 
            +
                        define_method("#{value}?") { self[name] == i }
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                        # def incoming! update! direction: :incoming end
         | 
| 85 | 
            +
                        define_method("#{value}!") { update! name => value }
         | 
| 86 | 
            +
                      end
         | 
| 87 | 
            +
                    end
         | 
| 88 | 
            +
                  end
         | 
| 89 | 
            +
                end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                private
         | 
| 92 | 
            +
                  def _enum_methods_module
         | 
| 93 | 
            +
                    @_enum_methods_module ||= begin
         | 
| 94 | 
            +
                      mod = Module.new
         | 
| 95 | 
            +
                      include mod
         | 
| 96 | 
            +
                      mod
         | 
| 97 | 
            +
                    end
         | 
| 98 | 
            +
                  end
         | 
| 99 | 
            +
              end
         | 
| 100 | 
            +
            end
         | 
    
        data/lib/active_record/errors.rb
    CHANGED
    
    | @@ -69,10 +69,6 @@ module ActiveRecord | |
| 69 69 | 
             
                end
         | 
| 70 70 | 
             
              end
         | 
| 71 71 |  | 
| 72 | 
            -
              # Raised when SQL statement is invalid and the application gets a blank result.
         | 
| 73 | 
            -
              class ThrowResult < ActiveRecordError
         | 
| 74 | 
            -
              end
         | 
| 75 | 
            -
             | 
| 76 72 | 
             
              # Defunct wrapper class kept for compatibility.
         | 
| 77 73 | 
             
              # +StatementInvalid+ wraps the original exception now.
         | 
| 78 74 | 
             
              class WrappedDatabaseException < StatementInvalid
         | 
| @@ -159,6 +155,15 @@ module ActiveRecord | |
| 159 155 |  | 
| 160 156 | 
             
              # Raised when unknown attributes are supplied via mass assignment.
         | 
| 161 157 | 
             
              class UnknownAttributeError < NoMethodError
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                attr_reader :record, :attribute
         | 
| 160 | 
            +
             | 
| 161 | 
            +
                def initialize(record, attribute)
         | 
| 162 | 
            +
                  @record = record
         | 
| 163 | 
            +
                  @attribute = attribute.to_s
         | 
| 164 | 
            +
                  super("unknown attribute: #{attribute}")
         | 
| 165 | 
            +
                end
         | 
| 166 | 
            +
             | 
| 162 167 | 
             
              end
         | 
| 163 168 |  | 
| 164 169 | 
             
              # Raised when an error occurred while doing a mass assignment to an attribute through the
         | 
| @@ -183,7 +188,7 @@ module ActiveRecord | |
| 183 188 | 
             
                end
         | 
| 184 189 | 
             
              end
         | 
| 185 190 |  | 
| 186 | 
            -
              # Raised when a primary key is needed, but  | 
| 191 | 
            +
              # Raised when a primary key is needed, but not specified in the schema or model.
         | 
| 187 192 | 
             
              class UnknownPrimaryKey < ActiveRecordError
         | 
| 188 193 | 
             
                attr_reader :model
         | 
| 189 194 |  | 
| @@ -119,6 +119,23 @@ module ActiveRecord | |
| 119 119 | 
             
              # perhaps you should reexamine whether your application is properly testable. Hence, dynamic values
         | 
| 120 120 | 
             
              # in fixtures are to be considered a code smell.
         | 
| 121 121 | 
             
              #
         | 
| 122 | 
            +
              # Helper methods defined in a fixture will not be available in other fixtures, to prevent against
         | 
| 123 | 
            +
              # unwanted inter-test dependencies. Methods used by multiple fixtures should be defined in a module
         | 
| 124 | 
            +
              # that is included in <tt>ActiveRecord::FixtureSet.context_class</tt>.
         | 
| 125 | 
            +
              #
         | 
| 126 | 
            +
              # - define a helper method in `test_helper.rb`
         | 
| 127 | 
            +
              #     class FixtureFileHelpers
         | 
| 128 | 
            +
              #       def file_sha(path)
         | 
| 129 | 
            +
              #         Digest::SHA2.hexdigest(File.read(Rails.root.join('test/fixtures', path)))
         | 
| 130 | 
            +
              #       end
         | 
| 131 | 
            +
              #     end
         | 
| 132 | 
            +
              #     ActiveRecord::FixtureSet.context_class.send :include, FixtureFileHelpers
         | 
| 133 | 
            +
              #
         | 
| 134 | 
            +
              # - use the helper method in a fixture
         | 
| 135 | 
            +
              #     photo:
         | 
| 136 | 
            +
              #       name: kitten.png
         | 
| 137 | 
            +
              #       sha: <%= file_sha 'files/kitten.png' %>
         | 
| 138 | 
            +
              #
         | 
| 122 139 | 
             
              # = Transactional Fixtures
         | 
| 123 140 | 
             
              #
         | 
| 124 141 | 
             
              # Test cases can use begin+rollback to isolate their changes to the database instead of having to
         | 
| @@ -379,22 +396,16 @@ module ActiveRecord | |
| 379 396 |  | 
| 380 397 | 
             
                @@all_cached_fixtures = Hash.new { |h,k| h[k] = {} }
         | 
| 381 398 |  | 
| 382 | 
            -
                def self. | 
| 383 | 
            -
                   | 
| 384 | 
            -
                    "ActiveRecord::Fixtures.find_table_name is deprecated and shall be removed from future releases.  Use ActiveRecord::Fixtures.default_fixture_model_name instead.")
         | 
| 385 | 
            -
                  default_fixture_model_name(fixture_set_name)
         | 
| 386 | 
            -
                end
         | 
| 387 | 
            -
             | 
| 388 | 
            -
                def self.default_fixture_model_name(fixture_set_name) # :nodoc:
         | 
| 389 | 
            -
                  ActiveRecord::Base.pluralize_table_names ?
         | 
| 399 | 
            +
                def self.default_fixture_model_name(fixture_set_name, config = ActiveRecord::Base) # :nodoc:
         | 
| 400 | 
            +
                  config.pluralize_table_names ?
         | 
| 390 401 | 
             
                    fixture_set_name.singularize.camelize :
         | 
| 391 402 | 
             
                    fixture_set_name.camelize
         | 
| 392 403 | 
             
                end
         | 
| 393 404 |  | 
| 394 | 
            -
                def self.default_fixture_table_name(fixture_set_name) # :nodoc:
         | 
| 395 | 
            -
                   "#{  | 
| 405 | 
            +
                def self.default_fixture_table_name(fixture_set_name, config = ActiveRecord::Base) # :nodoc:
         | 
| 406 | 
            +
                   "#{ config.table_name_prefix }"\
         | 
| 396 407 | 
             
                   "#{ fixture_set_name.tr('/', '_') }"\
         | 
| 397 | 
            -
                   "#{  | 
| 408 | 
            +
                   "#{ config.table_name_suffix }".to_sym
         | 
| 398 409 | 
             
                end
         | 
| 399 410 |  | 
| 400 411 | 
             
                def self.reset_cache
         | 
| @@ -442,9 +453,47 @@ module ActiveRecord | |
| 442 453 | 
             
                cattr_accessor :all_loaded_fixtures
         | 
| 443 454 | 
             
                self.all_loaded_fixtures = {}
         | 
| 444 455 |  | 
| 445 | 
            -
                 | 
| 456 | 
            +
                class ClassCache
         | 
| 457 | 
            +
                  def initialize(class_names, config)
         | 
| 458 | 
            +
                    @class_names = class_names.stringify_keys
         | 
| 459 | 
            +
                    @config      = config
         | 
| 460 | 
            +
             | 
| 461 | 
            +
                    # Remove string values that aren't constants or subclasses of AR
         | 
| 462 | 
            +
                    @class_names.delete_if { |k,klass|
         | 
| 463 | 
            +
                      unless klass.is_a? Class
         | 
| 464 | 
            +
                        klass = klass.safe_constantize
         | 
| 465 | 
            +
                        ActiveSupport::Deprecation.warn("The ability to pass in strings as a class name will be removed in Rails 4.2, consider using the class itself instead.")
         | 
| 466 | 
            +
                      end
         | 
| 467 | 
            +
                      !insert_class(@class_names, k, klass)
         | 
| 468 | 
            +
                    }
         | 
| 469 | 
            +
                  end
         | 
| 470 | 
            +
             | 
| 471 | 
            +
                  def [](fs_name)
         | 
| 472 | 
            +
                    @class_names.fetch(fs_name) {
         | 
| 473 | 
            +
                      klass = default_fixture_model(fs_name, @config).safe_constantize
         | 
| 474 | 
            +
                      insert_class(@class_names, fs_name, klass)
         | 
| 475 | 
            +
                    }
         | 
| 476 | 
            +
                  end
         | 
| 477 | 
            +
             | 
| 478 | 
            +
                  private
         | 
| 479 | 
            +
             | 
| 480 | 
            +
                  def insert_class(class_names, name, klass)
         | 
| 481 | 
            +
                    # We only want to deal with AR objects.
         | 
| 482 | 
            +
                    if klass && klass < ActiveRecord::Base
         | 
| 483 | 
            +
                      class_names[name] = klass
         | 
| 484 | 
            +
                    else
         | 
| 485 | 
            +
                      class_names[name] = nil
         | 
| 486 | 
            +
                    end
         | 
| 487 | 
            +
                  end
         | 
| 488 | 
            +
             | 
| 489 | 
            +
                  def default_fixture_model(fs_name, config)
         | 
| 490 | 
            +
                    ActiveRecord::FixtureSet.default_fixture_model_name(fs_name, config)
         | 
| 491 | 
            +
                  end
         | 
| 492 | 
            +
                end
         | 
| 493 | 
            +
             | 
| 494 | 
            +
                def self.create_fixtures(fixtures_directory, fixture_set_names, class_names = {}, config = ActiveRecord::Base)
         | 
| 446 495 | 
             
                  fixture_set_names = Array(fixture_set_names).map(&:to_s)
         | 
| 447 | 
            -
                  class_names = class_names | 
| 496 | 
            +
                  class_names = ClassCache.new class_names, config
         | 
| 448 497 |  | 
| 449 498 | 
             
                  # FIXME: Apparently JK uses this.
         | 
| 450 499 | 
             
                  connection = block_given? ? yield : ActiveRecord::Base.connection
         | 
| @@ -458,10 +507,12 @@ module ActiveRecord | |
| 458 507 | 
             
                      fixtures_map = {}
         | 
| 459 508 |  | 
| 460 509 | 
             
                      fixture_sets = files_to_read.map do |fs_name|
         | 
| 510 | 
            +
                        klass = class_names[fs_name]
         | 
| 511 | 
            +
                        conn = klass ? klass.connection : connection
         | 
| 461 512 | 
             
                        fixtures_map[fs_name] = new( # ActiveRecord::FixtureSet.new
         | 
| 462 | 
            -
                           | 
| 513 | 
            +
                          conn,
         | 
| 463 514 | 
             
                          fs_name,
         | 
| 464 | 
            -
                           | 
| 515 | 
            +
                          klass,
         | 
| 465 516 | 
             
                          ::File.join(fixtures_directory, fs_name))
         | 
| 466 517 | 
             
                      end
         | 
| 467 518 |  | 
| @@ -470,16 +521,8 @@ module ActiveRecord | |
| 470 521 | 
             
                      connection.transaction(:requires_new => true) do
         | 
| 471 522 | 
             
                        fixture_sets.each do |fs|
         | 
| 472 523 | 
             
                          conn = fs.model_class.respond_to?(:connection) ? fs.model_class.connection : connection
         | 
| 473 | 
            -
                           | 
| 474 | 
            -
             | 
| 475 | 
            -
                          table_rows.keys.each do |table|
         | 
| 476 | 
            -
                            conn.delete "DELETE FROM #{conn.quote_table_name(table)}", 'Fixture Delete'
         | 
| 477 | 
            -
                          end
         | 
| 478 | 
            -
             | 
| 479 | 
            -
                          table_rows.each do |fixture_set_name, rows|
         | 
| 480 | 
            -
                            rows.each do |row|
         | 
| 481 | 
            -
                              conn.insert_fixture(row, fixture_set_name)
         | 
| 482 | 
            -
                            end
         | 
| 524 | 
            +
                          fs.fixture_sql(conn).each do |stmt|
         | 
| 525 | 
            +
                            conn.execute stmt
         | 
| 483 526 | 
             
                          end
         | 
| 484 527 | 
             
                        end
         | 
| 485 528 |  | 
| @@ -503,27 +546,36 @@ module ActiveRecord | |
| 503 546 | 
             
                  Zlib.crc32(label.to_s) % MAX_ID
         | 
| 504 547 | 
             
                end
         | 
| 505 548 |  | 
| 506 | 
            -
                 | 
| 549 | 
            +
                # Superclass for the evaluation contexts used by ERB fixtures.
         | 
| 550 | 
            +
                def self.context_class
         | 
| 551 | 
            +
                  @context_class ||= Class.new
         | 
| 552 | 
            +
                end
         | 
| 553 | 
            +
             | 
| 554 | 
            +
                attr_reader :table_name, :name, :fixtures, :model_class, :config
         | 
| 507 555 |  | 
| 508 | 
            -
                def initialize(connection, name, class_name, path)
         | 
| 509 | 
            -
                  @fixtures = {} # Ordered hash
         | 
| 556 | 
            +
                def initialize(connection, name, class_name, path, config = ActiveRecord::Base)
         | 
| 510 557 | 
             
                  @name     = name
         | 
| 511 558 | 
             
                  @path     = path
         | 
| 559 | 
            +
                  @config   = config
         | 
| 560 | 
            +
                  @model_class = nil
         | 
| 561 | 
            +
             | 
| 562 | 
            +
                  if class_name.is_a?(String)
         | 
| 563 | 
            +
                    ActiveSupport::Deprecation.warn("The ability to pass in strings as a class name will be removed in Rails 4.2, consider using the class itself instead.")
         | 
| 564 | 
            +
                  end
         | 
| 512 565 |  | 
| 513 566 | 
             
                  if class_name.is_a?(Class) # TODO: Should be an AR::Base type class, or any?
         | 
| 514 567 | 
             
                    @model_class = class_name
         | 
| 515 568 | 
             
                  else
         | 
| 516 | 
            -
                    @model_class = class_name. | 
| 569 | 
            +
                    @model_class = class_name.safe_constantize if class_name
         | 
| 517 570 | 
             
                  end
         | 
| 518 571 |  | 
| 519 | 
            -
                  @connection  =  | 
| 520 | 
            -
                                   model_class.connection : connection )
         | 
| 572 | 
            +
                  @connection  = connection
         | 
| 521 573 |  | 
| 522 574 | 
             
                  @table_name = ( model_class.respond_to?(:table_name) ?
         | 
| 523 575 | 
             
                                  model_class.table_name :
         | 
| 524 | 
            -
                                  self.class.default_fixture_table_name(name) )
         | 
| 576 | 
            +
                                  self.class.default_fixture_table_name(name, config) )
         | 
| 525 577 |  | 
| 526 | 
            -
                  read_fixture_files
         | 
| 578 | 
            +
                  @fixtures = read_fixture_files path, @model_class
         | 
| 527 579 | 
             
                end
         | 
| 528 580 |  | 
| 529 581 | 
             
                def [](x)
         | 
| @@ -542,10 +594,20 @@ module ActiveRecord | |
| 542 594 | 
             
                  fixtures.size
         | 
| 543 595 | 
             
                end
         | 
| 544 596 |  | 
| 597 | 
            +
                def fixture_sql(conn)
         | 
| 598 | 
            +
                  table_rows = self.table_rows
         | 
| 599 | 
            +
             | 
| 600 | 
            +
                  table_rows.keys.map { |table|
         | 
| 601 | 
            +
                    "DELETE FROM #{conn.quote_table_name(table)}"
         | 
| 602 | 
            +
                  }.concat table_rows.flat_map { |fixture_set_name, rows|
         | 
| 603 | 
            +
                    rows.map { |row| conn.fixture_sql(row, fixture_set_name) }
         | 
| 604 | 
            +
                  }
         | 
| 605 | 
            +
                end
         | 
| 606 | 
            +
             | 
| 545 607 | 
             
                # Return a hash of rows to be inserted. The key is the table, the value is
         | 
| 546 608 | 
             
                # a list of rows to insert to that table.
         | 
| 547 609 | 
             
                def table_rows
         | 
| 548 | 
            -
                  now =  | 
| 610 | 
            +
                  now = config.default_timezone == :utc ? Time.now.utc : Time.now
         | 
| 549 611 | 
             
                  now = now.to_s(:db)
         | 
| 550 612 |  | 
| 551 613 | 
             
                  # allow a standard key to be used for doing defaults in YAML
         | 
| @@ -557,7 +619,7 @@ module ActiveRecord | |
| 557 619 | 
             
                  rows[table_name] = fixtures.map do |label, fixture|
         | 
| 558 620 | 
             
                    row = fixture.to_hash
         | 
| 559 621 |  | 
| 560 | 
            -
                    if model_class | 
| 622 | 
            +
                    if model_class
         | 
| 561 623 | 
             
                      # fill in timestamp columns if they aren't specified and the model is set to record_timestamps
         | 
| 562 624 | 
             
                      if model_class.record_timestamps
         | 
| 563 625 | 
             
                        timestamp_column_names.each do |c_name|
         | 
| @@ -567,7 +629,7 @@ module ActiveRecord | |
| 567 629 |  | 
| 568 630 | 
             
                      # interpolate the fixture label
         | 
| 569 631 | 
             
                      row.each do |key, value|
         | 
| 570 | 
            -
                        row[key] = label if  | 
| 632 | 
            +
                        row[key] = label if "$LABEL" == value
         | 
| 571 633 | 
             
                      end
         | 
| 572 634 |  | 
| 573 635 | 
             
                      # generate a primary key if necessary
         | 
| @@ -597,14 +659,9 @@ module ActiveRecord | |
| 597 659 |  | 
| 598 660 | 
             
                            row[fk_name] = ActiveRecord::FixtureSet.identify(value)
         | 
| 599 661 | 
             
                          end
         | 
| 600 | 
            -
                        when : | 
| 601 | 
            -
                          if  | 
| 602 | 
            -
                             | 
| 603 | 
            -
                            table_name = association.join_table
         | 
| 604 | 
            -
                            rows[table_name].concat targets.map { |target|
         | 
| 605 | 
            -
                              { association.foreign_key             => row[primary_key_name],
         | 
| 606 | 
            -
                                association.association_foreign_key => ActiveRecord::FixtureSet.identify(target) }
         | 
| 607 | 
            -
                            }
         | 
| 662 | 
            +
                        when :has_many
         | 
| 663 | 
            +
                          if association.options[:through]
         | 
| 664 | 
            +
                            add_join_records(rows, row, HasManyThroughProxy.new(association))
         | 
| 608 665 | 
             
                          end
         | 
| 609 666 | 
             
                        end
         | 
| 610 667 | 
             
                      end
         | 
| @@ -615,11 +672,50 @@ module ActiveRecord | |
| 615 672 | 
             
                  rows
         | 
| 616 673 | 
             
                end
         | 
| 617 674 |  | 
| 675 | 
            +
                class ReflectionProxy # :nodoc:
         | 
| 676 | 
            +
                  def initialize(association)
         | 
| 677 | 
            +
                    @association = association
         | 
| 678 | 
            +
                  end
         | 
| 679 | 
            +
             | 
| 680 | 
            +
                  def join_table
         | 
| 681 | 
            +
                    @association.join_table
         | 
| 682 | 
            +
                  end
         | 
| 683 | 
            +
             | 
| 684 | 
            +
                  def name
         | 
| 685 | 
            +
                    @association.name
         | 
| 686 | 
            +
                  end
         | 
| 687 | 
            +
                end
         | 
| 688 | 
            +
             | 
| 689 | 
            +
                class HasManyThroughProxy < ReflectionProxy # :nodoc:
         | 
| 690 | 
            +
                  def rhs_key
         | 
| 691 | 
            +
                    @association.foreign_key
         | 
| 692 | 
            +
                  end
         | 
| 693 | 
            +
             | 
| 694 | 
            +
                  def lhs_key
         | 
| 695 | 
            +
                    @association.through_reflection.foreign_key
         | 
| 696 | 
            +
                  end
         | 
| 697 | 
            +
                end
         | 
| 698 | 
            +
             | 
| 618 699 | 
             
                private
         | 
| 619 700 | 
             
                  def primary_key_name
         | 
| 620 701 | 
             
                    @primary_key_name ||= model_class && model_class.primary_key
         | 
| 621 702 | 
             
                  end
         | 
| 622 703 |  | 
| 704 | 
            +
                  def add_join_records(rows, row, association)
         | 
| 705 | 
            +
                    # This is the case when the join table has no fixtures file
         | 
| 706 | 
            +
                    if (targets = row.delete(association.name.to_s))
         | 
| 707 | 
            +
                      table_name = association.join_table
         | 
| 708 | 
            +
                      lhs_key    = association.lhs_key
         | 
| 709 | 
            +
                      rhs_key    = association.rhs_key
         | 
| 710 | 
            +
             | 
| 711 | 
            +
                      targets = targets.is_a?(Array) ? targets : targets.split(/\s*,\s*/)
         | 
| 712 | 
            +
                      rows[table_name].concat targets.map { |target|
         | 
| 713 | 
            +
                        { lhs_key => row[primary_key_name],
         | 
| 714 | 
            +
                          rhs_key => ActiveRecord::FixtureSet.identify(target) }
         | 
| 715 | 
            +
                      }
         | 
| 716 | 
            +
                    end
         | 
| 717 | 
            +
                  end
         | 
| 718 | 
            +
             | 
| 623 719 | 
             
                  def has_primary_key_column?
         | 
| 624 720 | 
             
                    @has_primary_key_column ||= primary_key_name &&
         | 
| 625 721 | 
             
                      model_class.columns.any? { |c| c.name == primary_key_name }
         | 
| @@ -638,12 +734,12 @@ module ActiveRecord | |
| 638 734 | 
             
                    @column_names ||= @connection.columns(@table_name).collect { |c| c.name }
         | 
| 639 735 | 
             
                  end
         | 
| 640 736 |  | 
| 641 | 
            -
                  def read_fixture_files
         | 
| 642 | 
            -
                    yaml_files = Dir["#{ | 
| 737 | 
            +
                  def read_fixture_files(path, model_class)
         | 
| 738 | 
            +
                    yaml_files = Dir["#{path}/{**,*}/*.yml"].select { |f|
         | 
| 643 739 | 
             
                      ::File.file?(f)
         | 
| 644 | 
            -
                    } + [yaml_file_path]
         | 
| 740 | 
            +
                    } + [yaml_file_path(path)]
         | 
| 645 741 |  | 
| 646 | 
            -
                    yaml_files. | 
| 742 | 
            +
                    yaml_files.each_with_object({}) do |file, fixtures|
         | 
| 647 743 | 
             
                      FixtureSet::File.open(file) do |fh|
         | 
| 648 744 | 
             
                        fh.each do |fixture_name, row|
         | 
| 649 745 | 
             
                          fixtures[fixture_name] = ActiveRecord::Fixture.new(row, model_class)
         | 
| @@ -652,8 +748,8 @@ module ActiveRecord | |
| 652 748 | 
             
                    end
         | 
| 653 749 | 
             
                  end
         | 
| 654 750 |  | 
| 655 | 
            -
                  def yaml_file_path
         | 
| 656 | 
            -
                    "#{ | 
| 751 | 
            +
                  def yaml_file_path(path)
         | 
| 752 | 
            +
                    "#{path}.yml"
         | 
| 657 753 | 
             
                  end
         | 
| 658 754 |  | 
| 659 755 | 
             
              end
         | 
| @@ -696,7 +792,7 @@ module ActiveRecord | |
| 696 792 |  | 
| 697 793 | 
             
                def find
         | 
| 698 794 | 
             
                  if model_class
         | 
| 699 | 
            -
                    model_class. | 
| 795 | 
            +
                    model_class.find(fixture[model_class.primary_key])
         | 
| 700 796 | 
             
                  else
         | 
| 701 797 | 
             
                    raise FixtureClassNotFound, "No class attached to find."
         | 
| 702 798 | 
             
                  end
         | 
| @@ -725,14 +821,16 @@ module ActiveRecord | |
| 725 821 | 
             
                  class_attribute :use_transactional_fixtures
         | 
| 726 822 | 
             
                  class_attribute :use_instantiated_fixtures # true, false, or :no_instances
         | 
| 727 823 | 
             
                  class_attribute :pre_loaded_fixtures
         | 
| 824 | 
            +
                  class_attribute :config
         | 
| 728 825 |  | 
| 729 826 | 
             
                  self.fixture_table_names = []
         | 
| 730 827 | 
             
                  self.use_transactional_fixtures = true
         | 
| 731 828 | 
             
                  self.use_instantiated_fixtures = false
         | 
| 732 829 | 
             
                  self.pre_loaded_fixtures = false
         | 
| 830 | 
            +
                  self.config = ActiveRecord::Base
         | 
| 733 831 |  | 
| 734 832 | 
             
                  self.fixture_class_names = Hash.new do |h, fixture_set_name|
         | 
| 735 | 
            -
                    h[fixture_set_name] = ActiveRecord::FixtureSet.default_fixture_model_name(fixture_set_name)
         | 
| 833 | 
            +
                    h[fixture_set_name] = ActiveRecord::FixtureSet.default_fixture_model_name(fixture_set_name, self.config)
         | 
| 736 834 | 
             
                  end
         | 
| 737 835 | 
             
                end
         | 
| 738 836 |  | 
| @@ -745,13 +843,6 @@ module ActiveRecord | |
| 745 843 | 
             
                  #                     'namespaced/fixture' => Another::Model
         | 
| 746 844 | 
             
                  #
         | 
| 747 845 | 
             
                  # The keys must be the fixture names, that coincide with the short paths to the fixture files.
         | 
| 748 | 
            -
                  #--
         | 
| 749 | 
            -
                  # It is also possible to pass the class name instead of the class:
         | 
| 750 | 
            -
                  #   set_fixture_class 'some_fixture' => 'SomeModel'
         | 
| 751 | 
            -
                  # I think this option is redundant, i propose to deprecate it.
         | 
| 752 | 
            -
                  # Isn't it easier to always pass the class itself?
         | 
| 753 | 
            -
                  # (2011-12-20 alexeymuranov)
         | 
| 754 | 
            -
                  #++
         | 
| 755 846 | 
             
                  def set_fixture_class(class_names = {})
         | 
| 756 847 | 
             
                    self.fixture_class_names = self.fixture_class_names.merge(class_names.stringify_keys)
         | 
| 757 848 | 
             
                  end
         | 
| @@ -765,7 +856,7 @@ module ActiveRecord | |
| 765 856 | 
             
                    end
         | 
| 766 857 |  | 
| 767 858 | 
             
                    self.fixture_table_names |= fixture_set_names
         | 
| 768 | 
            -
                    require_fixture_classes(fixture_set_names)
         | 
| 859 | 
            +
                    require_fixture_classes(fixture_set_names, self.config)
         | 
| 769 860 | 
             
                    setup_fixture_accessors(fixture_set_names)
         | 
| 770 861 | 
             
                  end
         | 
| 771 862 |  | 
| @@ -780,7 +871,7 @@ module ActiveRecord | |
| 780 871 | 
             
                    end
         | 
| 781 872 | 
             
                  end
         | 
| 782 873 |  | 
| 783 | 
            -
                  def require_fixture_classes(fixture_set_names = nil)
         | 
| 874 | 
            +
                  def require_fixture_classes(fixture_set_names = nil, config = ActiveRecord::Base)
         | 
| 784 875 | 
             
                    if fixture_set_names
         | 
| 785 876 | 
             
                      fixture_set_names = fixture_set_names.map { |n| n.to_s }
         | 
| 786 877 | 
             
                    else
         | 
| @@ -788,7 +879,7 @@ module ActiveRecord | |
| 788 879 | 
             
                    end
         | 
| 789 880 |  | 
| 790 881 | 
             
                    fixture_set_names.each do |file_name|
         | 
| 791 | 
            -
                      file_name = file_name.singularize if  | 
| 882 | 
            +
                      file_name = file_name.singularize if config.pluralize_table_names
         | 
| 792 883 | 
             
                      try_to_load_dependency(file_name)
         | 
| 793 884 | 
             
                    end
         | 
| 794 885 | 
             
                  end
         | 
| @@ -840,9 +931,7 @@ module ActiveRecord | |
| 840 931 | 
             
                    !self.class.uses_transaction?(method_name)
         | 
| 841 932 | 
             
                end
         | 
| 842 933 |  | 
| 843 | 
            -
                def setup_fixtures
         | 
| 844 | 
            -
                  return if ActiveRecord::Base.configurations.blank?
         | 
| 845 | 
            -
             | 
| 934 | 
            +
                def setup_fixtures(config = ActiveRecord::Base)
         | 
| 846 935 | 
             
                  if pre_loaded_fixtures && !use_transactional_fixtures
         | 
| 847 936 | 
             
                    raise RuntimeError, 'pre_loaded_fixtures requires use_transactional_fixtures'
         | 
| 848 937 | 
             
                  end
         | 
| @@ -856,7 +945,7 @@ module ActiveRecord | |
| 856 945 | 
             
                    if @@already_loaded_fixtures[self.class]
         | 
| 857 946 | 
             
                      @loaded_fixtures = @@already_loaded_fixtures[self.class]
         | 
| 858 947 | 
             
                    else
         | 
| 859 | 
            -
                      @loaded_fixtures = load_fixtures
         | 
| 948 | 
            +
                      @loaded_fixtures = load_fixtures(config)
         | 
| 860 949 | 
             
                      @@already_loaded_fixtures[self.class] = @loaded_fixtures
         | 
| 861 950 | 
             
                    end
         | 
| 862 951 | 
             
                    @fixture_connections = enlist_fixture_connections
         | 
| @@ -867,16 +956,14 @@ module ActiveRecord | |
| 867 956 | 
             
                  else
         | 
| 868 957 | 
             
                    ActiveRecord::FixtureSet.reset_cache
         | 
| 869 958 | 
             
                    @@already_loaded_fixtures[self.class] = nil
         | 
| 870 | 
            -
                    @loaded_fixtures = load_fixtures
         | 
| 959 | 
            +
                    @loaded_fixtures = load_fixtures(config)
         | 
| 871 960 | 
             
                  end
         | 
| 872 961 |  | 
| 873 962 | 
             
                  # Instantiate fixtures for every test if requested.
         | 
| 874 | 
            -
                  instantiate_fixtures if use_instantiated_fixtures
         | 
| 963 | 
            +
                  instantiate_fixtures(config) if use_instantiated_fixtures
         | 
| 875 964 | 
             
                end
         | 
| 876 965 |  | 
| 877 966 | 
             
                def teardown_fixtures
         | 
| 878 | 
            -
                  return if ActiveRecord::Base.configurations.blank?
         | 
| 879 | 
            -
             | 
| 880 967 | 
             
                  # Rollback changes if a transaction is active.
         | 
| 881 968 | 
             
                  if run_in_transaction?
         | 
| 882 969 | 
             
                    @fixture_connections.each do |connection|
         | 
| @@ -895,19 +982,19 @@ module ActiveRecord | |
| 895 982 | 
             
                end
         | 
| 896 983 |  | 
| 897 984 | 
             
                private
         | 
| 898 | 
            -
                  def load_fixtures
         | 
| 899 | 
            -
                    fixtures = ActiveRecord::FixtureSet.create_fixtures(fixture_path, fixture_table_names, fixture_class_names)
         | 
| 985 | 
            +
                  def load_fixtures(config)
         | 
| 986 | 
            +
                    fixtures = ActiveRecord::FixtureSet.create_fixtures(fixture_path, fixture_table_names, fixture_class_names, config)
         | 
| 900 987 | 
             
                    Hash[fixtures.map { |f| [f.name, f] }]
         | 
| 901 988 | 
             
                  end
         | 
| 902 989 |  | 
| 903 990 | 
             
                  # for pre_loaded_fixtures, only require the classes once. huge speed improvement
         | 
| 904 991 | 
             
                  @@required_fixture_classes = false
         | 
| 905 992 |  | 
| 906 | 
            -
                  def instantiate_fixtures
         | 
| 993 | 
            +
                  def instantiate_fixtures(config)
         | 
| 907 994 | 
             
                    if pre_loaded_fixtures
         | 
| 908 995 | 
             
                      raise RuntimeError, 'Load fixtures before instantiating them.' if ActiveRecord::FixtureSet.all_loaded_fixtures.empty?
         | 
| 909 996 | 
             
                      unless @@required_fixture_classes
         | 
| 910 | 
            -
                        self.class.require_fixture_classes ActiveRecord::FixtureSet.all_loaded_fixtures.keys
         | 
| 997 | 
            +
                        self.class.require_fixture_classes ActiveRecord::FixtureSet.all_loaded_fixtures.keys, config
         | 
| 911 998 | 
             
                        @@required_fixture_classes = true
         | 
| 912 999 | 
             
                      end
         | 
| 913 1000 | 
             
                      ActiveRecord::FixtureSet.instantiate_all_loaded_fixtures(self, load_instances?)
         | 
| @@ -924,3 +1011,13 @@ module ActiveRecord | |
| 924 1011 | 
             
                  end
         | 
| 925 1012 | 
             
              end
         | 
| 926 1013 | 
             
            end
         | 
| 1014 | 
            +
             | 
| 1015 | 
            +
            class ActiveRecord::FixtureSet::RenderContext # :nodoc:
         | 
| 1016 | 
            +
              def self.create_subclass
         | 
| 1017 | 
            +
                Class.new ActiveRecord::FixtureSet.context_class do
         | 
| 1018 | 
            +
                  def get_binding
         | 
| 1019 | 
            +
                    binding()
         | 
| 1020 | 
            +
                  end
         | 
| 1021 | 
            +
                end
         | 
| 1022 | 
            +
              end
         | 
| 1023 | 
            +
            end
         |