diff options
Diffstat (limited to 'activerecord')
29 files changed, 235 insertions, 144 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 61dba12b64..70d7988e94 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,28 @@ +* Revert `ActiveRecord::Relation#order` change that make new order + prepend the old one. + + Before: + + User.order("name asc").order("created_at desc") + # SELECT * FROM users ORDER BY created_at desc, name asc + + After: + + User.order("name asc").order("created_at desc") + # SELECT * FROM users ORDER BY name asc, created_at desc + + This also affects order defined in `default_scope` or any kind of associations. + +* Add ability to define how a class is converted to Arel predicates. + For example, adding a very vendor specific regex implementation: + + regex_handler = proc do |column, value| + Arel::Nodes::InfixOperation.new('~', column, value.source) + end + ActiveRecord::PredicateBuilder.register_handler(Regexp, regex_handler) + + *Sean Griffin & @joannecheng* + * Don't allow `quote_value` to be called without a column. Some adapters require column information to do their job properly. diff --git a/activerecord/Rakefile b/activerecord/Rakefile index ad5372ed50..cee1dd5aeb 100644 --- a/activerecord/Rakefile +++ b/activerecord/Rakefile @@ -58,11 +58,10 @@ end task "isolated_test_#{adapter}" do adapter_short = adapter == 'db2' ? adapter : adapter[/^[a-z0-9]+/] puts [adapter, adapter_short].inspect - ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME')) (Dir["test/cases/**/*_test.rb"].reject { |x| x =~ /\/adapters\// } + Dir["test/cases/adapters/#{adapter_short}/**/*_test.rb"]).all? do |file| - sh(ruby, '-w' ,"-Itest", file) + sh(Gem.ruby, '-w' ,"-Itest", file) end or raise "Failures" end diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb index bdfafa5066..62b9c94422 100644 --- a/activerecord/lib/active_record/associations/association_scope.rb +++ b/activerecord/lib/active_record/associations/association_scope.rb @@ -89,10 +89,11 @@ module ActiveRecord scope = scope.joins(join(foreign_table, constraint)) end + klass = i == 0 ? self.klass : reflection.klass + # Exclude the scope of the association itself, because that # was already merged in the #scope method. scope_chain[i].each do |scope_chain_item| - klass = i == 0 ? self.klass : reflection.klass item = eval_scope(klass, scope_chain_item) if scope_chain_item == self.reflection.scope diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/array_parser.rb b/activerecord/lib/active_record/connection_adapters/postgresql/array_parser.rb index b7d24f2bb3..20de8d1982 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/array_parser.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/array_parser.rb @@ -2,6 +2,13 @@ module ActiveRecord module ConnectionAdapters class PostgreSQLColumn < Column module ArrayParser + + DOUBLE_QUOTE = '"' + BACKSLASH = "\\" + COMMA = ',' + BRACKET_OPEN = '{' + BRACKET_CLOSE = '}' + private # Loads pg_array_parser if available. String parsing can be # performed quicker by a native extension, which will not create @@ -12,18 +19,18 @@ module ActiveRecord include PgArrayParser rescue LoadError def parse_pg_array(string) - parse_data(string, 0) + parse_data(string) end end - def parse_data(string, index) - local_index = index + def parse_data(string) + local_index = 0 array = [] while(local_index < string.length) case string[local_index] - when '{' + when BRACKET_OPEN local_index,array = parse_array_contents(array, string, local_index + 1) - when '}' + when BRACKET_CLOSE return array end local_index += 1 @@ -33,9 +40,9 @@ module ActiveRecord end def parse_array_contents(array, string, index) - is_escaping = false - is_quoted = false - was_quoted = false + is_escaping = false + is_quoted = false + was_quoted = false current_item = '' local_index = index @@ -47,29 +54,29 @@ module ActiveRecord else if is_quoted case token - when '"' + when DOUBLE_QUOTE is_quoted = false was_quoted = true - when "\\" + when BACKSLASH is_escaping = true else current_item << token end else case token - when "\\" + when BACKSLASH is_escaping = true - when ',' + when COMMA add_item_to_array(array, current_item, was_quoted) current_item = '' was_quoted = false - when '"' + when DOUBLE_QUOTE is_quoted = true - when '{' + when BRACKET_OPEN internal_items = [] local_index,internal_items = parse_array_contents(internal_items, string, local_index + 1) array.push(internal_items) - when '}' + when BRACKET_CLOSE add_item_to_array(array, current_item, was_quoted) return local_index,array else diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 90020c3510..19c6f8148b 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -32,7 +32,7 @@ module ActiveRecord class PendingMigrationError < ActiveRecordError#:nodoc: def initialize - super("Migrations are pending; run 'bin/rake db:migrate RAILS_ENV=#{Rails.env}' to resolve this issue.") + super("Migrations are pending; run 'bin/rake db:migrate RAILS_ENV=#{::Rails.env}' to resolve this issue.") end end diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 73d154e03e..2fa7b1194d 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -564,7 +564,7 @@ module ActiveRecord # of scopes corresponding to the chain. def scope_chain @scope_chain ||= begin - scope_chain = source_reflection.scope_chain.map(&:dup) + scope_chain = source_reflection.scope_chain # Add to it the scope from this reflection (if any) scope_chain.first << scope if scope diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb index 08ef899f68..8948f2bba5 100644 --- a/activerecord/lib/active_record/relation/predicate_builder.rb +++ b/activerecord/lib/active_record/relation/predicate_builder.rb @@ -1,5 +1,10 @@ module ActiveRecord class PredicateBuilder # :nodoc: + @handlers = [] + + autoload :RelationHandler, 'active_record/relation/predicate_builder/relation_handler' + autoload :ArrayHandler, 'active_record/relation/predicate_builder/array_handler' + def self.resolve_column_aliases(klass, hash) hash = hash.dup hash.keys.grep(Symbol) do |key| @@ -73,44 +78,36 @@ module ActiveRecord end.compact end + # Define how a class is converted to Arel nodes when passed to +where+. + # The handler can be any object that responds to +call+, and will be used + # for any value that +===+ the class given. For example: + # + # MyCustomDateRange = Struct.new(:start, :end) + # handler = proc do |column, range| + # Arel::Nodes::Between.new(column, + # Arel::Nodes::And.new([range.start, range.end]) + # ) + # end + # ActiveRecord::PredicateBuilder.register_handler(MyCustomDateRange, handler) + def self.register_handler(klass, handler) + @handlers.unshift([klass, handler]) + end + + register_handler(BasicObject, ->(attribute, value) { attribute.eq(value) }) + # FIXME: I think we need to deprecate this behavior + register_handler(Class, ->(attribute, value) { attribute.eq(value.name) }) + register_handler(Base, ->(attribute, value) { attribute.eq(value.id) }) + register_handler(Range, ->(attribute, value) { attribute.in(value) }) + register_handler(Relation, RelationHandler.new) + register_handler(Array, ArrayHandler.new) + private def self.build(attribute, value) - case value - when Array - values = value.to_a.map {|x| x.is_a?(Base) ? x.id : x} - ranges, values = values.partition {|v| v.is_a?(Range)} - - values_predicate = if values.include?(nil) - values = values.compact - - case values.length - when 0 - attribute.eq(nil) - when 1 - attribute.eq(values.first).or(attribute.eq(nil)) - else - attribute.in(values).or(attribute.eq(nil)) - end - else - attribute.in(values) - end + handler_for(value).call(attribute, value) + end - array_predicates = ranges.map { |range| attribute.in(range) } - array_predicates << values_predicate - array_predicates.inject { |composite, predicate| composite.or(predicate) } - when ActiveRecord::Relation - value = value.select(value.klass.arel_table[value.klass.primary_key]) if value.select_values.empty? - attribute.in(value.arel.ast) - when Range - attribute.in(value) - when ActiveRecord::Base - attribute.eq(value.id) - when Class - # FIXME: I think we need to deprecate this behavior - attribute.eq(value.name) - else - attribute.eq(value) - end + def self.handler_for(object) + @handlers.detect { |klass, _| klass === object }.last end end end diff --git a/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb new file mode 100644 index 0000000000..2f6c34ac08 --- /dev/null +++ b/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb @@ -0,0 +1,29 @@ +module ActiveRecord + class PredicateBuilder + class ArrayHandler # :nodoc: + def call(attribute, value) + values = value.map { |x| x.is_a?(Base) ? x.id : x } + ranges, values = values.partition { |v| v.is_a?(Range) } + + values_predicate = if values.include?(nil) + values = values.compact + + case values.length + when 0 + attribute.eq(nil) + when 1 + attribute.eq(values.first).or(attribute.eq(nil)) + else + attribute.in(values).or(attribute.eq(nil)) + end + else + attribute.in(values) + end + + array_predicates = ranges.map { |range| attribute.in(range) } + array_predicates << values_predicate + array_predicates.inject { |composite, predicate| composite.or(predicate) } + end + end + end +end diff --git a/activerecord/lib/active_record/relation/predicate_builder/relation_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/relation_handler.rb new file mode 100644 index 0000000000..618fa3cdd9 --- /dev/null +++ b/activerecord/lib/active_record/relation/predicate_builder/relation_handler.rb @@ -0,0 +1,13 @@ +module ActiveRecord + class PredicateBuilder + class RelationHandler # :nodoc: + def call(attribute, value) + if value.select_values.empty? + value = value.select(value.klass.arel_table[value.klass.primary_key]) + end + + attribute.in(value.arel.ast) + end + end + end +end diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index d0c56ac3d0..49b632c4c7 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -299,7 +299,7 @@ module ActiveRecord arg } - self.order_values = args.concat self.order_values + self.order_values += args self end @@ -311,7 +311,7 @@ module ActiveRecord # # User.order('email DESC').reorder('id ASC').order('name ASC') # - # generates a query with 'ORDER BY name ASC, id ASC'. + # generates a query with 'ORDER BY id ASC, name ASC'. def reorder(*args) check_if_method_has_arguments!("reorder", args) spawn.reorder!(*args) diff --git a/activerecord/test/cases/adapters/mysql/reserved_word_test.rb b/activerecord/test/cases/adapters/mysql/reserved_word_test.rb index 4cf4bc4c61..8eb9565963 100644 --- a/activerecord/test/cases/adapters/mysql/reserved_word_test.rb +++ b/activerecord/test/cases/adapters/mysql/reserved_word_test.rb @@ -2,7 +2,7 @@ require "cases/helper" class Group < ActiveRecord::Base Group.table_name = 'group' - belongs_to :select, :class_name => 'Select' + belongs_to :select has_one :values end diff --git a/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb b/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb index e76617b845..1a82308176 100644 --- a/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb +++ b/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb @@ -2,7 +2,7 @@ require "cases/helper" class Group < ActiveRecord::Base Group.table_name = 'group' - belongs_to :select, :class_name => 'Select' + belongs_to :select has_one :values end diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb index 0267cdf6e0..a79f145e31 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -605,6 +605,8 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase end def test_dependent_delete_and_destroy_with_belongs_to + AuthorAddress.destroyed_author_address_ids.clear + author_address = author_addresses(:david_address) author_address_extra = author_addresses(:david_address_extra) assert_equal [], AuthorAddress.destroyed_author_address_ids diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb index c63f48e370..712a770133 100644 --- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb @@ -506,9 +506,9 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase assert_equal high_id_jamis, projects(:active_record).developers.find_by_name('Jamis') end - def test_find_should_prepend_to_association_order + def test_find_should_append_to_association_order ordered_developers = projects(:active_record).developers.order('projects.id') - assert_equal ['projects.id', 'developers.name desc, developers.id desc'], ordered_developers.order_values + assert_equal ['developers.name desc, developers.id desc', 'projects.id'], ordered_developers.order_values end def test_dynamic_find_all_should_respect_readonly_access diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 9c484a8bbe..ce51853bf3 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -253,9 +253,9 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal 2, companies(:first_firm).limited_clients.limit(nil).to_a.size end - def test_find_should_prepend_to_association_order + def test_find_should_append_to_association_order ordered_clients = companies(:first_firm).clients_sorted_desc.order('companies.id') - assert_equal ['companies.id', 'id DESC'], ordered_clients.order_values + assert_equal ['id DESC', 'companies.id'], ordered_clients.order_values end def test_dynamic_find_should_respect_association_order diff --git a/activerecord/test/cases/associations/has_one_through_associations_test.rb b/activerecord/test/cases/associations/has_one_through_associations_test.rb index 90c557e886..f2723f2e18 100644 --- a/activerecord/test/cases/associations/has_one_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_through_associations_test.rb @@ -191,6 +191,7 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase end def test_preloading_has_one_through_on_belongs_to + MemberDetail.delete_all assert_not_nil @member.member_type @organization = organizations(:nsa) @member_detail = MemberDetail.new @@ -201,7 +202,7 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase end @new_detail = @member_details[0] assert @new_detail.send(:association, :member_type).loaded? - assert_not_nil assert_no_queries { @new_detail.member_type } + assert_no_queries { @new_detail.member_type } end def test_save_of_record_with_loaded_has_one_through diff --git a/activerecord/test/cases/associations/nested_through_associations_test.rb b/activerecord/test/cases/associations/nested_through_associations_test.rb index e75d43bda8..9b1abc3b81 100644 --- a/activerecord/test/cases/associations/nested_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_through_associations_test.rb @@ -186,7 +186,9 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase members = assert_queries(4) { Member.includes(:organization_member_details_2).to_a.sort_by(&:id) } groucho_details, other_details = member_details(:groucho), member_details(:some_other_guy) - assert_no_queries do + # postgresql test if randomly executed then executes "SHOW max_identifier_length". Hence + # the need to ignore certain predefined sqls that deal with system calls. + assert_no_queries(ignore_none: false) do assert_equal [groucho_details, other_details], members.first.organization_member_details_2.sort_by(&:id) end end diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index d8bc0653a1..51a8a13d04 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -876,11 +876,4 @@ class FinderTest < ActiveRecord::TestCase ensure old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ') end - - def with_active_record_default_timezone(zone) - old_zone, ActiveRecord::Base.default_timezone = ActiveRecord::Base.default_timezone, zone - yield - ensure - ActiveRecord::Base.default_timezone = old_zone - end end diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb index 7dbb6616f8..f96978aff8 100644 --- a/activerecord/test/cases/helper.rb +++ b/activerecord/test/cases/helper.rb @@ -124,7 +124,7 @@ module LogIntercepter def self.extended(base) base.logged = [] end - def log(sql, name, binds = [], &block) + def log(sql, name = 'SQL', binds = [], &block) if @intercepted @logged << [sql, name, binds] yield diff --git a/activerecord/test/cases/integration_test.rb b/activerecord/test/cases/integration_test.rb index b0a7cda2f3..f5daca2fa8 100644 --- a/activerecord/test/cases/integration_test.rb +++ b/activerecord/test/cases/integration_test.rb @@ -32,6 +32,8 @@ class IntegrationTest < ActiveRecord::TestCase est_key = Developer.first.cache_key assert_equal utc_key, est_key + ensure + Time.zone = 'UTC' end def test_cache_key_format_for_existing_record_with_updated_at diff --git a/activerecord/test/cases/multiparameter_attributes_test.rb b/activerecord/test/cases/multiparameter_attributes_test.rb index 1209f5460f..ce21760645 100644 --- a/activerecord/test/cases/multiparameter_attributes_test.rb +++ b/activerecord/test/cases/multiparameter_attributes_test.rb @@ -11,6 +11,10 @@ class MultiParameterAttributeTest < ActiveRecord::TestCase Time.zone = nil end + def teardown + ActiveRecord::Base.default_timezone = :utc + end + def test_multiparameter_attributes_on_date attributes = { "last_read(1i)" => "2004", "last_read(2i)" => "6", "last_read(3i)" => "24" } topic = Topic.find(1) diff --git a/activerecord/test/cases/quoting_test.rb b/activerecord/test/cases/quoting_test.rb index 3dd11ae89d..85fbe01416 100644 --- a/activerecord/test/cases/quoting_test.rb +++ b/activerecord/test/cases/quoting_test.rb @@ -53,50 +53,40 @@ module ActiveRecord end def test_quoted_time_utc - before = ActiveRecord::Base.default_timezone - ActiveRecord::Base.default_timezone = :utc - t = Time.now - assert_equal t.getutc.to_s(:db), @quoter.quoted_date(t) - ensure - ActiveRecord::Base.default_timezone = before + with_active_record_default_timezone :utc do + t = Time.now + assert_equal t.getutc.to_s(:db), @quoter.quoted_date(t) + end end def test_quoted_time_local - before = ActiveRecord::Base.default_timezone - ActiveRecord::Base.default_timezone = :local - t = Time.now - assert_equal t.getlocal.to_s(:db), @quoter.quoted_date(t) - ensure - ActiveRecord::Base.default_timezone = before + with_active_record_default_timezone :local do + t = Time.now + assert_equal t.getlocal.to_s(:db), @quoter.quoted_date(t) + end end def test_quoted_time_crazy - before = ActiveRecord::Base.default_timezone - ActiveRecord::Base.default_timezone = :asdfasdf - t = Time.now - assert_equal t.getlocal.to_s(:db), @quoter.quoted_date(t) - ensure - ActiveRecord::Base.default_timezone = before + with_active_record_default_timezone :asdfasdf do + t = Time.now + assert_equal t.getlocal.to_s(:db), @quoter.quoted_date(t) + end end def test_quoted_datetime_utc - before = ActiveRecord::Base.default_timezone - ActiveRecord::Base.default_timezone = :utc - t = DateTime.now - assert_equal t.getutc.to_s(:db), @quoter.quoted_date(t) - ensure - ActiveRecord::Base.default_timezone = before + with_active_record_default_timezone :utc do + t = DateTime.now + assert_equal t.getutc.to_s(:db), @quoter.quoted_date(t) + end end ### # DateTime doesn't define getlocal, so make sure it does nothing def test_quoted_datetime_local - before = ActiveRecord::Base.default_timezone - ActiveRecord::Base.default_timezone = :local - t = DateTime.now - assert_equal t.to_s(:db), @quoter.quoted_date(t) - ensure - ActiveRecord::Base.default_timezone = before + with_active_record_default_timezone :local do + t = DateTime.now + assert_equal t.to_s(:db), @quoter.quoted_date(t) + end end def test_quote_with_quoted_id diff --git a/activerecord/test/cases/relation/predicate_builder_test.rb b/activerecord/test/cases/relation/predicate_builder_test.rb new file mode 100644 index 0000000000..1c87f5c12e --- /dev/null +++ b/activerecord/test/cases/relation/predicate_builder_test.rb @@ -0,0 +1,14 @@ +require "cases/helper" +require 'models/topic' + +module ActiveRecord + class PredicateBuilderTest < ActiveRecord::TestCase + def test_registering_new_handlers + PredicateBuilder.register_handler(Regexp, proc do |column, value| + Arel::Nodes::InfixOperation.new('~', column, value.source) + end) + + assert_match %r{["`]topics["`].["`]title["`] ~ 'rails'}, Topic.where(title: /rails/).to_sql + end + end +end diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index d0f8731b9a..bf9d395b2d 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -180,7 +180,7 @@ class RelationTest < ActiveRecord::TestCase end def test_finding_with_order_concatenated - topics = Topic.order('title').order('author_name') + topics = Topic.order('author_name').order('title') assert_equal 4, topics.to_a.size assert_equal topics(:fourth).title, topics.first.title end @@ -1183,20 +1183,20 @@ class RelationTest < ActiveRecord::TestCase end def test_default_scope_order_with_scope_order - assert_equal 'honda', CoolCar.order_using_new_style.limit(1).first.name - assert_equal 'honda', FastCar.order_using_new_style.limit(1).first.name + assert_equal 'zyke', CoolCar.order_using_new_style.limit(1).first.name + assert_equal 'zyke', FastCar.order_using_new_style.limit(1).first.name end def test_order_using_scoping car1 = CoolCar.order('id DESC').scoping do - CoolCar.all.merge!(:order => 'id asc').first + CoolCar.all.merge!(order: 'id asc').first end - assert_equal 'honda', car1.name + assert_equal 'zyke', car1.name car2 = FastCar.order('id DESC').scoping do - FastCar.all.merge!(:order => 'id asc').first + FastCar.all.merge!(order: 'id asc').first end - assert_equal 'honda', car2.name + assert_equal 'zyke', car2.name end def test_unscoped_block_style diff --git a/activerecord/test/cases/scoping/default_scoping_test.rb b/activerecord/test/cases/scoping/default_scoping_test.rb index 4bcc97ec44..2358e2396d 100644 --- a/activerecord/test/cases/scoping/default_scoping_test.rb +++ b/activerecord/test/cases/scoping/default_scoping_test.rb @@ -82,7 +82,7 @@ class DefaultScopingTest < ActiveRecord::TestCase end def test_scope_overwrites_default - expected = Developer.all.merge!(:order => ' name DESC, salary DESC').to_a.collect { |dev| dev.name } + expected = Developer.all.merge!(order: 'salary DESC, name DESC').to_a.collect { |dev| dev.name } received = DeveloperOrderedBySalary.by_name.to_a.collect { |dev| dev.name } assert_equal expected, received end @@ -94,7 +94,7 @@ class DefaultScopingTest < ActiveRecord::TestCase end def test_order_after_reorder_combines_orders - expected = Developer.order('id DESC, name DESC').collect { |dev| [dev.name, dev.id] } + expected = Developer.order('name DESC, id DESC').collect { |dev| [dev.name, dev.id] } received = Developer.order('name ASC').reorder('name DESC').order('id DESC').collect { |dev| [dev.name, dev.id] } assert_equal expected, received end @@ -253,8 +253,8 @@ class DefaultScopingTest < ActiveRecord::TestCase end def test_order_in_default_scope_should_not_prevail - expected = Developer.all.merge!(:order => 'salary').to_a.collect { |dev| dev.salary } - received = DeveloperOrderedBySalary.all.merge!(:order => 'salary').to_a.collect { |dev| dev.salary } + expected = Developer.all.merge!(order: 'salary desc').to_a.collect { |dev| dev.salary } + received = DeveloperOrderedBySalary.all.merge!(order: 'salary').to_a.collect { |dev| dev.salary } assert_equal expected, received end diff --git a/activerecord/test/cases/test_case.rb b/activerecord/test/cases/test_case.rb index c33e5cdc00..8c6d189b0c 100644 --- a/activerecord/test/cases/test_case.rb +++ b/activerecord/test/cases/test_case.rb @@ -45,8 +45,9 @@ module ActiveRecord x end - def assert_no_queries(&block) - assert_queries(0, :ignore_none => true, &block) + def assert_no_queries(options = {}, &block) + options.reverse_merge! ignore_none: true + assert_queries(0, options, &block) end def assert_column(model, column_name, msg=nil) diff --git a/activerecord/test/cases/transaction_callbacks_test.rb b/activerecord/test/cases/transaction_callbacks_test.rb index 9485de88a6..5644a35385 100644 --- a/activerecord/test/cases/transaction_callbacks_test.rb +++ b/activerecord/test/cases/transaction_callbacks_test.rb @@ -182,9 +182,9 @@ class TransactionCallbacksTest < ActiveRecord::TestCase end def test_call_after_rollback_when_commit_fails - @first.class.connection.class.send(:alias_method, :real_method_commit_db_transaction, :commit_db_transaction) + @first.class.connection.singleton_class.send(:alias_method, :real_method_commit_db_transaction, :commit_db_transaction) begin - @first.class.connection.class.class_eval do + @first.class.connection.singleton_class.class_eval do def commit_db_transaction; raise "boom!"; end end @@ -194,8 +194,8 @@ class TransactionCallbacksTest < ActiveRecord::TestCase assert !@first.save rescue nil assert_equal [:after_rollback], @first.history ensure - @first.class.connection.class.send(:remove_method, :commit_db_transaction) - @first.class.connection.class.send(:alias_method, :commit_db_transaction, :real_method_commit_db_transaction) + @first.class.connection.singleton_class.send(:remove_method, :commit_db_transaction) + @first.class.connection.singleton_class.send(:alias_method, :commit_db_transaction, :real_method_commit_db_transaction) end end diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb index 9c5f2e4724..f84088def3 100644 --- a/activerecord/test/cases/transactions_test.rb +++ b/activerecord/test/cases/transactions_test.rb @@ -453,6 +453,11 @@ class TransactionTest < ActiveRecord::TestCase raise ActiveRecord::Rollback end end + + ensure + Topic.reset_column_information # reset the column information to get correct reading + Topic.connection.remove_column('topics', 'stuff') if Topic.column_names.include?('stuff') + Topic.reset_column_information # reset the column information again for other tests end def test_transactions_state_from_rollback diff --git a/activerecord/test/cases/validations/association_validation_test.rb b/activerecord/test/cases/validations/association_validation_test.rb index 7e92a2b127..602f633c45 100644 --- a/activerecord/test/cases/validations/association_validation_test.rb +++ b/activerecord/test/cases/validations/association_validation_test.rb @@ -10,29 +10,33 @@ require 'models/interest' class AssociationValidationTest < ActiveRecord::TestCase fixtures :topics, :owners - repair_validations(Topic, Reply, Owner) + repair_validations(Topic, Reply) def test_validates_size_of_association - assert_nothing_raised { Owner.validates_size_of :pets, :minimum => 1 } - o = Owner.new('name' => 'nopets') - assert !o.save - assert o.errors[:pets].any? - o.pets.build('name' => 'apet') - assert o.valid? + repair_validations Owner do + assert_nothing_raised { Owner.validates_size_of :pets, :minimum => 1 } + o = Owner.new('name' => 'nopets') + assert !o.save + assert o.errors[:pets].any? + o.pets.build('name' => 'apet') + assert o.valid? + end end def test_validates_size_of_association_using_within - assert_nothing_raised { Owner.validates_size_of :pets, :within => 1..2 } - o = Owner.new('name' => 'nopets') - assert !o.save - assert o.errors[:pets].any? - - o.pets.build('name' => 'apet') - assert o.valid? - - 2.times { o.pets.build('name' => 'apet') } - assert !o.save - assert o.errors[:pets].any? + repair_validations Owner do + assert_nothing_raised { Owner.validates_size_of :pets, :within => 1..2 } + o = Owner.new('name' => 'nopets') + assert !o.save + assert o.errors[:pets].any? + + o.pets.build('name' => 'apet') + assert o.valid? + + 2.times { o.pets.build('name' => 'apet') } + assert !o.save + assert o.errors[:pets].any? + end end def test_validates_associated_many @@ -91,12 +95,14 @@ class AssociationValidationTest < ActiveRecord::TestCase end def test_validates_size_of_association_utf8 - assert_nothing_raised { Owner.validates_size_of :pets, :minimum => 1 } - o = Owner.new('name' => 'あいうえおかきくけこ') - assert !o.save - assert o.errors[:pets].any? - o.pets.build('name' => 'あいうえおかきくけこ') - assert o.valid? + repair_validations Owner do + assert_nothing_raised { Owner.validates_size_of :pets, :minimum => 1 } + o = Owner.new('name' => 'あいうえおかきくけこ') + assert !o.save + assert o.errors[:pets].any? + o.pets.build('name' => 'あいうえおかきくけこ') + assert o.valid? + end end def test_validates_presence_of_belongs_to_association__parent_is_new_record |