aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
authorDavid Heinemeier Hansson <david@loudthinking.com>2014-08-29 14:54:08 -0700
committerDavid Heinemeier Hansson <david@loudthinking.com>2014-08-29 14:54:08 -0700
commit7475b43cdbbbf7456e798210cb97ef20f2225166 (patch)
tree04ae517943ccc476ca0a8b9b3bdbb21949a558c1 /activerecord
parent6a23bf0f4c33151e0cec0648e271dc6f5ab3f686 (diff)
parent4445478df311a74797d8dc4945c40662f9c1442a (diff)
downloadrails-7475b43cdbbbf7456e798210cb97ef20f2225166.tar.gz
rails-7475b43cdbbbf7456e798210cb97ef20f2225166.tar.bz2
rails-7475b43cdbbbf7456e798210cb97ef20f2225166.zip
Merge branch 'master' of github.com:rails/rails
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/CHANGELOG.md21
-rw-r--r--activerecord/RUNNING_UNIT_TESTS.rdoc4
-rw-r--r--activerecord/Rakefile2
-rw-r--r--activerecord/lib/active_record/associations.rb89
-rw-r--r--activerecord/lib/active_record/associations/collection_proxy.rb8
-rw-r--r--activerecord/lib/active_record/associations/has_many_through_association.rb12
-rw-r--r--activerecord/lib/active_record/associations/through_association.rb6
-rw-r--r--activerecord/lib/active_record/attribute_methods.rb8
-rw-r--r--activerecord/lib/active_record/attribute_methods/dirty.rb29
-rw-r--r--activerecord/lib/active_record/attribute_methods/read.rb4
-rw-r--r--activerecord/lib/active_record/attribute_methods/serialization.rb7
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb11
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb8
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/uuid.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb7
-rw-r--r--activerecord/lib/active_record/core.rb6
-rw-r--r--activerecord/lib/active_record/fixtures.rb12
-rw-r--r--activerecord/lib/active_record/migration.rb20
-rw-r--r--activerecord/lib/active_record/reflection.rb31
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb6
-rw-r--r--activerecord/lib/active_record/tasks/database_tasks.rb12
-rw-r--r--activerecord/lib/active_record/transactions.rb18
-rw-r--r--activerecord/lib/active_record/type/binary.rb10
-rw-r--r--activerecord/lib/active_record/type/serialized.rb5
-rw-r--r--activerecord/test/cases/adapters/postgresql/explain_test.rb3
-rw-r--r--activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb20
-rw-r--r--activerecord/test/cases/adapters/postgresql/uuid_test.rb14
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb20
-rw-r--r--activerecord/test/cases/associations/has_many_through_associations_test.rb2
-rw-r--r--activerecord/test/cases/associations/has_one_associations_test.rb2
-rw-r--r--activerecord/test/cases/attribute_decorators_test.rb1
-rw-r--r--activerecord/test/cases/autosave_association_test.rb8
-rw-r--r--activerecord/test/cases/base_test.rb14
-rw-r--r--activerecord/test/cases/calculations_test.rb4
-rw-r--r--activerecord/test/cases/dirty_test.rb16
-rw-r--r--activerecord/test/cases/finder_test.rb42
-rw-r--r--activerecord/test/cases/fixtures_test.rb16
-rw-r--r--activerecord/test/cases/helper.rb2
-rw-r--r--activerecord/test/cases/invertible_migration_test.rb5
-rw-r--r--activerecord/test/cases/locking_test.rb2
-rw-r--r--activerecord/test/cases/migration/helper.rb4
-rw-r--r--activerecord/test/cases/migration_test.rb7
-rw-r--r--activerecord/test/cases/migrator_test.rb569
-rw-r--r--activerecord/test/cases/relation/merging_test.rb13
-rw-r--r--activerecord/test/cases/relations_test.rb16
-rw-r--r--activerecord/test/cases/test_case.rb2
-rw-r--r--activerecord/test/models/comment.rb1
-rw-r--r--activerecord/test/models/company.rb1
-rw-r--r--activerecord/test/models/developer.rb2
-rw-r--r--activerecord/test/schema/schema.rb1
50 files changed, 668 insertions, 457 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 74f802f3f7..9d6eb6ad21 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,21 @@
+* `default_sequence_name` from the PostgreSQL adapter returns a `String`.
+
+ *Yves Senn*
+
+* Fixed a regression where whitespaces were stripped from DISTINCT queries in
+ PostgreSQL.
+
+ *Agis Anastasopoulos*
+
+ Fixes #16623.
+
+* Fix has_many :through relation merging failing when dynamic conditions are
+ passed as a lambda with an arity of one.
+
+ Fixes #16128.
+
+ *Agis Anastasopoulos*
+
* Fixed the `Relation#exists?` to work with polymorphic associations.
Fixes #15821.
@@ -9,6 +27,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.
@@ -33,7 +52,7 @@
* Fix regression on after_commit that didnt fire when having nested transactions.
- Fixes #16425
+ Fixes #16425.
*arthurnn*
diff --git a/activerecord/RUNNING_UNIT_TESTS.rdoc b/activerecord/RUNNING_UNIT_TESTS.rdoc
index ca1f2fd665..569685bd45 100644
--- a/activerecord/RUNNING_UNIT_TESTS.rdoc
+++ b/activerecord/RUNNING_UNIT_TESTS.rdoc
@@ -32,8 +32,8 @@ defined in +Rakefile+)
== Config File
-If +test/config.yml+ is present, it's parameters are obeyed. Otherwise, the
-parameters in +test/config.example.yml+ are obeyed.
+If +test/config.yml+ is present, then its parameters are obeyed; otherwise, the
+parameters in +test/config.example.yml+ are.
You can override the +connections:+ parameter in either file using the +ARCONN+
(Active Record CONNection) environment variable:
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 945f22d3c8..18da28d480 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -447,9 +447,11 @@ module ActiveRecord
#
# Possible callbacks are: +before_add+, +after_add+, +before_remove+ and +after_remove+.
#
- # Should any of the +before_add+ callbacks throw an exception, the object does not get
- # added to the collection. Same with the +before_remove+ callbacks; if an exception is
- # thrown the object doesn't get removed.
+ # If any of the +before_add+ callbacks throw an exception, the object will not be
+ # added to the collection.
+ #
+ # Similarly, if any of the +before_remove+ callbacks throw an exception, the object
+ # will not be removed from the collection.
#
# == Association extensions
#
@@ -647,7 +649,7 @@ module ActiveRecord
# belongs_to :commenter
# end
#
- # When using nested association, you will not be able to modify the association because there
+ # When using a nested association, you will not be able to modify the association because there
# is not enough information to know what modification to make. For example, if you tried to
# add a <tt>Commenter</tt> in the example above, there would be no way to tell how to set up the
# intermediate <tt>Post</tt> and <tt>Comment</tt> objects.
@@ -717,7 +719,7 @@ module ActiveRecord
# == Eager loading of associations
#
# Eager loading is a way to find objects of a certain class and a number of named associations.
- # This is one of the easiest ways of to prevent the dreaded N+1 problem in which fetching 100
+ # It is one of the easiest ways to prevent the dreaded N+1 problem in which fetching 100
# posts that each need to display their author triggers 101 database queries. Through the
# use of eager loading, the number of queries will be reduced from 101 to 2.
#
@@ -749,16 +751,16 @@ module ActiveRecord
# Post.includes(:author, :comments).each do |post|
#
# This will load all comments with a single query. This reduces the total number of queries
- # to 3. More generally the number of queries will be 1 plus the number of associations
+ # to 3. In general, the number of queries will be 1 plus the number of associations
# named (except if some of the associations are polymorphic +belongs_to+ - see below).
#
# To include a deep hierarchy of associations, use a hash:
#
- # Post.includes(:author, {comments: {author: :gravatar}}).each do |post|
+ # Post.includes(:author, { comments: { author: :gravatar } }).each do |post|
#
- # That'll grab not only all the comments but all their authors and gravatar pictures.
- # You can mix and match symbols, arrays and hashes in any combination to describe the
- # associations you want to load.
+ # The above code will load all the comments and all of their associated
+ # authors and gravatars. You can mix and match any combination of symbols,
+ # arrays, and hashes to retrieve the associations you want to load.
#
# All of this power shouldn't fool you into thinking that you can pull out huge amounts
# of data with no performance penalty just because you've reduced the number of queries.
@@ -767,8 +769,8 @@ module ActiveRecord
# cut down on the number of queries in a situation as the one described above.
#
# Since only one table is loaded at a time, conditions or orders cannot reference tables
- # other than the main one. If this is the case Active Record falls back to the previously
- # used LEFT OUTER JOIN based strategy. For example
+ # other than the main one. If this is the case, Active Record falls back to the previously
+ # used LEFT OUTER JOIN based strategy. For example:
#
# Post.includes([:author, :comments]).where(['comments.approved = ?', true])
#
@@ -1133,6 +1135,31 @@ module ActiveRecord
# * <tt>Firm#clients.create!</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save!</tt>)
# The declaration can also include an +options+ hash to specialize the behavior of the association.
#
+ # === Scopes
+ #
+ # You can pass a second argument +scope+ as a callable (i.e. proc or
+ # lambda) to retrieve a specific set of records or customize the generated
+ # query when you access the associated collection.
+ #
+ # Scope examples:
+ # has_many :comments, -> { where(author_id: 1) }
+ # has_many :employees, -> { joins(:address) }
+ # has_many :posts, ->(post) { where("max_post_length > ?", post.length) }
+ #
+ # === Extensions
+ #
+ # The +extension+ argument allows you to pass a block into a has_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_many :employees 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]
# Specify the class name of the association. Use it only if that name can't be inferred
@@ -1257,6 +1284,17 @@ module ActiveRecord
# * <tt>Account#create_beneficiary</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save; b</tt>)
# * <tt>Account#create_beneficiary!</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save!; b</tt>)
#
+ # === Scopes
+ #
+ # You can pass a second argument +scope+ as a callable (i.e. proc or
+ # lambda) to retrieve a specific record or customize the generated query
+ # when you access the associated object.
+ #
+ # Scope examples:
+ # has_one :author, -> { where(comment_id: 1) }
+ # has_one :employer, -> { joins(:company) }
+ # has_one :dob, ->(dob) { where("Date.new(2000, 01, 01) > ?", dob) }
+ #
# === Options
#
# The declaration can also include an +options+ hash to specialize the behavior of the association.
@@ -1554,6 +1592,33 @@ module ActiveRecord
# * <tt>Developer#projects.create</tt> (similar to <tt>c = Project.new("developer_id" => id); c.save; c</tt>)
# The declaration may include an +options+ hash to specialize the behavior of the association.
#
+ # === Scopes
+ #
+ # You can pass a second argument +scope+ as a callable (i.e. proc or
+ # lambda) to retrieve a specific set of records or customize the generated
+ # query when you access the associated collection.
+ #
+ # Scope examples:
+ # has_and_belongs_to_many :projects, -> { includes :milestones, :manager }
+ # has_and_belongs_to_many :categories, ->(category) {
+ # 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/associations/through_association.rb b/activerecord/lib/active_record/associations/through_association.rb
index 611d471e62..e47e81aa0f 100644
--- a/activerecord/lib/active_record/associations/through_association.rb
+++ b/activerecord/lib/active_record/associations/through_association.rb
@@ -15,7 +15,11 @@ module ActiveRecord
scope = super
reflection.chain.drop(1).each do |reflection|
relation = reflection.klass.all
- relation.merge!(reflection.scope) if reflection.scope
+
+ reflection_scope = reflection.scope
+ if reflection_scope && reflection_scope.arity.zero?
+ relation.merge!(reflection_scope)
+ end
scope.merge!(
relation.except(:select, :create_with, :includes, :preload, :joins, :eager_load)
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 d3f4e51c33..2f02738f6d 100644
--- a/activerecord/lib/active_record/attribute_methods/dirty.rb
+++ b/activerecord/lib/active_record/attribute_methods/dirty.rb
@@ -43,14 +43,6 @@ module ActiveRecord
calculate_changes_from_defaults
end
- def changed?
- super || changed_in_place.any?
- end
-
- def changed
- super | changed_in_place
- end
-
def changes_applied
super
store_original_raw_attributes
@@ -62,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
@@ -165,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/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/connection_adapters/postgresql/oid/uuid.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/uuid.rb
index dd97393eac..033e0324bb 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/uuid.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/uuid.rb
@@ -12,6 +12,8 @@ module ActiveRecord
[a-fA-F0-9]{4}-?
[a-fA-F0-9]{4}-?\}?\z}x
+ alias_method :type_cast_for_database, :type_cast_from_database
+
def type
:uuid
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
index 7042817672..767b6b614a 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
@@ -281,9 +281,9 @@ module ActiveRecord
def default_sequence_name(table_name, pk = nil) #:nodoc:
result = serial_sequence(table_name, pk || 'id')
return nil unless result
- Utils.extract_schema_qualified_name(result)
+ Utils.extract_schema_qualified_name(result).to_s
rescue ActiveRecord::StatementInvalid
- PostgreSQL::Name.new(nil, "#{table_name}_#{pk || 'id'}_seq")
+ PostgreSQL::Name.new(nil, "#{table_name}_#{pk || 'id'}_seq").to_s
end
def serial_sequence(table, column)
@@ -549,7 +549,8 @@ module ActiveRecord
# Convert Arel node to string
s = s.to_sql unless s.is_a?(String)
# Remove any ASC/DESC modifiers
- s.gsub(/\s+(?:ASC|DESC)?\s*(?:NULLS\s+(?:FIRST|LAST)\s*)?/i, '')
+ s.gsub(/\s+(?:ASC|DESC)\b/i, '')
+ .gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, '')
}.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
[super, *order_columns].join(', ')
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 4306b36ae1..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
@@ -870,11 +870,11 @@ module ActiveRecord
def try_to_load_dependency(file_name)
require_dependency file_name
rescue LoadError => e
- # Let's hope the developer has included it
- # Let's warn in case this is a subdependency, otherwise
- # subdependency error messages are totally cryptic
- if ActiveRecord::Base.logger
- ActiveRecord::Base.logger.warn("Unable to load #{file_name}, underlying cause #{e.message} \n\n #{e.backtrace.join("\n")}")
+ unless fixture_class_names.key?(file_name.pluralize)
+ if ActiveRecord::Base.logger
+ ActiveRecord::Base.logger.warn("Unable to load #{file_name}, make sure you added it to ActiveSupport::TestCase.set_fixture_class")
+ ActiveRecord::Base.logger.warn("underlying cause #{e.message} \n\n #{e.backtrace.join("\n")}")
+ end
end
end
diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb
index 659c5e3bbb..d0d9304a36 100644
--- a/activerecord/lib/active_record/migration.rb
+++ b/activerecord/lib/active_record/migration.rb
@@ -161,21 +161,14 @@ module ActiveRecord
# in the <tt>db/migrate/</tt> directory where <tt>timestamp</tt> is the
# UTC formatted date and time that the migration was generated.
#
- # You may then edit the <tt>up</tt> and <tt>down</tt> methods of
- # MyNewMigration.
- #
# There is a special syntactic shortcut to generate migrations that add fields to a table.
#
# rails generate migration add_fieldname_to_tablename fieldname:string
#
# This will generate the file <tt>timestamp_add_fieldname_to_tablename</tt>, which will look like this:
# class AddFieldnameToTablename < ActiveRecord::Migration
- # def up
- # add_column :tablenames, :fieldname, :string
- # end
- #
- # def down
- # remove_column :tablenames, :fieldname
+ # def change
+ # add_column :tablenames, :field, :string
# end
# end
#
@@ -188,9 +181,12 @@ module ActiveRecord
#
# To roll the database back to a previous migration version, use
# <tt>rake db:migrate VERSION=X</tt> where <tt>X</tt> is the version to which
- # you wish to downgrade. If any of the migrations throw an
- # <tt>ActiveRecord::IrreversibleMigration</tt> exception, that step will fail and you'll
- # have some manual work to do.
+ # you wish to downgrade. Alternatively, you can also use the STEP option if you
+ # wish to rollback last few migrations. <tt>rake db:migrate STEP=2</tt> will rollback
+ # the latest two migrations.
+ #
+ # If any of the migrations throw an <tt>ActiveRecord::IrreversibleMigration</tt> exception,
+ # that step will fail and you'll have some manual work to do.
#
# == Database support
#
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index 1547c8e3f4..c0deb76a33 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -38,7 +38,7 @@ module ActiveRecord
ar.aggregate_reflections = ar.aggregate_reflections.merge(name.to_s => reflection)
end
- # \Reflection enables interrogating Active Record classes and objects
+ # \Reflection enables interrogating of Active Record classes and objects
# about their associations and aggregations. This information can,
# for example, be used in a form builder that takes an Active Record object
# and creates input fields for all of the attributes depending on their type
@@ -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..a21c3f1868 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
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/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/adapters/postgresql/postgresql_adapter_test.rb b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
index cfff1f980b..a71c0dfb26 100644
--- a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
@@ -134,18 +134,18 @@ module ActiveRecord
end
def test_default_sequence_name
- assert_equal PostgreSQL::Name.new('public', 'accounts_id_seq'),
+ assert_equal 'public.accounts_id_seq',
@connection.default_sequence_name('accounts', 'id')
- assert_equal PostgreSQL::Name.new('public', 'accounts_id_seq'),
+ assert_equal 'public.accounts_id_seq',
@connection.default_sequence_name('accounts')
end
def test_default_sequence_name_bad_table
- assert_equal PostgreSQL::Name.new(nil, 'zomg_id_seq'),
+ assert_equal 'zomg_id_seq',
@connection.default_sequence_name('zomg', 'id')
- assert_equal PostgreSQL::Name.new(nil, 'zomg_id_seq'),
+ assert_equal 'zomg_id_seq',
@connection.default_sequence_name('zomg')
end
@@ -153,7 +153,7 @@ module ActiveRecord
with_example_table do
pk, seq = @connection.pk_and_sequence_for('ex')
assert_equal 'id', pk
- assert_equal @connection.default_sequence_name('ex', 'id'), seq
+ assert_equal @connection.default_sequence_name('ex', 'id'), seq.to_s
end
end
@@ -161,7 +161,7 @@ module ActiveRecord
with_example_table 'code serial primary key' do
pk, seq = @connection.pk_and_sequence_for('ex')
assert_equal 'code', pk
- assert_equal @connection.default_sequence_name('ex', 'code'), seq
+ assert_equal @connection.default_sequence_name('ex', 'code'), seq.to_s
end
end
@@ -334,6 +334,14 @@ module ActiveRecord
@connection.columns_for_distinct("posts.id", ["posts.created_at desc", "posts.position asc"])
end
+ def test_columns_for_distinct_with_case
+ assert_equal(
+ 'posts.id, CASE WHEN author.is_active THEN UPPER(author.name) ELSE UPPER(author.email) END AS alias_0',
+ @connection.columns_for_distinct('posts.id',
+ ["CASE WHEN author.is_active THEN UPPER(author.name) ELSE UPPER(author.email) END"])
+ )
+ end
+
def test_columns_for_distinct_blank_not_nil_orders
assert_equal "posts.id, posts.created_at AS alias_0",
@connection.columns_for_distinct("posts.id", ["posts.created_at desc", "", " "])
diff --git a/activerecord/test/cases/adapters/postgresql/uuid_test.rb b/activerecord/test/cases/adapters/postgresql/uuid_test.rb
index 66006d718f..6e7920b814 100644
--- a/activerecord/test/cases/adapters/postgresql/uuid_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/uuid_test.rb
@@ -252,5 +252,19 @@ class PostgresqlUUIDTestInverseOf < ActiveRecord::TestCase
comment = post.uuid_comments.create!
assert post.uuid_comments.find(comment.id)
end
+
+ def test_find_with_uuid
+ UuidPost.create!
+ assert_raise ActiveRecord::RecordNotFound do
+ UuidPost.find(123456)
+ end
+
+ end
+
+ def test_find_by_with_uuid
+ UuidPost.create!
+ assert_nil UuidPost.find_by(id: 789)
+ 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 042fdaf0bb..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)
@@ -823,15 +824,20 @@ end
class FixtureLoadingTest < ActiveRecord::TestCase
def test_logs_message_for_failed_dependency_load
- ActiveRecord::TestCase.expects(:require_dependency).with(:does_not_exist).raises(LoadError)
- ActiveRecord::Base.logger.expects(:warn)
- ActiveRecord::TestCase.try_to_load_dependency(:does_not_exist)
+ ActiveRecord::Base.logger.expects(:warn).twice
+ ActiveRecord::TestCase.try_to_load_dependency('does_not_exist')
+ end
+
+ def test_does_not_logs_message_for_dependency_that_has_been_defined_with_set_fixture_class
+ ActiveRecord::TestCase.set_fixture_class unknown_dead_parrots: DeadParrot
+ ActiveRecord::Base.logger.expects(:warn).never
+ ActiveRecord::TestCase.try_to_load_dependency('unknown_dead_parrot')
end
def test_does_not_logs_message_for_successful_dependency_load
- ActiveRecord::TestCase.expects(:require_dependency).with(:works_out_fine)
+ ActiveRecord::TestCase.expects(:require_dependency).with('works_out_fine')
ActiveRecord::Base.logger.expects(:warn).never
- ActiveRecord::TestCase.try_to_load_dependency(:works_out_fine)
+ ActiveRecord::TestCase.try_to_load_dependency('works_out_fine')
end
end
diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb
index e43b796237..209ef597db 100644
--- a/activerecord/test/cases/helper.rb
+++ b/activerecord/test/cases/helper.rb
@@ -117,7 +117,7 @@ end
def enable_uuid_ossp!(connection)
return false unless connection.supports_extensions?
- return true if connection.extension_enabled?('uuid-ossp')
+ return connection.reconnect! if connection.extension_enabled?('uuid-ossp')
connection.enable_extension 'uuid-ossp'
connection.commit_db_transaction
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 f9d1edc340..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
@@ -89,7 +90,7 @@ class MigrationTest < ActiveRecord::TestCase
end
def test_migration_detection_without_schema_migration_table
- ActiveRecord::Base.connection.drop_table :schema_migrations
+ ActiveRecord::Base.connection.drop_table('schema_migrations') if ActiveRecord::Base.connection.table_exists?('schema_migrations')
migrations_path = MIGRATIONS_ROOT + "/valid"
old_path = ActiveRecord::Migrator.migrations_paths
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/relation/merging_test.rb b/activerecord/test/cases/relation/merging_test.rb
index 2b5c2fd5a4..0d537fbfe3 100644
--- a/activerecord/test/cases/relation/merging_test.rb
+++ b/activerecord/test/cases/relation/merging_test.rb
@@ -4,6 +4,7 @@ require 'models/comment'
require 'models/developer'
require 'models/post'
require 'models/project'
+require 'models/rating'
class RelationMergingTest < ActiveRecord::TestCase
fixtures :developers, :comments, :authors, :posts
@@ -144,4 +145,16 @@ class MergingDifferentRelationsTest < ActiveRecord::TestCase
assert_equal ["Mary", "Mary", "Mary", "David"], posts_by_author_name
end
+
+ test "relation merging (using a proc argument)" do
+ dev = Developer.where(name: "Jamis").first
+
+ comment_1 = dev.comments.create!(body: "I'm Jamis", post: Post.first)
+ rating_1 = comment_1.ratings.create!
+
+ comment_2 = dev.comments.create!(body: "I'm John", post: Post.first)
+ comment_2.ratings.create!
+
+ assert_equal dev.ratings, [rating_1]
+ 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/test_case.rb b/activerecord/test/cases/test_case.rb
index 4070216733..eb44c4a83c 100644
--- a/activerecord/test/cases/test_case.rb
+++ b/activerecord/test/cases/test_case.rb
@@ -94,7 +94,7 @@ module ActiveRecord
# instead examining the SQL content.
oracle_ignored = [/^select .*nextval/i, /^SAVEPOINT/, /^ROLLBACK TO/, /^\s*select .* from all_triggers/im, /^\s*select .* from all_constraints/im, /^\s*select .* from all_tab_cols/im]
mysql_ignored = [/^SHOW TABLES/i, /^SHOW FULL FIELDS/, /^SHOW CREATE TABLE /i, /^SHOW VARIABLES /]
- postgresql_ignored = [/^\s*select\b.*\bfrom\b.*pg_namespace\b/im, /^\s*select\b.*\battname\b.*\bfrom\b.*\bpg_attribute\b/im, /^SHOW search_path/i]
+ postgresql_ignored = [/^\s*select\b.*\bfrom\b.*pg_namespace\b/im, /^\s*select tablename\b.*from pg_tables\b/im, /^\s*select\b.*\battname\b.*\bfrom\b.*\bpg_attribute\b/im, /^SHOW search_path/i]
sqlite3_ignored = [/^\s*SELECT name\b.*\bFROM sqlite_master/im]
[oracle_ignored, mysql_ignored, postgresql_ignored, sqlite3_ignored].each do |db_ignored_sql|
diff --git a/activerecord/test/models/comment.rb b/activerecord/test/models/comment.rb
index 15970758db..7a88299d08 100644
--- a/activerecord/test/models/comment.rb
+++ b/activerecord/test/models/comment.rb
@@ -9,6 +9,7 @@ class Comment < ActiveRecord::Base
belongs_to :post, :counter_cache => true
belongs_to :author, polymorphic: true
belongs_to :resource, polymorphic: true
+ belongs_to :developer
has_many :ratings
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).
diff --git a/activerecord/test/models/developer.rb b/activerecord/test/models/developer.rb
index 5bd2f00129..3627cfdd09 100644
--- a/activerecord/test/models/developer.rb
+++ b/activerecord/test/models/developer.rb
@@ -46,6 +46,8 @@ class Developer < ActiveRecord::Base
has_many :audit_logs
has_many :contracts
has_many :firms, :through => :contracts, :source => :firm
+ has_many :comments, ->(developer) { where(body: "I'm #{developer.name}") }
+ has_many :ratings, through: :comments
scope :jamises, -> { where(:name => 'Jamis') }
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 98f2492ef8..0584df87c6 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -198,6 +198,7 @@ ActiveRecord::Schema.define do
t.references :author, polymorphic: true
t.string :resource_id
t.string :resource_type
+ t.integer :developer_id
end
create_table :companies, force: true do |t|