diff options
Diffstat (limited to 'activerecord')
45 files changed, 538 insertions, 404 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index b9af8584ae..865d1b547a 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,15 @@ +* MySQL: set the connection collation along with the charset. + + Sets the connection collation to the database collation configured in + database.yml. Otherwise, `SET NAMES utf8mb4` will use the default + collation for that charset (utf8mb4_general_ci) when you may have chosen + a different collation, like utf8mb4_unicode_ci. + + This only applies to literal string comparisons, not column values, so it + is unlikely to affect you. + + *Jeremy Kemper* + * `default_sequence_name` from the PostgreSQL adapter returns a `String`. *Yves Senn* @@ -12,7 +24,7 @@ * Fix has_many :through relation merging failing when dynamic conditions are passed as a lambda with an arity of one. - Fixes #16128 + Fixes #16128. *Agis Anastasopoulos* @@ -27,6 +39,7 @@ will not rescue those errors anymore, and just bubble them up, as the other callbacks. This adds a opt-in flag to enable that behaviour, of not rescuing the errors. + Example: # For not swallow errors in after_commit/after_rollback callbacks. @@ -51,7 +64,7 @@ * Fix regression on after_commit that didnt fire when having nested transactions. - Fixes #16425 + Fixes #16425. *arthurnn* diff --git a/activerecord/Rakefile b/activerecord/Rakefile index b1069e5dcc..4d5178ff02 100644 --- a/activerecord/Rakefile +++ b/activerecord/Rakefile @@ -51,7 +51,7 @@ end t.libs << 'test' t.test_files = (Dir.glob( "test/cases/**/*_test.rb" ).reject { |x| x =~ /\/adapters\// - } + Dir.glob("test/cases/adapters/#{adapter_short}/**/*_test.rb")).sort + } + Dir.glob("test/cases/adapters/#{adapter_short}/**/*_test.rb")) t.warning = true t.verbose = true diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 18d4291599..18da28d480 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1604,6 +1604,21 @@ module ActiveRecord # where("default_category = ?", category.name) # } # + # === Extensions + # + # The +extension+ argument allows you to pass a block into a + # has_and_belongs_to_many association. This is useful for adding new + # finders, creators and other factory-type methods to be used as part of + # the association. + # + # Extension examples: + # has_and_belongs_to_many :contractors do + # def find_or_create_by_name(name) + # first_name, last_name = name.split(" ", 2) + # find_or_create_by(first_name: first_name, last_name: last_name) + # end + # end + # # === Options # # [:class_name] diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 84c8cfe72b..8c7b0b4be9 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -783,7 +783,7 @@ module ActiveRecord # person.pets.count # => 0 # person.pets.any? # => true # - # You can also pass a block to define criteria. The behavior + # You can also pass a +block+ to define criteria. The behavior # is the same, it returns true if the collection based on the # criteria is not empty. # @@ -817,7 +817,7 @@ module ActiveRecord # person.pets.count # => 2 # person.pets.many? # => true # - # You can also pass a block to define criteria. The + # You can also pass a +block+ to define criteria. The # behavior is the same, it returns true if the collection # based on the criteria has more than one record. # @@ -841,7 +841,7 @@ module ActiveRecord @association.many?(&block) end - # Returns +true+ if the given object is present in the collection. + # Returns +true+ if the given +record+ is present in the collection. # # class Person < ActiveRecord::Base # has_many :pets @@ -879,7 +879,7 @@ module ActiveRecord # Equivalent to <tt>Array#==</tt>. Returns +true+ if the two arrays # contain the same number of elements and if each element is equal - # to the corresponding element in the other array, otherwise returns + # to the corresponding element in the +other+ array, otherwise returns # +false+. # # class Person < ActiveRecord::Base diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb index 44c4436e95..0968b0068e 100644 --- a/activerecord/lib/active_record/associations/has_many_through_association.rb +++ b/activerecord/lib/active_record/associations/has_many_through_association.rb @@ -63,12 +63,12 @@ module ActiveRecord save_through_record(record) if has_cached_counter? && !through_reflection_updates_counter_cache? - ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc) - Automatic updating of counter caches on through associations has been - deprecated, and will be removed in Rails 5.0. Instead, please set the - appropriate counter_cache options on the has_many and belongs_to for - your associations to #{through_reflection.name}. - MESSAGE + ActiveSupport::Deprecation.warn \ + "Automatic updating of counter caches on through associations has been " \ + "deprecated, and will be removed in Rails 5.0. Instead, please set the " \ + "appropriate counter_cache options on the has_many and belongs_to for " \ + "your associations to #{through_reflection.name}." + update_counter_in_database(1) end record diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index 1ff28ceccc..ceee96b3a8 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -203,11 +203,9 @@ module ActiveRecord def column_for_attribute(name) column = columns_hash[name.to_s] if column.nil? - ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc) - `column_for_attribute` will return a null object for non-existent columns - in Rails 5.0. Use `has_attribute?` if you need to check for an - attribute's existence. - MESSAGE + ActiveSupport::Deprecation.warn \ + "`column_for_attribute` will return a null object for non-existent columns " \ + "in Rails 5.0. Use `has_attribute?` if you need to check for an attribute's existence." end column end diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb index 01f126f1b3..2f02738f6d 100644 --- a/activerecord/lib/active_record/attribute_methods/dirty.rb +++ b/activerecord/lib/active_record/attribute_methods/dirty.rb @@ -54,7 +54,19 @@ module ActiveRecord end def changed_attributes - super.reverse_merge(attributes_changed_in_place).freeze + # This should only be set by methods which will call changed_attributes + # multiple times when it is known that the computed value cannot change. + if defined?(@cached_changed_attributes) + @cached_changed_attributes + else + super.reverse_merge(attributes_changed_in_place).freeze + end + end + + def changes + cache_changed_attributes do + super + end end private @@ -157,6 +169,13 @@ module ActiveRecord store_original_raw_attribute(attr) end end + + def cache_changed_attributes + @cached_changed_attributes = changed_attributes + yield + ensure + remove_instance_variable(:@cached_changed_attributes) + end end end end diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb index 10869dfc1e..bf2a084a00 100644 --- a/activerecord/lib/active_record/attribute_methods/read.rb +++ b/activerecord/lib/active_record/attribute_methods/read.rb @@ -46,9 +46,7 @@ module ActiveRecord protected def cached_attributes_deprecation_warning(method_name) - ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc) - Calling `#{method_name}` is no longer necessary. All attributes are cached. - MESSAGE + ActiveSupport::Deprecation.warn "Calling `#{method_name}` is no longer necessary. All attributes are cached." end if Module.methods_transplantable? diff --git a/activerecord/lib/active_record/attribute_methods/serialization.rb b/activerecord/lib/active_record/attribute_methods/serialization.rb index 264ce2bdfa..100d6d4229 100644 --- a/activerecord/lib/active_record/attribute_methods/serialization.rb +++ b/activerecord/lib/active_record/attribute_methods/serialization.rb @@ -54,10 +54,9 @@ module ActiveRecord end def serialized_attributes - ActiveSupport::Deprecation.warn(<<-WARNING.strip_heredoc) - `serialized_attributes` is deprecated without replacement, and will - be removed in Rails 5.0. - WARNING + ActiveSupport::Deprecation.warn "`serialized_attributes` is deprecated " \ + "without replacement, and will be removed in Rails 5.0." + @serialized_attributes ||= Hash[ columns.select { |t| t.cast_type.is_a?(Type::Serialized) }.map { |c| [c.name, c.cast_type.coder] diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 92ac607a3c..cf0e3a260d 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -61,12 +61,11 @@ module ActiveRecord def emit_warning_if_null_unspecified(options) return if options.key?(:null) - ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc) - `timestamp` was called without specifying an option for `null`. In Rails - 5.0, this behavior will change to `null: false`. You should manually - specify `null: true` to prevent the behavior of your existing migrations - from changing. - MESSAGE + ActiveSupport::Deprecation.warn \ + "`timestamp` was called without specifying an option for `null`. In Rails " \ + "5.0, this behavior will change to `null: false`. You should manually " \ + "specify `null: true` to prevent the behavior of your existing migrations " \ + "from changing." end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index a1c370b05d..d5be8034e7 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -812,7 +812,11 @@ module ActiveRecord # NAMES does not have an equals sign, see # http://dev.mysql.com/doc/refman/5.0/en/set-statement.html#id944430 # (trailing comma because variable_assignments will always have content) - encoding = "NAMES #{@config[:encoding]}, " if @config[:encoding] + if @config[:encoding] + encoding = "NAMES #{@config[:encoding]}" + encoding << " COLLATE #{@config[:collation]}" if @config[:collation] + encoding << ", " + end # Gather up all of the SET variables... variable_assignments = variables.map do |k, v| diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb index ae967d5167..84b9490ba3 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb @@ -25,10 +25,10 @@ module ActiveRecord if !infinity?(from) && extracted[:exclude_start] if from.respond_to?(:succ) from = from.succ - ActiveSupport::Deprecation.warn <<-MESSAGE -Excluding the beginning of a Range is only partialy supported through `#succ`. -This is not reliable and will be removed in the future. - MESSAGE + ActiveSupport::Deprecation.warn \ + "Excluding the beginning of a Range is only partialy supported " \ + "through `#succ`. This is not reliable and will be removed in " \ + "the future." else raise ArgumentError, "The Ruby Range object does not support excluding the beginning of a Range. (unsupported value: '#{value}')" end diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index d22806fbdf..82b9c79533 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -151,7 +151,7 @@ module ActiveRecord end def find_by(*args) - return super if current_scope || args.length > 1 || reflect_on_all_aggregations.any? + return super if current_scope || !(Hash === args.first) || reflect_on_all_aggregations.any? hash = args.first @@ -177,6 +177,10 @@ module ActiveRecord end end + def find_by!(*args) + find_by(*args) or raise RecordNotFound + end + def initialize_generated_modules super diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index 727f12103a..a85ba6b539 100644 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -126,7 +126,7 @@ module ActiveRecord # that is included in <tt>ActiveRecord::FixtureSet.context_class</tt>. # # - define a helper method in `test_helper.rb` - # class FixtureFileHelpers + # module FixtureFileHelpers # def file_sha(path) # Digest::SHA2.hexdigest(File.read(Rails.root.join('test/fixtures', path))) # end diff --git a/activerecord/lib/active_record/gem_version.rb b/activerecord/lib/active_record/gem_version.rb index 4a7aace460..15c9dee712 100644 --- a/activerecord/lib/active_record/gem_version.rb +++ b/activerecord/lib/active_record/gem_version.rb @@ -1,5 +1,5 @@ module ActiveRecord - # Returns the version of the currently loaded ActiveRecord as a <tt>Gem::Version</tt> + # Returns the version of the currently loaded Active Record as a <tt>Gem::Version</tt> def self.gem_version Gem::Version.new VERSION::STRING end @@ -8,7 +8,7 @@ module ActiveRecord MAJOR = 4 MINOR = 2 TINY = 0 - PRE = "alpha" + PRE = "beta1" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 331b6b0698..c0deb76a33 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -339,12 +339,13 @@ module ActiveRecord return unless scope if scope.arity > 0 - ActiveSupport::Deprecation.warn <<-WARNING -The association scope '#{name}' is instance dependent (the scope block takes an argument). -Preloading happens before the individual instances are created. This means that there is no instance -being passed to the association scope. This will most likely result in broken or incorrect behavior. -Joining, Preloading and eager loading of these associations is deprecated and will be removed in the future. - WARNING + ActiveSupport::Deprecation.warn \ + "The association scope '#{name}' is instance dependent (the scope " \ + "block takes an argument). Preloading happens before the individual " \ + "instances are created. This means that there is no instance being " \ + "passed to the association scope. This will most likely result in " \ + "broken or incorrect behavior. Joining, Preloading and eager loading " \ + "of these associations is deprecated and will be removed in the future." end end alias :check_eager_loadable! :check_preloadable! @@ -787,15 +788,13 @@ Joining, Preloading and eager loading of these associations is deprecated and wi if names.length > 1 example_options = options.dup example_options[:source] = source_reflection_names.first - ActiveSupport::Deprecation.warn <<-eowarn -Ambiguous source reflection for through association. Please specify a :source -directive on your declaration like: - - class #{active_record.name} < ActiveRecord::Base - #{macro} :#{name}, #{example_options} - end - - eowarn + ActiveSupport::Deprecation.warn \ + "Ambiguous source reflection for through association. Please " \ + "specify a :source directive on your declaration like:\n" \ + "\n" \ + " class #{active_record.name} < ActiveRecord::Base\n" \ + " #{macro} :#{name}, #{example_options}\n" \ + " end" end @source_reflection_name = names.first diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 067966321d..e59cce6934 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -94,10 +94,8 @@ module ActiveRecord def check_cached_relation # :nodoc: if defined?(@arel) && @arel @arel = nil - ActiveSupport::Deprecation.warn <<-WARNING -Modifying already cached Relation. The cache will be reset. -Use a cloned Relation to prevent this warning. -WARNING + ActiveSupport::Deprecation.warn "Modifying already cached Relation. The " \ + "cache will be reset. Use a cloned Relation to prevent this warning." end end diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb index 892c78e479..331c1b7b63 100644 --- a/activerecord/lib/active_record/tasks/database_tasks.rb +++ b/activerecord/lib/active_record/tasks/database_tasks.rb @@ -131,10 +131,12 @@ module ActiveRecord verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil scope = ENV['SCOPE'] - Migration.verbose = verbose + verbose_was, Migration.verbose = Migration.verbose, verbose Migrator.migrate(Migrator.migrations_paths, version) do |migration| scope.blank? || scope == migration.scope end + ensure + Migration.verbose = verbose_was end def charset_current(environment = env) @@ -184,10 +186,10 @@ module ActiveRecord end def load_schema(format = ActiveRecord::Base.schema_format, file = nil) - ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc) - This method will act on a specific connection in the future. - To act on the current connection, use `load_schema_current` instead. - MESSAGE + ActiveSupport::Deprecation.warn \ + "This method will act on a specific connection in the future. " \ + "To act on the current connection, use `load_schema_current` instead." + load_schema_current(format, file) end diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb index 1bb7aab8fb..45bc10b9b0 100644 --- a/activerecord/lib/active_record/transactions.rb +++ b/activerecord/lib/active_record/transactions.rb @@ -3,15 +3,15 @@ module ActiveRecord module Transactions extend ActiveSupport::Concern ACTIONS = [:create, :destroy, :update] - CALLBACK_WARN_MESSAGE = <<-EOF -Currently, Active Record will rescue any errors raised within -after_rollback/after_commit callbacks and print them to the logs. In the next -version, these errors will no longer be rescued. Instead, they will simply -bubble just like other Active Record callbacks. - -You can opt into the new behavior and remove this warning by setting -config.active_record.raise_in_transactional_callbacks to true. -EOF + CALLBACK_WARN_MESSAGE = "Currently, Active Record suppresses errors raised " \ + "within `after_rollback`/`after_commit` callbacks and only print them to " \ + "the logs. In the next version, these errors will no longer be suppressed. " \ + "Instead, the errors will propagate normally just like in other Active " \ + "Record callbacks.\n" \ + "\n" \ + "You can opt into the new behavior and remove this warning by setting:\n" \ + "\n" \ + " config.active_record.raise_in_transactional_callbacks = true" included do define_callbacks :commit, :rollback, diff --git a/activerecord/lib/active_record/type/binary.rb b/activerecord/lib/active_record/type/binary.rb index d29ff4e494..005a48ef0d 100644 --- a/activerecord/lib/active_record/type/binary.rb +++ b/activerecord/lib/active_record/type/binary.rb @@ -22,6 +22,11 @@ module ActiveRecord Data.new(super) end + def changed_in_place?(raw_old_value, value) + old_value = type_cast_from_database(raw_old_value) + old_value != value + end + class Data # :nodoc: def initialize(value) @value = value.to_s @@ -30,10 +35,15 @@ module ActiveRecord def to_s @value end + alias_method :to_str, :to_s def hex @value.unpack('H*')[0] end + + def ==(other) + other == to_s || super + end end end end diff --git a/activerecord/lib/active_record/type/serialized.rb b/activerecord/lib/active_record/type/serialized.rb index abeea769c4..5b512433b0 100644 --- a/activerecord/lib/active_record/type/serialized.rb +++ b/activerecord/lib/active_record/type/serialized.rb @@ -26,6 +26,11 @@ module ActiveRecord end end + def changed_in_place?(raw_old_value, value) + return false if value.nil? + subtype.changed_in_place?(raw_old_value, coder.dump(value)) + end + def accessor ActiveRecord::Store::IndifferentHashAccessor end diff --git a/activerecord/test/cases/adapters/mysql/connection_test.rb b/activerecord/test/cases/adapters/mysql/connection_test.rb index a7b0addc1b..3dabb1104a 100644 --- a/activerecord/test/cases/adapters/mysql/connection_test.rb +++ b/activerecord/test/cases/adapters/mysql/connection_test.rb @@ -129,6 +129,11 @@ class MysqlConnectionTest < ActiveRecord::TestCase end end + def test_mysql_connection_collation_is_configured + assert_equal 'utf8_unicode_ci', @connection.show_variable('collation_connection') + assert_equal 'utf8_general_ci', ARUnit2Model.connection.show_variable('collation_connection') + end + def test_mysql_default_in_strict_mode result = @connection.exec_query "SELECT @@SESSION.sql_mode" assert_equal [["STRICT_ALL_TABLES"]], result.rows diff --git a/activerecord/test/cases/adapters/mysql/consistency_test.rb b/activerecord/test/cases/adapters/mysql/consistency_test.rb index 083d533bb2..e972d6b330 100644 --- a/activerecord/test/cases/adapters/mysql/consistency_test.rb +++ b/activerecord/test/cases/adapters/mysql/consistency_test.rb @@ -12,6 +12,7 @@ class MysqlConsistencyTest < ActiveRecord::TestCase ActiveRecord::ConnectionAdapters::MysqlAdapter.emulate_booleans = false @connection = ActiveRecord::Base.connection + @connection.clear_cache! @connection.create_table("mysql_consistency") do |t| t.boolean "a_bool" t.string "a_string" diff --git a/activerecord/test/cases/adapters/mysql2/boolean_test.rb b/activerecord/test/cases/adapters/mysql2/boolean_test.rb index f3c711a64b..03627135b2 100644 --- a/activerecord/test/cases/adapters/mysql2/boolean_test.rb +++ b/activerecord/test/cases/adapters/mysql2/boolean_test.rb @@ -9,6 +9,7 @@ class Mysql2BooleanTest < ActiveRecord::TestCase setup do @connection = ActiveRecord::Base.connection + @connection.clear_cache! @connection.create_table("mysql_booleans") do |t| t.boolean "archived" t.string "published", limit: 1 diff --git a/activerecord/test/cases/adapters/mysql2/connection_test.rb b/activerecord/test/cases/adapters/mysql2/connection_test.rb index beedb4f3a1..0b2f59b0eb 100644 --- a/activerecord/test/cases/adapters/mysql2/connection_test.rb +++ b/activerecord/test/cases/adapters/mysql2/connection_test.rb @@ -52,6 +52,11 @@ class MysqlConnectionTest < ActiveRecord::TestCase assert @connection.active? end + def test_mysql_connection_collation_is_configured + assert_equal 'utf8_unicode_ci', @connection.show_variable('collation_connection') + assert_equal 'utf8_general_ci', ARUnit2Model.connection.show_variable('collation_connection') + end + # TODO: Below is a straight up copy/paste from mysql/connection_test.rb # I'm not sure what the correct way is to share these tests between # adapters in minitest. diff --git a/activerecord/test/cases/adapters/postgresql/explain_test.rb b/activerecord/test/cases/adapters/postgresql/explain_test.rb index 416f84cb38..19053b6732 100644 --- a/activerecord/test/cases/adapters/postgresql/explain_test.rb +++ b/activerecord/test/cases/adapters/postgresql/explain_test.rb @@ -11,16 +11,13 @@ module ActiveRecord explain = Developer.where(:id => 1).explain assert_match %(EXPLAIN for: SELECT "developers".* FROM "developers" WHERE "developers"."id" = $1), explain assert_match %(QUERY PLAN), explain - assert_match %(Index Scan using developers_pkey on developers), explain end def test_explain_with_eager_loading explain = Developer.where(:id => 1).includes(:audit_logs).explain assert_match %(QUERY PLAN), explain assert_match %(EXPLAIN for: SELECT "developers".* FROM "developers" WHERE "developers"."id" = $1), explain - assert_match %(Index Scan using developers_pkey on developers), explain assert_match %(EXPLAIN for: SELECT "audit_logs".* FROM "audit_logs" WHERE "audit_logs"."developer_id" IN (1)), explain - assert_match %(Seq Scan on audit_logs), explain end end end diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index fe961e871c..1d28c8dac9 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -606,7 +606,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_transactions_when_adding_to_new_record - assert_no_queries do + assert_no_queries(ignore_none: false) do firm = Firm.new firm.clients_of_firm.concat(Client.new("name" => "Natural Company")) end @@ -621,7 +621,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_new_aliased_to_build company = companies(:first_firm) - new_client = assert_no_queries { company.clients_of_firm.new("name" => "Another Client") } + new_client = assert_no_queries(ignore_none: false) { company.clients_of_firm.new("name" => "Another Client") } assert !company.clients_of_firm.loaded? assert_equal "Another Client", new_client.name @@ -631,7 +631,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_build company = companies(:first_firm) - new_client = assert_no_queries { company.clients_of_firm.build("name" => "Another Client") } + new_client = assert_no_queries(ignore_none: false) { company.clients_of_firm.build("name" => "Another Client") } assert !company.clients_of_firm.loaded? assert_equal "Another Client", new_client.name @@ -667,7 +667,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_build_many company = companies(:first_firm) - new_clients = assert_no_queries { company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) } + new_clients = assert_no_queries(ignore_none: false) { company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) } assert_equal 2, new_clients.size end @@ -693,7 +693,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_build_via_block company = companies(:first_firm) - new_client = assert_no_queries { company.clients_of_firm.build {|client| client.name = "Another Client" } } + new_client = assert_no_queries(ignore_none: false) { company.clients_of_firm.build {|client| client.name = "Another Client" } } assert !company.clients_of_firm.loaded? assert_equal "Another Client", new_client.name @@ -703,7 +703,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_build_many_via_block company = companies(:first_firm) - new_clients = assert_no_queries do + new_clients = assert_no_queries(ignore_none: false) do company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) do |client| client.name = "changed" end @@ -928,7 +928,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_transaction_when_deleting_new_record - assert_no_queries do + assert_no_queries(ignore_none: false) do firm = Firm.new client = Client.new("name" => "New Client") firm.clients_of_firm << client @@ -1349,7 +1349,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end def test_transactions_when_replacing_on_new_record - assert_no_queries do + assert_no_queries(ignore_none: false) do firm = Firm.new firm.clients_of_firm = [Client.new("name" => "New Client")] end @@ -1487,7 +1487,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase firm.clients.load_target assert firm.clients.loaded? - assert_no_queries do + assert_no_queries(ignore_none: false) do firm.clients.first assert_equal 2, firm.clients.first(2).size firm.clients.last @@ -1835,7 +1835,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase test "has many associations on new records use null relations" do post = Post.new - assert_no_queries do + assert_no_queries(ignore_none: false) do assert_equal [], post.comments assert_equal [], post.comments.where(body: 'omg') assert_equal [], post.comments.pluck(:body) diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb index a85e020f0c..d9659a72c5 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -1095,7 +1095,7 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase def test_has_many_through_associations_on_new_records_use_null_relations person = Person.new - assert_no_queries do + assert_no_queries(ignore_none: false) do assert_equal [], person.posts assert_equal [], person.posts.where(body: 'omg') assert_equal [], person.posts.pluck(:body) diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb index a4650ccdf2..d412b3168e 100644 --- a/activerecord/test/cases/associations/has_one_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_associations_test.rb @@ -200,7 +200,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase end def test_build_association_dont_create_transaction - assert_no_queries { + assert_no_queries(ignore_none: false) { Firm.new.build_account } end diff --git a/activerecord/test/cases/attribute_decorators_test.rb b/activerecord/test/cases/attribute_decorators_test.rb index cbc2c4e5d7..32977b805f 100644 --- a/activerecord/test/cases/attribute_decorators_test.rb +++ b/activerecord/test/cases/attribute_decorators_test.rb @@ -44,6 +44,7 @@ module ActiveRecord end test "decoration does not eagerly load existing columns" do + Model.reset_column_information assert_no_queries do Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) } end diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb index 09892d50ba..025cdbeba9 100644 --- a/activerecord/test/cases/autosave_association_test.rb +++ b/activerecord/test/cases/autosave_association_test.rb @@ -499,7 +499,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa def test_build_before_save company = companies(:first_firm) - new_client = assert_no_queries { company.clients_of_firm.build("name" => "Another Client") } + new_client = assert_no_queries(ignore_none: false) { company.clients_of_firm.build("name" => "Another Client") } assert !company.clients_of_firm.loaded? company.name += '-changed' @@ -510,7 +510,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa def test_build_many_before_save company = companies(:first_firm) - assert_no_queries { company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) } + assert_no_queries(ignore_none: false) { company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) } company.name += '-changed' assert_queries(3) { assert company.save } @@ -519,7 +519,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa def test_build_via_block_before_save company = companies(:first_firm) - new_client = assert_no_queries { company.clients_of_firm.build {|client| client.name = "Another Client" } } + new_client = assert_no_queries(ignore_none: false) { company.clients_of_firm.build {|client| client.name = "Another Client" } } assert !company.clients_of_firm.loaded? company.name += '-changed' @@ -530,7 +530,7 @@ class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCa def test_build_many_via_block_before_save company = companies(:first_firm) - assert_no_queries do + assert_no_queries(ignore_none: false) do company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) do |client| client.name = "changed" end diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 4c0b0c868a..fb535e74fc 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1540,20 +1540,6 @@ class BasicsTest < ActiveRecord::TestCase assert_equal "", Company.new.description end - ["find_by", "find_by!"].each do |meth| - test "#{meth} delegates to scoped" do - record = stub - - scope = mock - scope.expects(meth).with(:foo, :bar).returns(record) - - klass = Class.new(ActiveRecord::Base) - klass.stubs(:all => scope) - - assert_equal record, klass.public_send(meth, :foo, :bar) - end - end - test "scoped can take a values hash" do klass = Class.new(ActiveRecord::Base) assert_equal ['foo'], klass.all.merge!(select: 'foo').select_values diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index 319ea9260a..ec6a319ab5 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -11,8 +11,6 @@ require 'models/minivan' require 'models/speedometer' require 'models/ship_part' -Company.has_many :accounts - class NumericData < ActiveRecord::Base self.table_name = 'numeric_data' @@ -22,7 +20,7 @@ class NumericData < ActiveRecord::Base end class CalculationsTest < ActiveRecord::TestCase - fixtures :companies, :accounts, :topics + fixtures :companies, :accounts, :topics, :speedometers, :minivans def test_should_sum_field assert_equal 318, Account.sum(:credit_limit) diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index 0c77eedb52..eb9b1a2d74 100644 --- a/activerecord/test/cases/dirty_test.rb +++ b/activerecord/test/cases/dirty_test.rb @@ -682,6 +682,22 @@ class DirtyTest < ActiveRecord::TestCase assert_not pirate.changed? end + test "in place mutation for binary" do + klass = Class.new(ActiveRecord::Base) do + self.table_name = :binaries + serialize :data + end + + klass.create!(data: "foo") + binary = klass.last + + assert_not binary.changed? + + binary.data << "bar" + + assert binary.changed? + end + private def with_partial_writes(klass, on = true) old = klass.partial_writes? diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index b42a60fea5..befbec4e1b 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -1027,6 +1027,48 @@ class FinderTest < ActiveRecord::TestCase assert_nothing_raised(ActiveRecord::StatementInvalid) { Topic.offset("3").to_a } end + test "find_by with hash conditions returns the first matching record" do + assert_equal posts(:eager_other), Post.find_by(id: posts(:eager_other).id) + end + + test "find_by with non-hash conditions returns the first matching record" do + assert_equal posts(:eager_other), Post.find_by("id = #{posts(:eager_other).id}") + end + + test "find_by with multi-arg conditions returns the first matching record" do + assert_equal posts(:eager_other), Post.find_by('id = ?', posts(:eager_other).id) + end + + test "find_by returns nil if the record is missing" do + assert_equal nil, Post.find_by("1 = 0") + end + + test "find_by doesn't have implicit ordering" do + assert_sql(/^((?!ORDER).)*$/) { Post.find_by(id: posts(:eager_other).id) } + end + + test "find_by! with hash conditions returns the first matching record" do + assert_equal posts(:eager_other), Post.find_by!(id: posts(:eager_other).id) + end + + test "find_by! with non-hash conditions returns the first matching record" do + assert_equal posts(:eager_other), Post.find_by!("id = #{posts(:eager_other).id}") + end + + test "find_by! with multi-arg conditions returns the first matching record" do + assert_equal posts(:eager_other), Post.find_by!('id = ?', posts(:eager_other).id) + end + + test "find_by! doesn't have implicit ordering" do + assert_sql(/^((?!ORDER).)*$/) { Post.find_by!(id: posts(:eager_other).id) } + end + + test "find_by! raises RecordNotFound if the record is missing" do + assert_raises(ActiveRecord::RecordNotFound) do + Post.find_by!("1 = 0") + end + end + protected def bind(statement, *vars) if vars.first.is_a?(Hash) diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb index d7bbe0df62..385ec48005 100644 --- a/activerecord/test/cases/fixtures_test.rb +++ b/activerecord/test/cases/fixtures_test.rb @@ -644,6 +644,7 @@ class LoadAllFixturesWithPathnameTest < ActiveRecord::TestCase end class FasterFixturesTest < ActiveRecord::TestCase + self.use_transactional_fixtures = false fixtures :categories, :authors def load_extra_fixture(name) diff --git a/activerecord/test/cases/invertible_migration_test.rb b/activerecord/test/cases/invertible_migration_test.rb index 285172d33e..8144f3e5c5 100644 --- a/activerecord/test/cases/invertible_migration_test.rb +++ b/activerecord/test/cases/invertible_migration_test.rb @@ -122,12 +122,17 @@ module ActiveRecord end end + setup do + @verbose_was, ActiveRecord::Migration.verbose = ActiveRecord::Migration.verbose, false + end + teardown do %w[horses new_horses].each do |table| if ActiveRecord::Base.connection.table_exists?(table) ActiveRecord::Base.connection.drop_table(table) end end + ActiveRecord::Migration.verbose = @verbose_was end def test_no_reverse diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb index 0c9dff2c25..713999df84 100644 --- a/activerecord/test/cases/locking_test.rb +++ b/activerecord/test/cases/locking_test.rb @@ -335,6 +335,8 @@ class OptimisticLockingWithSchemaChangeTest < ActiveRecord::TestCase assert_raises(ActiveRecord::RecordNotFound) { LegacyThing.find(t.id) } ensure remove_counter_column_from(Person, 'legacy_things_count') + LegacyThing.connection.remove_column LegacyThing.table_name, 'person_id' + LegacyThing.reset_column_information end private diff --git a/activerecord/test/cases/migration/helper.rb b/activerecord/test/cases/migration/helper.rb index 4dad77e8fd..5bc0898f33 100644 --- a/activerecord/test/cases/migration/helper.rb +++ b/activerecord/test/cases/migration/helper.rb @@ -5,10 +5,6 @@ module ActiveRecord class << self; attr_accessor :message_count; end self.message_count = 0 - def puts(text="") - ActiveRecord::Migration.message_count += 1 - end - module TestHelper attr_reader :connection, :table_name diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index 034a0f567e..633077622c 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -34,8 +34,7 @@ class MigrationTest < ActiveRecord::TestCase Reminder.connection.drop_table(table) rescue nil end Reminder.reset_column_information - ActiveRecord::Migration.verbose = true - ActiveRecord::Migration.message_count = 0 + @verbose_was, ActiveRecord::Migration.verbose = ActiveRecord::Migration.verbose, false ActiveRecord::Base.connection.schema_cache.clear! end @@ -65,6 +64,8 @@ class MigrationTest < ActiveRecord::TestCase Person.connection.remove_column("people", "middle_name") rescue nil Person.connection.add_column("people", "first_name", :string) Person.reset_column_information + + ActiveRecord::Migration.verbose = @verbose_was end def test_migrator_versions diff --git a/activerecord/test/cases/migrator_test.rb b/activerecord/test/cases/migrator_test.rb index 9568aa2217..9809d83315 100644 --- a/activerecord/test/cases/migrator_test.rb +++ b/activerecord/test/cases/migrator_test.rb @@ -1,377 +1,388 @@ require "cases/helper" require "cases/migration/helper" -module ActiveRecord - class MigratorTest < ActiveRecord::TestCase - self.use_transactional_fixtures = false +class MigratorTest < ActiveRecord::TestCase + self.use_transactional_fixtures = false - # Use this class to sense if migrations have gone - # up or down. - class Sensor < ActiveRecord::Migration - attr_reader :went_up, :went_down + # Use this class to sense if migrations have gone + # up or down. + class Sensor < ActiveRecord::Migration + attr_reader :went_up, :went_down - def initialize name = self.class.name, version = nil - super - @went_up = false - @went_down = false - end - - def up; @went_up = true; end - def down; @went_down = true; end - end - - def setup + def initialize name = self.class.name, version = nil super - ActiveRecord::SchemaMigration.create_table - ActiveRecord::SchemaMigration.delete_all rescue nil + @went_up = false + @went_down = false end - teardown do - ActiveRecord::SchemaMigration.delete_all rescue nil - ActiveRecord::Migration.verbose = true - end + def up; @went_up = true; end + def down; @went_down = true; end + end - def test_migrator_with_duplicate_names - assert_raises(ActiveRecord::DuplicateMigrationNameError, "Multiple migrations have the name Chunky") do - list = [Migration.new('Chunky'), Migration.new('Chunky')] - ActiveRecord::Migrator.new(:up, list) + def setup + super + ActiveRecord::SchemaMigration.create_table + ActiveRecord::SchemaMigration.delete_all rescue nil + @verbose_was = ActiveRecord::Migration.verbose + ActiveRecord::Migration.message_count = 0 + ActiveRecord::Migration.class_eval do + undef :puts + def puts(*) + ActiveRecord::Migration.message_count += 1 end end + end - def test_migrator_with_duplicate_versions - assert_raises(ActiveRecord::DuplicateMigrationVersionError) do - list = [Migration.new('Foo', 1), Migration.new('Bar', 1)] - ActiveRecord::Migrator.new(:up, list) + teardown do + ActiveRecord::SchemaMigration.delete_all rescue nil + ActiveRecord::Migration.verbose = @verbose_was + ActiveRecord::Migration.class_eval do + undef :puts + def puts(*) + super end end + end - def test_migrator_with_missing_version_numbers - assert_raises(ActiveRecord::UnknownMigrationVersionError) do - list = [Migration.new('Foo', 1), Migration.new('Bar', 2)] - ActiveRecord::Migrator.new(:up, list, 3).run - end + def test_migrator_with_duplicate_names + assert_raises(ActiveRecord::DuplicateMigrationNameError, "Multiple migrations have the name Chunky") do + list = [ActiveRecord::Migration.new('Chunky'), ActiveRecord::Migration.new('Chunky')] + ActiveRecord::Migrator.new(:up, list) end + end - def test_finds_migrations - migrations = ActiveRecord::Migrator.migrations(MIGRATIONS_ROOT + "/valid") + def test_migrator_with_duplicate_versions + assert_raises(ActiveRecord::DuplicateMigrationVersionError) do + list = [ActiveRecord::Migration.new('Foo', 1), ActiveRecord::Migration.new('Bar', 1)] + ActiveRecord::Migrator.new(:up, list) + end + end - [[1, 'ValidPeopleHaveLastNames'], [2, 'WeNeedReminders'], [3, 'InnocentJointable']].each_with_index do |pair, i| - assert_equal migrations[i].version, pair.first - assert_equal migrations[i].name, pair.last - end + def test_migrator_with_missing_version_numbers + assert_raises(ActiveRecord::UnknownMigrationVersionError) do + list = [ActiveRecord::Migration.new('Foo', 1), ActiveRecord::Migration.new('Bar', 2)] + ActiveRecord::Migrator.new(:up, list, 3).run end + end - def test_finds_migrations_in_subdirectories - migrations = ActiveRecord::Migrator.migrations(MIGRATIONS_ROOT + "/valid_with_subdirectories") + def test_finds_migrations + migrations = ActiveRecord::Migrator.migrations(MIGRATIONS_ROOT + "/valid") - [[1, 'ValidPeopleHaveLastNames'], [2, 'WeNeedReminders'], [3, 'InnocentJointable']].each_with_index do |pair, i| - assert_equal migrations[i].version, pair.first - assert_equal migrations[i].name, pair.last - end + [[1, 'ValidPeopleHaveLastNames'], [2, 'WeNeedReminders'], [3, 'InnocentJointable']].each_with_index do |pair, i| + assert_equal migrations[i].version, pair.first + assert_equal migrations[i].name, pair.last end + end - def test_finds_migrations_from_two_directories - directories = [MIGRATIONS_ROOT + '/valid_with_timestamps', MIGRATIONS_ROOT + '/to_copy_with_timestamps'] - migrations = ActiveRecord::Migrator.migrations directories - - [[20090101010101, "PeopleHaveHobbies"], - [20090101010202, "PeopleHaveDescriptions"], - [20100101010101, "ValidWithTimestampsPeopleHaveLastNames"], - [20100201010101, "ValidWithTimestampsWeNeedReminders"], - [20100301010101, "ValidWithTimestampsInnocentJointable"]].each_with_index do |pair, i| - assert_equal pair.first, migrations[i].version - assert_equal pair.last, migrations[i].name - end - end + def test_finds_migrations_in_subdirectories + migrations = ActiveRecord::Migrator.migrations(MIGRATIONS_ROOT + "/valid_with_subdirectories") - def test_finds_migrations_in_numbered_directory - migrations = ActiveRecord::Migrator.migrations [MIGRATIONS_ROOT + '/10_urban'] - assert_equal 9, migrations[0].version - assert_equal 'AddExpressions', migrations[0].name + [[1, 'ValidPeopleHaveLastNames'], [2, 'WeNeedReminders'], [3, 'InnocentJointable']].each_with_index do |pair, i| + assert_equal migrations[i].version, pair.first + assert_equal migrations[i].name, pair.last end + end - def test_relative_migrations - list = Dir.chdir(MIGRATIONS_ROOT) do - ActiveRecord::Migrator.migrations("valid") - end + def test_finds_migrations_from_two_directories + directories = [MIGRATIONS_ROOT + '/valid_with_timestamps', MIGRATIONS_ROOT + '/to_copy_with_timestamps'] + migrations = ActiveRecord::Migrator.migrations directories + + [[20090101010101, "PeopleHaveHobbies"], + [20090101010202, "PeopleHaveDescriptions"], + [20100101010101, "ValidWithTimestampsPeopleHaveLastNames"], + [20100201010101, "ValidWithTimestampsWeNeedReminders"], + [20100301010101, "ValidWithTimestampsInnocentJointable"]].each_with_index do |pair, i| + assert_equal pair.first, migrations[i].version + assert_equal pair.last, migrations[i].name + end + end - migration_proxy = list.find { |item| - item.name == 'ValidPeopleHaveLastNames' - } - assert migration_proxy, 'should find pending migration' + def test_finds_migrations_in_numbered_directory + migrations = ActiveRecord::Migrator.migrations [MIGRATIONS_ROOT + '/10_urban'] + assert_equal 9, migrations[0].version + assert_equal 'AddExpressions', migrations[0].name + end + + def test_relative_migrations + list = Dir.chdir(MIGRATIONS_ROOT) do + ActiveRecord::Migrator.migrations("valid") end - def test_finds_pending_migrations - ActiveRecord::SchemaMigration.create!(:version => '1') - migration_list = [ Migration.new('foo', 1), Migration.new('bar', 3) ] - migrations = ActiveRecord::Migrator.new(:up, migration_list).pending_migrations + migration_proxy = list.find { |item| + item.name == 'ValidPeopleHaveLastNames' + } + assert migration_proxy, 'should find pending migration' + end - assert_equal 1, migrations.size - assert_equal migration_list.last, migrations.first - end + def test_finds_pending_migrations + ActiveRecord::SchemaMigration.create!(:version => '1') + migration_list = [ActiveRecord::Migration.new('foo', 1), ActiveRecord::Migration.new('bar', 3)] + migrations = ActiveRecord::Migrator.new(:up, migration_list).pending_migrations - def test_migrator_interleaved_migrations - pass_one = [Sensor.new('One', 1)] + assert_equal 1, migrations.size + assert_equal migration_list.last, migrations.first + end - ActiveRecord::Migrator.new(:up, pass_one).migrate - assert pass_one.first.went_up - assert_not pass_one.first.went_down + def test_migrator_interleaved_migrations + pass_one = [Sensor.new('One', 1)] - pass_two = [Sensor.new('One', 1), Sensor.new('Three', 3)] - ActiveRecord::Migrator.new(:up, pass_two).migrate - assert_not pass_two[0].went_up - assert pass_two[1].went_up - assert pass_two.all? { |x| !x.went_down } + ActiveRecord::Migrator.new(:up, pass_one).migrate + assert pass_one.first.went_up + assert_not pass_one.first.went_down - pass_three = [Sensor.new('One', 1), - Sensor.new('Two', 2), - Sensor.new('Three', 3)] + pass_two = [Sensor.new('One', 1), Sensor.new('Three', 3)] + ActiveRecord::Migrator.new(:up, pass_two).migrate + assert_not pass_two[0].went_up + assert pass_two[1].went_up + assert pass_two.all? { |x| !x.went_down } - ActiveRecord::Migrator.new(:down, pass_three).migrate - assert pass_three[0].went_down - assert_not pass_three[1].went_down - assert pass_three[2].went_down - end + pass_three = [Sensor.new('One', 1), + Sensor.new('Two', 2), + Sensor.new('Three', 3)] - def test_up_calls_up - migrations = [Sensor.new(nil, 0), Sensor.new(nil, 1), Sensor.new(nil, 2)] - ActiveRecord::Migrator.new(:up, migrations).migrate - assert migrations.all? { |m| m.went_up } - assert migrations.all? { |m| !m.went_down } - assert_equal 2, ActiveRecord::Migrator.current_version - end + ActiveRecord::Migrator.new(:down, pass_three).migrate + assert pass_three[0].went_down + assert_not pass_three[1].went_down + assert pass_three[2].went_down + end - def test_down_calls_down - test_up_calls_up + def test_up_calls_up + migrations = [Sensor.new(nil, 0), Sensor.new(nil, 1), Sensor.new(nil, 2)] + ActiveRecord::Migrator.new(:up, migrations).migrate + assert migrations.all? { |m| m.went_up } + assert migrations.all? { |m| !m.went_down } + assert_equal 2, ActiveRecord::Migrator.current_version + end - migrations = [Sensor.new(nil, 0), Sensor.new(nil, 1), Sensor.new(nil, 2)] - ActiveRecord::Migrator.new(:down, migrations).migrate - assert migrations.all? { |m| !m.went_up } - assert migrations.all? { |m| m.went_down } - assert_equal 0, ActiveRecord::Migrator.current_version - end + def test_down_calls_down + test_up_calls_up - def test_current_version - ActiveRecord::SchemaMigration.create!(:version => '1000') - assert_equal 1000, ActiveRecord::Migrator.current_version - end + migrations = [Sensor.new(nil, 0), Sensor.new(nil, 1), Sensor.new(nil, 2)] + ActiveRecord::Migrator.new(:down, migrations).migrate + assert migrations.all? { |m| !m.went_up } + assert migrations.all? { |m| m.went_down } + assert_equal 0, ActiveRecord::Migrator.current_version + end - def test_migrator_one_up - calls, migrations = sensors(3) + def test_current_version + ActiveRecord::SchemaMigration.create!(:version => '1000') + assert_equal 1000, ActiveRecord::Migrator.current_version + end - ActiveRecord::Migrator.new(:up, migrations, 1).migrate - assert_equal [[:up, 1]], calls - calls.clear + def test_migrator_one_up + calls, migrations = sensors(3) - ActiveRecord::Migrator.new(:up, migrations, 2).migrate - assert_equal [[:up, 2]], calls - end + ActiveRecord::Migrator.new(:up, migrations, 1).migrate + assert_equal [[:up, 1]], calls + calls.clear - def test_migrator_one_down - calls, migrations = sensors(3) + ActiveRecord::Migrator.new(:up, migrations, 2).migrate + assert_equal [[:up, 2]], calls + end - ActiveRecord::Migrator.new(:up, migrations).migrate - assert_equal [[:up, 1], [:up, 2], [:up, 3]], calls - calls.clear + def test_migrator_one_down + calls, migrations = sensors(3) - ActiveRecord::Migrator.new(:down, migrations, 1).migrate + ActiveRecord::Migrator.new(:up, migrations).migrate + assert_equal [[:up, 1], [:up, 2], [:up, 3]], calls + calls.clear - assert_equal [[:down, 3], [:down, 2]], calls - end + ActiveRecord::Migrator.new(:down, migrations, 1).migrate - def test_migrator_one_up_one_down - calls, migrations = sensors(3) + assert_equal [[:down, 3], [:down, 2]], calls + end - ActiveRecord::Migrator.new(:up, migrations, 1).migrate - assert_equal [[:up, 1]], calls - calls.clear + def test_migrator_one_up_one_down + calls, migrations = sensors(3) - ActiveRecord::Migrator.new(:down, migrations, 0).migrate - assert_equal [[:down, 1]], calls - end + ActiveRecord::Migrator.new(:up, migrations, 1).migrate + assert_equal [[:up, 1]], calls + calls.clear - def test_migrator_double_up - calls, migrations = sensors(3) - assert_equal(0, ActiveRecord::Migrator.current_version) + ActiveRecord::Migrator.new(:down, migrations, 0).migrate + assert_equal [[:down, 1]], calls + end - ActiveRecord::Migrator.new(:up, migrations, 1).migrate - assert_equal [[:up, 1]], calls - calls.clear + def test_migrator_double_up + calls, migrations = sensors(3) + assert_equal(0, ActiveRecord::Migrator.current_version) - ActiveRecord::Migrator.new(:up, migrations, 1).migrate - assert_equal [], calls - end + ActiveRecord::Migrator.new(:up, migrations, 1).migrate + assert_equal [[:up, 1]], calls + calls.clear - def test_migrator_double_down - calls, migrations = sensors(3) + ActiveRecord::Migrator.new(:up, migrations, 1).migrate + assert_equal [], calls + end - assert_equal(0, ActiveRecord::Migrator.current_version) + def test_migrator_double_down + calls, migrations = sensors(3) - ActiveRecord::Migrator.new(:up, migrations, 1).run - assert_equal [[:up, 1]], calls - calls.clear + assert_equal(0, ActiveRecord::Migrator.current_version) - ActiveRecord::Migrator.new(:down, migrations, 1).run - assert_equal [[:down, 1]], calls - calls.clear + ActiveRecord::Migrator.new(:up, migrations, 1).run + assert_equal [[:up, 1]], calls + calls.clear - ActiveRecord::Migrator.new(:down, migrations, 1).run - assert_equal [], calls + ActiveRecord::Migrator.new(:down, migrations, 1).run + assert_equal [[:down, 1]], calls + calls.clear - assert_equal(0, ActiveRecord::Migrator.current_version) - end + ActiveRecord::Migrator.new(:down, migrations, 1).run + assert_equal [], calls - def test_migrator_verbosity - _, migrations = sensors(3) + assert_equal(0, ActiveRecord::Migrator.current_version) + end - ActiveRecord::Migrator.new(:up, migrations, 1).migrate - assert_not_equal 0, ActiveRecord::Migration.message_count + def test_migrator_verbosity + _, migrations = sensors(3) - ActiveRecord::Migration.message_count = 0 + ActiveRecord::Migrator.new(:up, migrations, 1).migrate + assert_not_equal 0, ActiveRecord::Migration.message_count - ActiveRecord::Migrator.new(:down, migrations, 0).migrate - assert_not_equal 0, ActiveRecord::Migration.message_count - ActiveRecord::Migration.message_count = 0 - end + ActiveRecord::Migration.message_count = 0 - def test_migrator_verbosity_off - _, migrations = sensors(3) + ActiveRecord::Migrator.new(:down, migrations, 0).migrate + assert_not_equal 0, ActiveRecord::Migration.message_count + end - ActiveRecord::Migration.message_count = 0 - ActiveRecord::Migration.verbose = false - ActiveRecord::Migrator.new(:up, migrations, 1).migrate - assert_equal 0, ActiveRecord::Migration.message_count - ActiveRecord::Migrator.new(:down, migrations, 0).migrate - assert_equal 0, ActiveRecord::Migration.message_count - end + def test_migrator_verbosity_off + _, migrations = sensors(3) - def test_target_version_zero_should_run_only_once - calls, migrations = sensors(3) + ActiveRecord::Migration.message_count = 0 + ActiveRecord::Migration.verbose = false + ActiveRecord::Migrator.new(:up, migrations, 1).migrate + assert_equal 0, ActiveRecord::Migration.message_count + ActiveRecord::Migrator.new(:down, migrations, 0).migrate + assert_equal 0, ActiveRecord::Migration.message_count + end - # migrate up to 1 - ActiveRecord::Migrator.new(:up, migrations, 1).migrate - assert_equal [[:up, 1]], calls - calls.clear + def test_target_version_zero_should_run_only_once + calls, migrations = sensors(3) - # migrate down to 0 - ActiveRecord::Migrator.new(:down, migrations, 0).migrate - assert_equal [[:down, 1]], calls - calls.clear + # migrate up to 1 + ActiveRecord::Migrator.new(:up, migrations, 1).migrate + assert_equal [[:up, 1]], calls + calls.clear - # migrate down to 0 again - ActiveRecord::Migrator.new(:down, migrations, 0).migrate - assert_equal [], calls - end + # migrate down to 0 + ActiveRecord::Migrator.new(:down, migrations, 0).migrate + assert_equal [[:down, 1]], calls + calls.clear - def test_migrator_going_down_due_to_version_target - calls, migrator = migrator_class(3) + # migrate down to 0 again + ActiveRecord::Migrator.new(:down, migrations, 0).migrate + assert_equal [], calls + end - migrator.up("valid", 1) - assert_equal [[:up, 1]], calls - calls.clear + def test_migrator_going_down_due_to_version_target + calls, migrator = migrator_class(3) - migrator.migrate("valid", 0) - assert_equal [[:down, 1]], calls - calls.clear + migrator.up("valid", 1) + assert_equal [[:up, 1]], calls + calls.clear - migrator.migrate("valid") - assert_equal [[:up, 1], [:up, 2], [:up, 3]], calls - end + migrator.migrate("valid", 0) + assert_equal [[:down, 1]], calls + calls.clear - def test_migrator_rollback - _, migrator = migrator_class(3) + migrator.migrate("valid") + assert_equal [[:up, 1], [:up, 2], [:up, 3]], calls + end - migrator.migrate("valid") - assert_equal(3, ActiveRecord::Migrator.current_version) + def test_migrator_rollback + _, migrator = migrator_class(3) - migrator.rollback("valid") - assert_equal(2, ActiveRecord::Migrator.current_version) + migrator.migrate("valid") + assert_equal(3, ActiveRecord::Migrator.current_version) - migrator.rollback("valid") - assert_equal(1, ActiveRecord::Migrator.current_version) + migrator.rollback("valid") + assert_equal(2, ActiveRecord::Migrator.current_version) - migrator.rollback("valid") - assert_equal(0, ActiveRecord::Migrator.current_version) + migrator.rollback("valid") + assert_equal(1, ActiveRecord::Migrator.current_version) - migrator.rollback("valid") - assert_equal(0, ActiveRecord::Migrator.current_version) - end + migrator.rollback("valid") + assert_equal(0, ActiveRecord::Migrator.current_version) - def test_migrator_db_has_no_schema_migrations_table - _, migrator = migrator_class(3) + migrator.rollback("valid") + assert_equal(0, ActiveRecord::Migrator.current_version) + end - ActiveRecord::Base.connection.execute("DROP TABLE schema_migrations") - assert_not ActiveRecord::Base.connection.table_exists?('schema_migrations') - migrator.migrate("valid", 1) - assert ActiveRecord::Base.connection.table_exists?('schema_migrations') - end + def test_migrator_db_has_no_schema_migrations_table + _, migrator = migrator_class(3) - def test_migrator_forward - _, migrator = migrator_class(3) - migrator.migrate("/valid", 1) - assert_equal(1, ActiveRecord::Migrator.current_version) + ActiveRecord::Base.connection.execute("DROP TABLE schema_migrations") + assert_not ActiveRecord::Base.connection.table_exists?('schema_migrations') + migrator.migrate("valid", 1) + assert ActiveRecord::Base.connection.table_exists?('schema_migrations') + end - migrator.forward("/valid", 2) - assert_equal(3, ActiveRecord::Migrator.current_version) + def test_migrator_forward + _, migrator = migrator_class(3) + migrator.migrate("/valid", 1) + assert_equal(1, ActiveRecord::Migrator.current_version) - migrator.forward("/valid") - assert_equal(3, ActiveRecord::Migrator.current_version) - end + migrator.forward("/valid", 2) + assert_equal(3, ActiveRecord::Migrator.current_version) - def test_only_loads_pending_migrations - # migrate up to 1 - ActiveRecord::SchemaMigration.create!(:version => '1') + migrator.forward("/valid") + assert_equal(3, ActiveRecord::Migrator.current_version) + end - calls, migrator = migrator_class(3) - migrator.migrate("valid", nil) + def test_only_loads_pending_migrations + # migrate up to 1 + ActiveRecord::SchemaMigration.create!(:version => '1') - assert_equal [[:up, 2], [:up, 3]], calls - end + calls, migrator = migrator_class(3) + migrator.migrate("valid", nil) - def test_get_all_versions - _, migrator = migrator_class(3) + assert_equal [[:up, 2], [:up, 3]], calls + end - migrator.migrate("valid") - assert_equal([1,2,3], ActiveRecord::Migrator.get_all_versions) + def test_get_all_versions + _, migrator = migrator_class(3) - migrator.rollback("valid") - assert_equal([1,2], ActiveRecord::Migrator.get_all_versions) + migrator.migrate("valid") + assert_equal([1,2,3], ActiveRecord::Migrator.get_all_versions) - migrator.rollback("valid") - assert_equal([1], ActiveRecord::Migrator.get_all_versions) + migrator.rollback("valid") + assert_equal([1,2], ActiveRecord::Migrator.get_all_versions) - migrator.rollback("valid") - assert_equal([], ActiveRecord::Migrator.get_all_versions) - end + migrator.rollback("valid") + assert_equal([1], ActiveRecord::Migrator.get_all_versions) - private - def m(name, version, &block) - x = Sensor.new name, version - x.extend(Module.new { - define_method(:up) { block.call(:up, x); super() } - define_method(:down) { block.call(:down, x); super() } - }) if block_given? - end + migrator.rollback("valid") + assert_equal([], ActiveRecord::Migrator.get_all_versions) + end + + private + def m(name, version, &block) + x = Sensor.new name, version + x.extend(Module.new { + define_method(:up) { block.call(:up, x); super() } + define_method(:down) { block.call(:down, x); super() } + }) if block_given? + end - def sensors(count) - calls = [] - migrations = count.times.map { |i| - m(nil, i + 1) { |c,migration| - calls << [c, migration.version] - } + def sensors(count) + calls = [] + migrations = count.times.map { |i| + m(nil, i + 1) { |c,migration| + calls << [c, migration.version] } - [calls, migrations] - end + } + [calls, migrations] + end - def migrator_class(count) - calls, migrations = sensors(count) + def migrator_class(count) + calls, migrations = sensors(count) - migrator = Class.new(Migrator).extend(Module.new { - define_method(:migrations) { |paths| - migrations - } - }) - [calls, migrator] - end + migrator = Class.new(ActiveRecord::Migrator).extend(Module.new { + define_method(:migrations) { |paths| + migrations + } + }) + [calls, migrator] end end diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 88df997a2f..7163697a68 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -311,26 +311,26 @@ class RelationTest < ActiveRecord::TestCase end def test_none - assert_no_queries do + assert_no_queries(ignore_none: false) do assert_equal [], Developer.none assert_equal [], Developer.all.none end end def test_none_chainable - assert_no_queries do + assert_no_queries(ignore_none: false) do assert_equal [], Developer.none.where(:name => 'David') end end def test_none_chainable_to_existing_scope_extension_method - assert_no_queries do + assert_no_queries(ignore_none: false) do assert_equal 1, Topic.anonymous_extension.none.one end end def test_none_chained_to_methods_firing_queries_straight_to_db - assert_no_queries do + assert_no_queries(ignore_none: false) do assert_equal [], Developer.none.pluck(:id, :name) assert_equal 0, Developer.none.delete_all assert_equal 0, Developer.none.update_all(:name => 'David') @@ -340,7 +340,7 @@ class RelationTest < ActiveRecord::TestCase end def test_null_relation_content_size_methods - assert_no_queries do + assert_no_queries(ignore_none: false) do assert_equal 0, Developer.none.size assert_equal 0, Developer.none.count assert_equal true, Developer.none.empty? @@ -350,7 +350,7 @@ class RelationTest < ActiveRecord::TestCase end def test_null_relation_calculations_methods - assert_no_queries do + assert_no_queries(ignore_none: false) do assert_equal 0, Developer.none.count assert_equal 0, Developer.none.calculate(:count, nil, {}) assert_equal nil, Developer.none.calculate(:average, 'salary') @@ -1570,7 +1570,7 @@ class RelationTest < ActiveRecord::TestCase end test "find_by doesn't have implicit ordering" do - assert_sql(/^((?!ORDER).)*$/) { Post.find_by(author_id: 2) } + assert_sql(/^((?!ORDER).)*$/) { Post.all.find_by(author_id: 2) } end test "find_by! with hash conditions returns the first matching record" do @@ -1586,7 +1586,7 @@ class RelationTest < ActiveRecord::TestCase end test "find_by! doesn't have implicit ordering" do - assert_sql(/^((?!ORDER).)*$/) { Post.find_by!(author_id: 2) } + assert_sql(/^((?!ORDER).)*$/) { Post.all.find_by!(author_id: 2) } end test "find_by! raises RecordNotFound if the record is missing" do diff --git a/activerecord/test/cases/serialized_attribute_test.rb b/activerecord/test/cases/serialized_attribute_test.rb index f8d87a3661..c5fb491b10 100644 --- a/activerecord/test/cases/serialized_attribute_test.rb +++ b/activerecord/test/cases/serialized_attribute_test.rb @@ -16,8 +16,8 @@ class SerializedAttributeTest < ActiveRecord::TestCase end def test_serialize_does_not_eagerly_load_columns + Topic.reset_column_information assert_no_queries do - Topic.reset_column_information Topic.serialize(:content) end end diff --git a/activerecord/test/config.example.yml b/activerecord/test/config.example.yml index a54914c372..ce30cff9e7 100644 --- a/activerecord/test/config.example.yml +++ b/activerecord/test/config.example.yml @@ -55,6 +55,7 @@ connections: arunit: username: rails encoding: utf8 + collation: utf8_unicode_ci arunit2: username: rails encoding: utf8 @@ -63,6 +64,7 @@ connections: arunit: username: rails encoding: utf8 + collation: utf8_unicode_ci arunit2: username: rails encoding: utf8 diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb index 76411ecb37..42f7fb4680 100644 --- a/activerecord/test/models/company.rb +++ b/activerecord/test/models/company.rb @@ -10,6 +10,7 @@ class Company < AbstractCompany has_one :dummy_account, :foreign_key => "firm_id", :class_name => "Account" has_many :contracts has_many :developers, :through => :contracts + has_many :accounts scope :of_first_firm, lambda { joins(:account => :firm). |