diff options
Diffstat (limited to 'activerecord')
23 files changed, 270 insertions, 107 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index aee8f8d1f7..67bec5f38e 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,5 +1,22 @@ ## Rails 4.0.0 (unreleased) ## +* Support for partial inserts. + + When inserting new records, only the fields which have been changed + from the defaults will actually be included in the INSERT statement. + The other fields will be populated by the database. + + This is more efficient, and also means that it will be safe to + remove database columns without getting subsequent errors in running + app processes (so long as the code in those processes doesn't + contain any references to the removed column). + + *Jon Leighton* + +* Allow before and after validations to take an array of lifecycle events + + *John Foley* + * Support for specifying transaction isolation level If your database supports setting the isolation level for a transaction, you can set @@ -76,21 +93,6 @@ *kennyj* -* Fix `find_in_batches` when primary_key is set other than id. - You can now use this method with the primary key which is not integer-based. - - Example: - - class Post < ActiveRecord::Base - self.primary_key = :title - end - - Post.find_in_batches(start: 'My First Post') do |batch| - batch.each { |post| post.author.greeting } - end - - *Toshiyuki Kawanishi* - * You can now override the generated accessor methods for stored attributes and reuse the original behavior with `read_store_attribute` and `write_store_attribute`, which are counterparts to `read_attribute` and `write_attribute`. @@ -299,6 +301,15 @@ *Jon Leighton* +* `Relation#order`: make new order prepend old one. + + User.order("name asc").order("created_at desc") + # SELECT * FROM users ORDER BY created_at desc, name asc + + This also affects order defined in `default_scope` or any kind of associations. + + *Bogdan Gusiev* + * `Model.all` now returns an `ActiveRecord::Relation`, rather than an array of records. Use `Relation#to_a` if you really want an array. @@ -328,6 +339,17 @@ *Jon Leighton* +* Added `#update_columns` method which updates the attributes from + the passed-in hash without calling save, hence skipping validations and + callbacks. `ActiveRecordError` will be raised when called on new objects + or when at least one of the attributes is marked as read only. + + post.attributes # => {"id"=>2, "title"=>"My title", "body"=>"My content", "author"=>"Peter"} + post.update_columns(title: 'New title', author: 'Sebastian') # => true + post.attributes # => {"id"=>2, "title"=>"New title", "body"=>"My content", "author"=>"Sebastian"} + + *Sebastian Martinez + Rafael Mendonça França* + * The migration generator now creates a join table with (commented) indexes every time the migration name contains the word `join_table`: diff --git a/activerecord/Rakefile b/activerecord/Rakefile index a29d7b0e99..53ddff420e 100644 --- a/activerecord/Rakefile +++ b/activerecord/Rakefile @@ -112,8 +112,8 @@ namespace :postgresql do desc 'Build the PostgreSQL test databases' task :build_databases do config = ARTest.config['connections']['postgresql'] - %x( createdb -E UTF8 #{config['arunit']['database']} ) - %x( createdb -E UTF8 #{config['arunit2']['database']} ) + %x( createdb -E UTF8 -T template0 #{config['arunit']['database']} ) + %x( createdb -E UTF8 -T template0 #{config['arunit2']['database']} ) # prepare hstore version = %x( createdb --version ).strip.gsub(/(.*)(\d\.\d\.\d)$/, "\\2") diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb index 495f0cde59..ba75c8be41 100644 --- a/activerecord/lib/active_record/associations/association.rb +++ b/activerecord/lib/active_record/associations/association.rb @@ -154,11 +154,8 @@ module ActiveRecord # We can't dump @reflection since it contains the scope proc def marshal_dump - reflection = @reflection - @reflection = nil - - ivars = instance_variables.map { |name| [name, instance_variable_get(name)] } - [reflection.name, ivars] + ivars = (instance_variables - [:@reflection]).map { |name| [name, instance_variable_get(name)] } + [@reflection.name, ivars] end def marshal_load(data) diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index ced15bc330..0aff2562b8 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -207,8 +207,8 @@ module ActiveRecord value end - def arel_attributes_with_values_for_create(pk_attribute_allowed) - arel_attributes_with_values(attributes_for_create(pk_attribute_allowed)) + def arel_attributes_with_values_for_create(attribute_names) + arel_attributes_with_values(attributes_for_create(attribute_names)) end def arel_attributes_with_values_for_update(attribute_names) @@ -242,9 +242,9 @@ module ActiveRecord # Filters out the primary keys, from the attribute names, when the primary # key is to be generated (e.g. the id attribute has no value). - def attributes_for_create(pk_attribute_allowed) - @attributes.keys.select do |name| - column_for_attribute(name) && (pk_attribute_allowed || !pk_attribute?(name)) + def attributes_for_create(attribute_names) + attribute_names.select do |name| + column_for_attribute(name) && !(pk_attribute?(name) && id.nil?) end end diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb index ba32f1ec51..7a5bb9e863 100644 --- a/activerecord/lib/active_record/attribute_methods/dirty.rb +++ b/activerecord/lib/active_record/attribute_methods/dirty.rb @@ -64,15 +64,29 @@ module ActiveRecord end def update(*) + partial_updates? ? super(keys_for_partial_update) : super + end + + def create(*) if partial_updates? - # Serialized attributes should always be written in case they've been - # changed in place. - super(changed | (attributes.keys & self.class.serialized_attributes.keys)) + keys = keys_for_partial_update + + # This is an extremely bloody annoying necessity to work around mysql being crap. + # See test_mysql_text_not_null_defaults + keys.concat self.class.columns.select(&:explicit_default?).map(&:name) + + super keys else super end end + # Serialized attributes should always be written in case they've been + # changed in place. + def keys_for_partial_update + changed | (attributes.keys & self.class.serialized_attributes.keys) + end + def _field_changed?(attr, old, value) if column = column_for_attribute(attr) if column.number? && (changes_from_nil_to_empty_string?(column, old, value) || diff --git a/activerecord/lib/active_record/attribute_methods/serialization.rb b/activerecord/lib/active_record/attribute_methods/serialization.rb index d2cfcbbaf8..9994a81ede 100644 --- a/activerecord/lib/active_record/attribute_methods/serialization.rb +++ b/activerecord/lib/active_record/attribute_methods/serialization.rb @@ -101,16 +101,6 @@ module ActiveRecord attributes end - - private - - def attribute_cast_code(attr_name) - if serialized_attributes.include?(attr_name) - "v.unserialized_value" - else - super - end - end end def type_cast_attribute_for_write(column, value) diff --git a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb index 9647d03be4..b9a69cdb0a 100644 --- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb +++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb @@ -34,21 +34,6 @@ module ActiveRecord module ClassMethods protected - # The enhanced read method automatically converts the UTC time stored in the database to the time - # zone stored in Time.zone. - def attribute_cast_code(attr_name) - column = columns_hash[attr_name] - - if create_time_zone_conversion_attribute?(attr_name, column) - typecast = "v = #{super}" - time_zone_conversion = "v.acts_like?(:time) ? v.in_time_zone : v" - - "((#{typecast}) && (#{time_zone_conversion}))" - else - super - end - end - # Defined for all +datetime+ and +timestamp+ attributes when +time_zone_aware_attributes+ are enabled. # This enhanced write method will automatically convert the time passed to it to the zone stored in Time.zone. def define_method_attribute=(attr_name) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb index 793f58d4d3..0d7046a705 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -299,7 +299,7 @@ module ActiveRecord end def empty_insert_statement_value - "VALUES(DEFAULT)" + "DEFAULT VALUES" end def case_sensitive_equality_operator 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 1783b036a2..8c83c4f5db 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -30,6 +30,10 @@ module ActiveRecord super end + def explicit_default? + !null && (sql_type =~ /blob/i || type == :text) + end + # Must return the relevant concrete adapter def adapter raise NotImplementedError @@ -320,6 +324,10 @@ module ActiveRecord end end + def empty_insert_statement_value + "VALUES ()" + end + # SCHEMA STATEMENTS ======================================== def structure_dump #:nodoc: diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb index 816b5e17c1..2028abf6f0 100644 --- a/activerecord/lib/active_record/connection_adapters/column.rb +++ b/activerecord/lib/active_record/connection_adapters/column.rb @@ -53,6 +53,10 @@ module ActiveRecord !default.nil? end + def explicit_default? + false + end + # Returns the Ruby class that corresponds to the abstract data type. def klass case type diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index 4a48812807..4d5cb72c67 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -490,10 +490,6 @@ module ActiveRecord alter_table(table_name, :rename => {column_name.to_s => new_column_name.to_s}) end - def empty_insert_statement_value - "VALUES(NULL)" - end - protected def select(sql, name = nil, binds = []) #:nodoc: exec_query(sql, name, binds) diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index 2eaad1d469..f81eb5f5d1 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -385,8 +385,8 @@ module ActiveRecord # Creates a record with values matching those of the instance attributes # and returns its id. - def create - attributes_values = arel_attributes_with_values_for_create(!id.nil?) + def create(attribute_names = @attributes.keys) + attributes_values = arel_attributes_with_values_for_create(attribute_names) new_id = self.class.unscoped.insert attributes_values self.id ||= new_id if self.class.primary_key diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb index e293f641ee..b11483de8c 100644 --- a/activerecord/lib/active_record/railtie.rb +++ b/activerecord/lib/active_record/railtie.rb @@ -82,7 +82,7 @@ module ActiveRecord if cache.version == ActiveRecord::Migrator.current_version ActiveRecord::Model.connection.schema_cache = cache else - warn "schema_cache.dump is expired. Current version is #{ActiveRecord::Migrator.current_version}, but cache version is #{cache.version}." + warn "Ignoring db/schema_cache.dump because it has expired. The current schema version is #{ActiveRecord::Migrator.current_version}, but the one in the cache is #{cache.version}." end end end diff --git a/activerecord/lib/active_record/relation/batches.rb b/activerecord/lib/active_record/relation/batches.rb index d32048cce1..28aab6d92b 100644 --- a/activerecord/lib/active_record/relation/batches.rb +++ b/activerecord/lib/active_record/relation/batches.rb @@ -36,12 +36,12 @@ module ActiveRecord # want multiple workers dealing with the same processing queue. You can # make worker 1 handle all the records between id 0 and 10,000 and # worker 2 handle from 10,000 and beyond (by setting the +:start+ - # option on that worker). You can also use non-integer-based primary keys - # if start point is set. + # option on that worker). # # It's not possible to set the order. That is automatically set to - # ascending on the primary key (e.g. "id ASC") to make the batch ordering - # work. You can't set the limit either, that's used to control + # ascending on the primary key ("id ASC") to make the batch ordering + # work. This also mean that this method only works with integer-based + # primary keys. You can't set the limit either, that's used to control # the batch sizes. # # Person.where("age > 21").find_in_batches do |group| @@ -62,8 +62,7 @@ module ActiveRecord ActiveRecord::Base.logger.warn("Scoped order and limit are ignored, it's forced to be batch order and batch size") end - start = options.delete(:start) - start ||= 0 + start = options.delete(:start) || 0 batch_size = options.delete(:batch_size) || 1000 relation = relation.reorder(batch_order).limit(batch_size) @@ -71,7 +70,7 @@ module ActiveRecord while records.any? records_size = records.size - primary_key_offset = records.last.send(primary_key) + primary_key_offset = records.last.id yield records diff --git a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb index 7abbf08571..3d27c97254 100644 --- a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb +++ b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb @@ -73,13 +73,16 @@ module ActiveRecord configuration.merge('database' => nil) end - # If neither encoding nor collation is specified, use the utf-8 defaults. def creation_options - options = configuration.slice('encoding', 'collation').symbolize_keys - if options.empty? - { charset: DEFAULT_CHARSET, collation: DEFAULT_COLLATION } - else - options + Hash.new.tap do |options| + options[:charset] = configuration['encoding'] if configuration.include? 'encoding' + options[:collation] = configuration['collation'] if configuration.include? 'collation' + + # Set default charset only when collation isn't set. + options[:charset] ||= DEFAULT_CHARSET unless options[:collation] + + # Set default collation only when charset is also default. + options[:collation] ||= DEFAULT_COLLATION if options[:charset] == DEFAULT_CHARSET end end diff --git a/activerecord/test/cases/associations/extension_test.rb b/activerecord/test/cases/associations/extension_test.rb index bd5a426ca8..da767a2a7e 100644 --- a/activerecord/test/cases/associations/extension_test.rb +++ b/activerecord/test/cases/associations/extension_test.rb @@ -40,9 +40,12 @@ class AssociationsExtensionsTest < ActiveRecord::TestCase assert_equal projects(:action_controller), david.projects.find_most_recent marshalled = Marshal.dump(david) - david = Marshal.load(marshalled) - assert_equal projects(:action_controller), david.projects.find_most_recent + # Marshaling an association shouldn't make it unusable by wiping its reflection. + assert_not_nil david.association(:projects).reflection + + david_too = Marshal.load(marshalled) + assert_equal projects(:action_controller), david_too.projects.find_most_recent end def test_marshalling_named_extensions diff --git a/activerecord/test/cases/batches_test.rb b/activerecord/test/cases/batches_test.rb index 3b4ff83725..12d5245fbd 100644 --- a/activerecord/test/cases/batches_test.rb +++ b/activerecord/test/cases/batches_test.rb @@ -1,8 +1,9 @@ require 'cases/helper' require 'models/post' +require 'models/subscriber' class EachTest < ActiveRecord::TestCase - fixtures :posts + fixtures :posts, :subscribers def setup @posts = Post.order("id asc") @@ -125,14 +126,14 @@ class EachTest < ActiveRecord::TestCase end def test_find_in_batches_should_use_any_column_as_primary_key - title_order_posts = Post.order('title asc') - start_title = title_order_posts.first.title + nick_order_subscribers = Subscriber.order('nick asc') + start_nick = nick_order_subscribers.second.nick - posts = [] - PostWithTitlePrimaryKey.find_in_batches(:batch_size => 1, :start => start_title) do |batch| - posts.concat(batch) + subscribers = [] + Subscriber.find_in_batches(:batch_size => 1, :start => start_nick) do |batch| + subscribers.concat(batch) end - assert_equal title_order_posts.map(&:id), posts.map(&:id) + assert_equal nick_order_subscribers[1..-1].map(&:id), subscribers.map(&:id) end end diff --git a/activerecord/test/cases/callbacks_test.rb b/activerecord/test/cases/callbacks_test.rb index deeef3a3fd..7457bafd4e 100644 --- a/activerecord/test/cases/callbacks_test.rb +++ b/activerecord/test/cases/callbacks_test.rb @@ -137,6 +137,32 @@ class OnCallbacksDeveloper < ActiveRecord::Base end end +class ContextualCallbacksDeveloper < ActiveRecord::Base + self.table_name = 'developers' + + before_validation { history << :before_validation } + before_validation :before_validation_on_create_and_update, :on => [ :create, :update ] + + validate do + history << :validate + end + + after_validation { history << :after_validation } + after_validation :after_validation_on_create_and_update, :on => [ :create, :update ] + + def before_validation_on_create_and_update + history << "before_validation_on_#{self.validation_context}".to_sym + end + + def after_validation_on_create_and_update + history << "after_validation_on_#{self.validation_context}".to_sym + end + + def history + @history ||= [] + end +end + class CallbackCancellationDeveloper < ActiveRecord::Base self.table_name = 'developers' @@ -285,6 +311,17 @@ class CallbacksTest < ActiveRecord::TestCase ], david.history end + def test_validate_on_contextual_create + david = ContextualCallbacksDeveloper.create('name' => 'David', 'salary' => 1000000) + assert_equal [ + :before_validation, + :before_validation_on_create, + :validate, + :after_validation, + :after_validation_on_create + ], david.history + end + def test_update david = CallbackDeveloper.find(1) david.save @@ -344,6 +381,18 @@ class CallbacksTest < ActiveRecord::TestCase ], david.history end + def test_validate_on_contextual_update + david = ContextualCallbacksDeveloper.find(1) + david.save + assert_equal [ + :before_validation, + :before_validation_on_update, + :validate, + :after_validation, + :after_validation_on_update + ], david.history + end + def test_destroy david = CallbackDeveloper.find(1) david.destroy diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb index 9a2a5a4e3c..75a52544d3 100644 --- a/activerecord/test/cases/dirty_test.rb +++ b/activerecord/test/cases/dirty_test.rb @@ -3,6 +3,7 @@ require 'models/topic' # For booleans require 'models/pirate' # For timestamps require 'models/parrot' require 'models/person' # For optimistic locking +require 'models/aircraft' class Pirate # Just reopening it, not defining it attr_accessor :detected_changes_in_after_update # Boolean for if changes are detected @@ -550,6 +551,30 @@ class DirtyTest < ActiveRecord::TestCase end end + test "partial insert" do + with_partial_updates Person do + jon = nil + assert_sql(/first_name/) do + jon = Person.create! first_name: 'Jon' + end + + assert ActiveRecord::SQLCounter.log_all.none? { |sql| sql =~ /followers_count/ } + + jon.reload + assert_equal 'Jon', jon.first_name + assert_equal 0, jon.followers_count + assert_not_nil jon.id + end + end + + test "partial insert with empty values" do + with_partial_updates Aircraft do + a = Aircraft.create! + a.reload + assert_not_nil a.id + end + end + private def with_partial_updates(klass, on = true) old = klass.partial_updates? diff --git a/activerecord/test/cases/hot_compatibility_test.rb b/activerecord/test/cases/hot_compatibility_test.rb new file mode 100644 index 0000000000..96e581ab4c --- /dev/null +++ b/activerecord/test/cases/hot_compatibility_test.rb @@ -0,0 +1,54 @@ +require 'cases/helper' + +class HotCompatibilityTest < ActiveRecord::TestCase + self.use_transactional_fixtures = false + + setup do + @klass = Class.new(ActiveRecord::Base) do + connection.create_table :hot_compatibilities do |t| + t.string :foo + t.string :bar + end + + def self.name; 'HotCompatibility'; end + end + end + + teardown do + @klass.connection.drop_table :hot_compatibilities + end + + test "insert after remove_column" do + # warm cache + @klass.create! + + # we have 3 columns + assert_equal 3, @klass.columns.length + + # remove one of them + @klass.connection.remove_column :hot_compatibilities, :bar + + # we still have 3 columns in the cache + assert_equal 3, @klass.columns.length + + # but we can successfully create a record so long as we don't + # reference the removed column + record = @klass.create! foo: 'foo' + record.reload + assert_equal 'foo', record.foo + end + + test "update after remove_column" do + record = @klass.create! foo: 'foo' + assert_equal 3, @klass.columns.length + @klass.connection.remove_column :hot_compatibilities, :bar + assert_equal 3, @klass.columns.length + + record.reload + assert_equal 'foo', record.foo + record.foo = 'bar' + record.save! + record.reload + assert_equal 'bar', record.foo + end +end diff --git a/activerecord/test/cases/tasks/mysql_rake_test.rb b/activerecord/test/cases/tasks/mysql_rake_test.rb index 46b97a1274..69a049fcfa 100644 --- a/activerecord/test/cases/tasks/mysql_rake_test.rb +++ b/activerecord/test/cases/tasks/mysql_rake_test.rb @@ -20,20 +20,32 @@ module ActiveRecord ActiveRecord::Tasks::DatabaseTasks.create @configuration end - def test_creates_database_with_default_options + def test_creates_database_with_default_encoding_and_collation @connection.expects(:create_database). - with('my-app-db', {:charset => 'utf8', :collation => 'utf8_unicode_ci'}) + with('my-app-db', charset: 'utf8', collation: 'utf8_unicode_ci') ActiveRecord::Tasks::DatabaseTasks.create @configuration end - def test_creates_database_with_given_options + def test_creates_database_with_given_encoding_and_default_collation @connection.expects(:create_database). - with('my-app-db', {:charset => 'latin', :collation => 'latin_ci'}) + with('my-app-db', charset: 'utf8', collation: 'utf8_unicode_ci') - ActiveRecord::Tasks::DatabaseTasks.create @configuration.merge( - 'encoding' => 'latin', 'collation' => 'latin_ci' - ) + ActiveRecord::Tasks::DatabaseTasks.create @configuration.merge('encoding' => 'utf8') + end + + def test_creates_database_with_given_encoding_and_no_collation + @connection.expects(:create_database). + with('my-app-db', charset: 'latin1') + + ActiveRecord::Tasks::DatabaseTasks.create @configuration.merge('encoding' => 'latin1') + end + + def test_creates_database_with_given_collation_and_no_encoding + @connection.expects(:create_database). + with('my-app-db', collation: 'latin1_swedish_ci') + + ActiveRecord::Tasks::DatabaseTasks.create @configuration.merge('collation' => 'latin1_swedish_ci') end def test_establishes_connection_to_database @@ -62,8 +74,9 @@ module ActiveRecord $stdout.stubs(:print).returns(nil) @error.stubs(:errno).returns(1045) ActiveRecord::Base.stubs(:connection).returns(@connection) - ActiveRecord::Base.stubs(:establish_connection).raises(@error).then. - returns(true) + ActiveRecord::Base.stubs(:establish_connection). + raises(@error). + then.returns(true) end def test_root_password_is_requested @@ -74,12 +87,12 @@ module ActiveRecord end def test_connection_established_as_root - ActiveRecord::Base.expects(:establish_connection).with({ + ActiveRecord::Base.expects(:establish_connection).with( 'adapter' => 'mysql', 'database' => nil, 'username' => 'root', 'password' => 'secret' - }) + ) ActiveRecord::Tasks::DatabaseTasks.create @configuration end @@ -99,12 +112,12 @@ module ActiveRecord def test_connection_established_as_normal_user ActiveRecord::Base.expects(:establish_connection).returns do - ActiveRecord::Base.expects(:establish_connection).with({ + ActiveRecord::Base.expects(:establish_connection).with( 'adapter' => 'mysql', 'database' => 'my-app-db', 'username' => 'pat', 'password' => 'secret' - }) + ) raise @error end @@ -166,18 +179,17 @@ module ActiveRecord def test_recreates_database_with_the_default_options @connection.expects(:recreate_database). - with('test-db', {:charset => 'utf8', :collation => 'utf8_unicode_ci'}) + with('test-db', charset: 'utf8', collation: 'utf8_unicode_ci') ActiveRecord::Tasks::DatabaseTasks.purge @configuration end def test_recreates_database_with_the_given_options @connection.expects(:recreate_database). - with('test-db', {:charset => 'latin', :collation => 'latin_ci'}) + with('test-db', charset: 'latin', collation: 'latin1_swedish_ci') ActiveRecord::Tasks::DatabaseTasks.purge @configuration.merge( - 'encoding' => 'latin', 'collation' => 'latin_ci' - ) + 'encoding' => 'latin', 'collation' => 'latin1_swedish_ci') end end diff --git a/activerecord/test/cases/transaction_isolation_test.rb b/activerecord/test/cases/transaction_isolation_test.rb index 1e34f93d8f..a396da6645 100644 --- a/activerecord/test/cases/transaction_isolation_test.rb +++ b/activerecord/test/cases/transaction_isolation_test.rb @@ -44,6 +44,9 @@ class TransactionIsolationTest < ActiveRecord::TestCase # specifies what must not happen at a certain level, not what must happen. At # the read uncommitted level, there is nothing that must not happen. test "read uncommitted" do + unless ActiveRecord::Base.connection.transaction_isolation_levels.include?(:read_uncommitted) + skip "database does not support read uncommitted isolation level" + end Tag.transaction(isolation: :read_uncommitted) do assert_equal 0, Tag.count Tag2.create @@ -67,6 +70,9 @@ class TransactionIsolationTest < ActiveRecord::TestCase # We are testing that a nonrepeatable read does not happen test "repeatable read" do + unless ActiveRecord::Base.connection.transaction_isolation_levels.include?(:repeatable_read) + skip "database does not support repeatable read isolation level" + end tag = Tag.create(name: 'jon') Tag.transaction(isolation: :repeatable_read) do diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb index 9858f68c4a..c995f59a15 100644 --- a/activerecord/test/models/post.rb +++ b/activerecord/test/models/post.rb @@ -186,8 +186,3 @@ class SpecialPostWithDefaultScope < ActiveRecord::Base self.table_name = 'posts' default_scope { where(:id => [1, 5,6]) } end - -class PostWithTitlePrimaryKey < ActiveRecord::Base - self.table_name = 'posts' - self.primary_key = :title -end |