aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/CHANGELOG.md19
-rw-r--r--activerecord/Rakefile2
-rw-r--r--activerecord/lib/active_record/association_relation.rb5
-rw-r--r--activerecord/lib/active_record/associations.rb19
-rw-r--r--activerecord/lib/active_record/associations/association.rb8
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb43
-rw-r--r--activerecord/lib/active_record/associations/collection_proxy.rb25
-rw-r--r--activerecord/lib/active_record/associations/has_many_association.rb2
-rw-r--r--activerecord/lib/active_record/associations/join_dependency.rb12
-rw-r--r--activerecord/lib/active_record/associations/join_dependency/join_part.rb4
-rw-r--r--activerecord/lib/active_record/associations/preloader/association.rb24
-rw-r--r--activerecord/lib/active_record/associations/preloader/collection_association.rb1
-rw-r--r--activerecord/lib/active_record/associations/preloader/singular_association.rb1
-rw-r--r--activerecord/lib/active_record/associations/singular_association.rb12
-rw-r--r--activerecord/lib/active_record/attribute.rb2
-rw-r--r--activerecord/lib/active_record/attribute_methods/primary_key.rb6
-rw-r--r--activerecord/lib/active_record/attribute_methods/read.rb10
-rw-r--r--activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb16
-rw-r--r--activerecord/lib/active_record/attribute_methods/write.rb14
-rw-r--r--activerecord/lib/active_record/autosave_association.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_adapter.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb40
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb16
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb13
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb (renamed from activerecord/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb)19
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb28
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb55
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb6
-rw-r--r--activerecord/lib/active_record/connection_handling.rb2
-rw-r--r--activerecord/lib/active_record/core.rb6
-rw-r--r--activerecord/lib/active_record/dynamic_matchers.rb10
-rw-r--r--activerecord/lib/active_record/fixtures.rb2
-rw-r--r--activerecord/lib/active_record/migration/command_recorder.rb10
-rw-r--r--activerecord/lib/active_record/model_schema.rb25
-rw-r--r--activerecord/lib/active_record/nested_attributes.rb31
-rw-r--r--activerecord/lib/active_record/persistence.rb12
-rw-r--r--activerecord/lib/active_record/querying.rb4
-rw-r--r--activerecord/lib/active_record/reflection.rb25
-rw-r--r--activerecord/lib/active_record/relation.rb9
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb2
-rw-r--r--activerecord/lib/active_record/relation/delegation.rb2
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb6
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder.rb28
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder/case_sensitive_handler.rb21
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder/class_handler.rb6
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb16
-rw-r--r--activerecord/lib/active_record/relation/where_clause_factory.rb2
-rw-r--r--activerecord/lib/active_record/result.rb4
-rw-r--r--activerecord/lib/active_record/statement_cache.rb4
-rw-r--r--activerecord/lib/active_record/table_metadata.rb2
-rw-r--r--activerecord/lib/active_record/tasks/mysql_database_tasks.rb2
-rw-r--r--activerecord/lib/active_record/tasks/postgresql_database_tasks.rb17
-rw-r--r--activerecord/lib/active_record/type.rb4
-rw-r--r--activerecord/lib/active_record/type/type_map.rb6
-rw-r--r--activerecord/lib/active_record/validations/uniqueness.rb32
-rw-r--r--activerecord/test/cases/adapters/mysql2/connection_test.rb21
-rw-r--r--activerecord/test/cases/adapters/postgresql/array_test.rb6
-rw-r--r--activerecord/test/cases/adapters/postgresql/geometric_test.rb12
-rw-r--r--activerecord/test/cases/adapters/postgresql/rename_table_test.rb8
-rw-r--r--activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb6
-rw-r--r--activerecord/test/cases/associations/belongs_to_associations_test.rb6
-rw-r--r--activerecord/test/cases/associations/inverse_associations_test.rb27
-rw-r--r--activerecord/test/cases/attribute_methods/read_test.rb1
-rw-r--r--activerecord/test/cases/attribute_methods_test.rb10
-rw-r--r--activerecord/test/cases/attributes_test.rb6
-rw-r--r--activerecord/test/cases/autosave_association_test.rb2
-rw-r--r--activerecord/test/cases/enum_test.rb40
-rw-r--r--activerecord/test/cases/fixtures_test.rb4
-rw-r--r--activerecord/test/cases/migration/column_attributes_test.rb2
-rw-r--r--activerecord/test/cases/migration/columns_test.rb8
-rw-r--r--activerecord/test/cases/quoting_test.rb8
-rw-r--r--activerecord/test/cases/relation/where_test.rb2
-rw-r--r--activerecord/test/cases/relation_test.rb8
-rw-r--r--activerecord/test/cases/view_test.rb12
-rw-r--r--activerecord/test/fixtures/all/namespaced/accounts.yml2
-rw-r--r--activerecord/test/fixtures/books.yml1
-rw-r--r--activerecord/test/models/book.rb1
-rw-r--r--activerecord/test/schema/schema.rb1
81 files changed, 502 insertions, 412 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 4aa1853bde..3eac34d65e 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,22 @@
+* PostgreSQL array columns will now respect the encoding of strings contained
+ in the array.
+
+ Fixes #26326.
+
+ *Sean Griffin*
+
+* Inverse association instances will now be set before `after_find` or
+ `after_initialize` callbacks are run.
+
+ Fixes #26320.
+
+ *Sean Griffin*
+
+* Remove unnecessarily association load when a `belongs_to` association has already been
+ loaded then the foreign key is changed directly and the record saved.
+
+ *James Coleman*
+
* Remove standardized column types/arguments spaces in schema dump.
*Tim Petricola*
diff --git a/activerecord/Rakefile b/activerecord/Rakefile
index 543ab2eaba..e077d345d6 100644
--- a/activerecord/Rakefile
+++ b/activerecord/Rakefile
@@ -67,7 +67,7 @@ end
|x| x.include?("/adapters/")
} + Dir["test/cases/adapters/#{adapter_short}/**/*_test.rb"]).all? do |file|
sh(Gem.ruby, "-w" ,"-Itest", file)
- end or raise "Failures"
+ end || raise("Failures")
end
end
end
diff --git a/activerecord/lib/active_record/association_relation.rb b/activerecord/lib/active_record/association_relation.rb
index 2da2d968b9..de2d03cd0b 100644
--- a/activerecord/lib/active_record/association_relation.rb
+++ b/activerecord/lib/active_record/association_relation.rb
@@ -29,7 +29,10 @@ module ActiveRecord
private
def exec_queries
- super.each { |r| @association.set_inverse_instance r }
+ super do |r|
+ @association.set_inverse_instance r
+ yield r if block_given?
+ end
end
end
end
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index dc68b01386..dc6fe1640e 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1792,12 +1792,7 @@ module ActiveRecord
# has_and_belongs_to_many :nations, class_name: "Country"
# has_and_belongs_to_many :categories, join_table: "prods_cats"
# has_and_belongs_to_many :categories, -> { readonly }
- def has_and_belongs_to_many(name, scope = nil, options = {}, &extension)
- if scope.is_a?(Hash)
- options = scope
- scope = nil
- end
-
+ def has_and_belongs_to_many(name, scope = nil, **options, &extension)
habtm_reflection = ActiveRecord::Reflection::HasAndBelongsToManyReflection.new(name, scope, options, self)
builder = Builder::HasAndBelongsToMany.new name, self, options
@@ -1815,12 +1810,12 @@ module ActiveRecord
include Module.new {
class_eval <<-RUBY, __FILE__, __LINE__ + 1
- def destroy_associations
- association(:#{middle_reflection.name}).delete_all(:delete_all)
- association(:#{name}).reset
- super
- end
- RUBY
+ def destroy_associations
+ association(:#{middle_reflection.name}).delete_all(:delete_all)
+ association(:#{name}).reset
+ super
+ end
+ RUBY
}
hm_options = {}
diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb
index 8328286805..f506614591 100644
--- a/activerecord/lib/active_record/associations/association.rb
+++ b/activerecord/lib/active_record/associations/association.rb
@@ -173,6 +173,14 @@ module ActiveRecord
set_inverse_instance(record)
end
+ def create(attributes = {}, &block)
+ _create_record(attributes, &block)
+ end
+
+ def create!(attributes = {}, &block)
+ _create_record(attributes, true, &block)
+ end
+
private
def find_target?
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index 0f51b35164..08bd532fb0 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -113,14 +113,6 @@ module ActiveRecord
end
end
- def create(attributes = {}, &block)
- _create_record(attributes, &block)
- end
-
- def create!(attributes = {}, &block)
- _create_record(attributes, true, &block)
- end
-
# Add +records+ to this association. Returns +self+ so method calls may
# be chained. Since << flattens its argument list and inserts each record,
# +push+ and +concat+ behave identically.
@@ -191,31 +183,6 @@ module ActiveRecord
end
end
- # Returns the number of records. If no arguments are given, it counts all
- # columns using SQL. If one argument is given, it counts only the passed
- # column using SQL. If a block is given, it counts the number of records
- # yielding a true value.
- def count(column_name = nil)
- return super if block_given?
- relation = scope
- if association_scope.distinct_value
- # This is needed because 'SELECT count(DISTINCT *)..' is not valid SQL.
- column_name ||= reflection.klass.primary_key
- relation = relation.distinct
- end
-
- value = relation.count(column_name)
-
- limit = options[:limit]
- offset = options[:offset]
-
- if limit || offset
- [ [value - offset.to_i, 0].max, limit.to_i ].min
- else
- value
- end
- end
-
# Removes +records+ from this association calling +before_remove+ and
# +after_remove+ callbacks.
#
@@ -260,9 +227,9 @@ module ActiveRecord
else
target.size
end
- elsif !loaded? && !association_scope.group_values.empty?
+ elsif !association_scope.group_values.empty?
load_target.size
- elsif !loaded? && !association_scope.distinct_value && target.is_a?(Array)
+ elsif !association_scope.distinct_value && target.is_a?(Array)
unsaved_records = target.select(&:new_record?)
unsaved_records.size + count_records
else
@@ -390,9 +357,9 @@ module ActiveRecord
end
binds = AssociationScope.get_bind_values(owner, reflection.chain)
- records = sc.execute(binds, klass, conn)
- records.each { |record| set_inverse_instance(record) }
- records
+ sc.execute(binds, klass, conn) do |record|
+ set_inverse_instance(record)
+ end
end
# We have some records loaded from the database (persisted) and some that are
diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb
index 48436155ce..dda240585e 100644
--- a/activerecord/lib/active_record/associations/collection_proxy.rb
+++ b/activerecord/lib/active_record/associations/collection_proxy.rb
@@ -743,6 +743,20 @@ module ActiveRecord
end
alias uniq distinct
+ def calculate(operation, column_name)
+ null_scope? ? scope.calculate(operation, column_name) : super
+ end
+
+ def pluck(*column_names)
+ null_scope? ? scope.pluck(*column_names) : super
+ end
+
+ ##
+ # :method: count
+ #
+ # :call-seq:
+ # count(column_name = nil, &block)
+ #
# Count all records.
#
# class Person < ActiveRecord::Base
@@ -762,17 +776,6 @@ module ActiveRecord
# perform the count using Ruby.
#
# person.pets.count { |pet| pet.name.include?('-') } # => 2
- def count(column_name = nil, &block)
- @association.count(column_name, &block)
- end
-
- def calculate(operation, column_name)
- null_scope? ? scope.calculate(operation, column_name) : super
- end
-
- def pluck(*column_names)
- null_scope? ? scope.pluck(*column_names) : super
- end
# Returns the size of the collection. If the collection hasn't been loaded,
# it executes a <tt>SELECT COUNT(*)</tt> query. Else it calls <tt>collection.size</tt>.
diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb
index 6720578b2c..d1d0cc4c49 100644
--- a/activerecord/lib/active_record/associations/has_many_association.rb
+++ b/activerecord/lib/active_record/associations/has_many_association.rb
@@ -80,7 +80,7 @@ module ActiveRecord
# If there's nothing in the database and @target has no new records
# we are certain the current target is an empty array. This is a
# documented side-effect of the method that may avoid an extra SELECT.
- @target ||= [] and loaded! if count == 0
+ (@target ||= []) && loaded! if count == 0
[association_scope.limit_value, count].compact.min
end
diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb
index 62acad0eda..c26c469c1e 100644
--- a/activerecord/lib/active_record/associations/join_dependency.rb
+++ b/activerecord/lib/active_record/associations/join_dependency.rb
@@ -228,8 +228,8 @@ module ActiveRecord
end
def find_reflection(klass, name)
- klass._reflect_on_association(name) or
- raise ConfigurationError, "Can't join '#{ klass.name }' to association named '#{ name }'; perhaps you misspelled it?"
+ klass._reflect_on_association(name) ||
+ raise(ConfigurationError, "Can't join '#{klass.name}' to association named '#{name}'; perhaps you misspelled it?")
end
def build(associations, base_klass)
@@ -286,17 +286,19 @@ module ActiveRecord
end
def construct_model(record, node, row, model_cache, id, aliases)
- model = model_cache[node][id] ||= node.instantiate(row,
- aliases.column_aliases(node))
other = record.association(node.reflection.name)
+ model = model_cache[node][id] ||=
+ node.instantiate(row, aliases.column_aliases(node)) do |m|
+ other.set_inverse_instance(m)
+ end
+
if node.reflection.collection?
other.target.push(model)
else
other.target = model
end
- other.set_inverse_instance(model)
model
end
end
diff --git a/activerecord/lib/active_record/associations/join_dependency/join_part.rb b/activerecord/lib/active_record/associations/join_dependency/join_part.rb
index 551087f822..61cec5403a 100644
--- a/activerecord/lib/active_record/associations/join_dependency/join_part.rb
+++ b/activerecord/lib/active_record/associations/join_dependency/join_part.rb
@@ -62,8 +62,8 @@ module ActiveRecord
hash
end
- def instantiate(row, aliases)
- base_klass.instantiate(extract_record(row, aliases))
+ def instantiate(row, aliases, &block)
+ base_klass.instantiate(extract_record(row, aliases), &block)
end
end
end
diff --git a/activerecord/lib/active_record/associations/preloader/association.rb b/activerecord/lib/active_record/associations/preloader/association.rb
index 4bb627f399..c79efca920 100644
--- a/activerecord/lib/active_record/associations/preloader/association.rb
+++ b/activerecord/lib/active_record/associations/preloader/association.rb
@@ -28,10 +28,6 @@ module ActiveRecord
end
def records_for(ids)
- query_scope(ids)
- end
-
- def query_scope(ids)
scope.where(association_key_name => ids)
end
@@ -62,7 +58,12 @@ module ActiveRecord
private
def associated_records_by_owner(preloader)
- records = load_records
+ records = load_records do |record|
+ owner = owners_by_key[convert_key(record[association_key_name])]
+ association = owner.association(reflection.name)
+ association.set_inverse_instance(record)
+ end
+
owners.each_with_object({}) do |owner, result|
result[owner] = records[convert_key(owner[owner_key_name])] || []
end
@@ -79,6 +80,15 @@ module ActiveRecord
@owner_keys
end
+ def owners_by_key
+ unless defined?(@owners_by_key)
+ @owners_by_key = owners.each_with_object({}) do |owner, h|
+ h[convert_key(owner[owner_key_name])] = owner
+ end
+ end
+ @owners_by_key
+ end
+
def key_conversion_required?
@key_conversion_required ||= association_key_type != owner_key_type
end
@@ -99,13 +109,13 @@ module ActiveRecord
@model.type_for_attribute(owner_key_name.to_s).type
end
- def load_records
+ def load_records(&block)
return {} if owner_keys.empty?
# Some databases impose a limit on the number of ids in a list (in Oracle it's 1000)
# Make several smaller queries if necessary or make one query if the adapter supports it
slices = owner_keys.each_slice(klass.connection.in_clause_length || owner_keys.size)
@preloaded_records = slices.flat_map do |slice|
- records_for(slice)
+ records_for(slice).load(&block)
end
@preloaded_records.group_by do |record|
convert_key(record[association_key_name])
diff --git a/activerecord/lib/active_record/associations/preloader/collection_association.rb b/activerecord/lib/active_record/associations/preloader/collection_association.rb
index 24b8e01029..26690bf16d 100644
--- a/activerecord/lib/active_record/associations/preloader/collection_association.rb
+++ b/activerecord/lib/active_record/associations/preloader/collection_association.rb
@@ -9,7 +9,6 @@ module ActiveRecord
association = owner.association(reflection.name)
association.loaded!
association.target.concat(records)
- records.each { |record| association.set_inverse_instance(record) }
end
end
end
diff --git a/activerecord/lib/active_record/associations/preloader/singular_association.rb b/activerecord/lib/active_record/associations/preloader/singular_association.rb
index 0888d383a6..5c5828262e 100644
--- a/activerecord/lib/active_record/associations/preloader/singular_association.rb
+++ b/activerecord/lib/active_record/associations/preloader/singular_association.rb
@@ -10,7 +10,6 @@ module ActiveRecord
association = owner.association(reflection.name)
association.target = record
- association.set_inverse_instance(record) if record
end
end
end
diff --git a/activerecord/lib/active_record/associations/singular_association.rb b/activerecord/lib/active_record/associations/singular_association.rb
index 1fe9a23263..e386cc0e4c 100644
--- a/activerecord/lib/active_record/associations/singular_association.rb
+++ b/activerecord/lib/active_record/associations/singular_association.rb
@@ -23,14 +23,6 @@ module ActiveRecord
replace(record)
end
- def create(attributes = {}, &block)
- _create_record(attributes, &block)
- end
-
- def create!(attributes = {}, &block)
- _create_record(attributes, true, &block)
- end
-
def build(attributes = {})
record = build_record(attributes)
yield(record) if block_given?
@@ -56,9 +48,9 @@ module ActiveRecord
end
binds = AssociationScope.get_bind_values(owner, reflection.chain)
- if record = sc.execute(binds, klass, conn).first
+ sc.execute(binds, klass, conn) do |record|
set_inverse_instance record
- end
+ end.first
end
def replace(record)
diff --git a/activerecord/lib/active_record/attribute.rb b/activerecord/lib/active_record/attribute.rb
index 380593e809..0b08c2a39b 100644
--- a/activerecord/lib/active_record/attribute.rb
+++ b/activerecord/lib/active_record/attribute.rb
@@ -187,7 +187,7 @@ module ActiveRecord
class Null < Attribute # :nodoc:
def initialize(name)
- super(name, nil, Type::Value.new)
+ super(name, nil, Type.default_value)
end
def type_cast(*)
diff --git a/activerecord/lib/active_record/attribute_methods/primary_key.rb b/activerecord/lib/active_record/attribute_methods/primary_key.rb
index 9e99ed8ac1..6243398a52 100644
--- a/activerecord/lib/active_record/attribute_methods/primary_key.rb
+++ b/activerecord/lib/active_record/attribute_methods/primary_key.rb
@@ -130,10 +130,10 @@ module ActiveRecord
return pk unless pk.is_a?(Array)
warn <<-WARNING.strip_heredoc
- WARNING: Active Record does not support composite primary key.
+ WARNING: Active Record does not support composite primary key.
- #{table_name} has composite primary key. Composite primary key is ignored.
- WARNING
+ #{table_name} has composite primary key. Composite primary key is ignored.
+ WARNING
end
end
end
diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb
index 58f82cfd30..131ed8740b 100644
--- a/activerecord/lib/active_record/attribute_methods/read.rb
+++ b/activerecord/lib/active_record/attribute_methods/read.rb
@@ -31,11 +31,11 @@ module ActiveRecord
ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
- def #{temp_method}
- name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
- _read_attribute(name) { |n| missing_attribute(n, caller) }
- end
- STR
+ def #{temp_method}
+ name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
+ _read_attribute(name) { |n| missing_attribute(n, caller) }
+ end
+ STR
generated_attribute_methods.module_eval do
alias_method name, temp_method
diff --git a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
index 2c8e86fbb2..bea1514cdf 100644
--- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
+++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
@@ -94,18 +94,18 @@ module ActiveRecord
cast_type.type == :time &&
time_zone_aware_types.include?(:not_explicitly_configured)
ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc)
- Time columns will become time zone aware in Rails 5.1. This
- still causes `String`s to be parsed as if they were in `Time.zone`,
- and `Time`s to be converted to `Time.zone`.
+ Time columns will become time zone aware in Rails 5.1. This
+ still causes `String`s to be parsed as if they were in `Time.zone`,
+ and `Time`s to be converted to `Time.zone`.
- To keep the old behavior, you must add the following to your initializer:
+ To keep the old behavior, you must add the following to your initializer:
- config.active_record.time_zone_aware_types = [:datetime]
+ config.active_record.time_zone_aware_types = [:datetime]
- To silence this deprecation warning, add the following:
+ To silence this deprecation warning, add the following:
- config.active_record.time_zone_aware_types = [:datetime, :time]
- MESSAGE
+ config.active_record.time_zone_aware_types = [:datetime, :time]
+ MESSAGE
end
result
diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb
index 5822414129..e9d044ef13 100644
--- a/activerecord/lib/active_record/attribute_methods/write.rb
+++ b/activerecord/lib/active_record/attribute_methods/write.rb
@@ -15,13 +15,13 @@ module ActiveRecord
ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
- def __temp__#{safe_name}=(value)
- name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
- write_attribute(name, value)
- end
- alias_method #{(name + '=').inspect}, :__temp__#{safe_name}=
- undef_method :__temp__#{safe_name}=
- STR
+ def __temp__#{safe_name}=(value)
+ name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
+ write_attribute(name, value)
+ end
+ alias_method #{(name + '=').inspect}, :__temp__#{safe_name}=
+ undef_method :__temp__#{safe_name}=
+ STR
end
end
diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb
index 6e6620aad5..db84876b0a 100644
--- a/activerecord/lib/active_record/autosave_association.rb
+++ b/activerecord/lib/active_record/autosave_association.rb
@@ -457,7 +457,9 @@ module ActiveRecord
# In addition, it will destroy the association if it was marked for destruction.
def save_belongs_to_association(reflection)
association = association_instance_get(reflection.name)
- record = association && association.load_target
+ return unless association && association.loaded? && !association.stale_target?
+
+ record = association.load_target
if record && !record.destroyed?
autosave = reflection.options[:autosave]
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
index 45d782e45e..0bd5ec4b26 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -970,8 +970,8 @@ module ActiveRecord
end
def foreign_key_for!(from_table, options_or_to_table = {}) # :nodoc:
- foreign_key_for(from_table, options_or_to_table) or \
- raise ArgumentError, "Table '#{from_table}' has no foreign key for #{options_or_to_table}"
+ foreign_key_for(from_table, options_or_to_table) || \
+ raise(ArgumentError, "Table '#{from_table}' has no foreign key for #{options_or_to_table}")
end
def foreign_key_column_for(table_name) # :nodoc:
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index 4dde525ebc..0c7197a002 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -433,16 +433,16 @@ module ActiveRecord
@connection
end
- def case_sensitive_comparison(attribute, column, value) # :nodoc:
- attribute.eq(value)
+ def case_sensitive_comparison(table, attribute, column, value)
+ table[attribute].eq(Arel::Nodes::BindParam.new)
end
- def case_insensitive_comparison(attribute, column, value) # :nodoc:
+ def case_insensitive_comparison(table, attribute, column, value)
if can_perform_case_insensitive_comparison_for?(column)
- value = attribute.relation.lower(value)
- attribute = attribute.lower
+ table[attribute].lower.eq(table.lower(Arel::Nodes::BindParam.new))
+ else
+ table[attribute].eq(Arel::Nodes::BindParam.new)
end
- attribute.eq(value)
end
def can_perform_case_insensitive_comparison_for?(column)
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
index 3a28879c15..d0ea1ce0cf 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -570,22 +570,23 @@ module ActiveRecord
# Maps logical Rails types to MySQL-specific data types.
def type_to_sql(type, limit = nil, precision = nil, scale = nil, unsigned = nil)
- sql = case type.to_s
- when "integer"
- integer_to_sql(limit)
- when "text"
- text_to_sql(limit)
- when "blob"
- binary_to_sql(limit)
- when "binary"
- if (0..0xfff) === limit
- "varbinary(#{limit})"
- else
- binary_to_sql(limit)
- end
- else
- super(type, limit, precision, scale)
- end
+ sql = \
+ case type.to_s
+ when "integer"
+ integer_to_sql(limit)
+ when "text"
+ text_to_sql(limit)
+ when "blob"
+ binary_to_sql(limit)
+ when "binary"
+ if (0..0xfff) === limit
+ "varbinary(#{limit})"
+ else
+ binary_to_sql(limit)
+ end
+ else
+ super(type, limit, precision, scale)
+ end
sql << " unsigned" if unsigned && type != :primary_key
sql
@@ -613,11 +614,12 @@ module ActiveRecord
SQL
end
- def case_sensitive_comparison(attribute, column, value) # :nodoc:
+ def case_sensitive_comparison(table, attribute, column, value)
if column.collation && !column.case_sensitive?
- value = Arel::Nodes::Bin.new(value)
+ table[attribute].eq(Arel::Nodes::Bin.new(Arel::Nodes::BindParam.new))
+ else
+ super
end
- attribute.eq(value)
end
def can_perform_case_insensitive_comparison_for?(column)
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb b/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb
index c8238eb266..56800f7590 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb
@@ -24,11 +24,9 @@ module ActiveRecord
# Executes the SQL statement in the context of this connection.
def execute(sql, name = nil)
- if @connection
- # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
- # made since we established the connection
- @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
- end
+ # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
+ # made since we established the connection
+ @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
super
end
@@ -71,11 +69,9 @@ module ActiveRecord
end
def exec_stmt_and_free(sql, name, binds, cache_stmt: false)
- if @connection
- # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
- # made since we established the connection
- @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
- end
+ # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
+ # made since we established the connection
+ @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
type_casted_binds = type_casted_binds(binds)
diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
index 0130b4ef62..a3e2c913c5 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
@@ -90,7 +90,6 @@ module ActiveRecord
#++
def active?
- return false unless @connection
@connection.ping
end
@@ -105,10 +104,7 @@ module ActiveRecord
# Otherwise, this method does nothing.
def disconnect!
super
- unless @connection.nil?
- @connection.close
- @connection = nil
- end
+ @connection.close
end
private
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
index 8c318886cf..0e526f6201 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
@@ -12,7 +12,7 @@ require "active_record/connection_adapters/postgresql/oid/json"
require "active_record/connection_adapters/postgresql/oid/jsonb"
require "active_record/connection_adapters/postgresql/oid/money"
require "active_record/connection_adapters/postgresql/oid/point"
-require "active_record/connection_adapters/postgresql/oid/rails_5_1_point"
+require "active_record/connection_adapters/postgresql/oid/legacy_point"
require "active_record/connection_adapters/postgresql/oid/range"
require "active_record/connection_adapters/postgresql/oid/specialized_string"
require "active_record/connection_adapters/postgresql/oid/uuid"
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
index 1a66afb23a..b969503178 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
@@ -33,7 +33,11 @@ module ActiveRecord
def serialize(value)
if value.is_a?(::Array)
- @pg_encoder.encode(type_cast_array(value, :serialize))
+ result = @pg_encoder.encode(type_cast_array(value, :serialize))
+ if encoding = determine_encoding_of_strings(value)
+ result.encode!(encoding)
+ end
+ result
else
super
end
@@ -63,6 +67,13 @@ module ActiveRecord
@subtype.public_send(method, value)
end
end
+
+ def determine_encoding_of_strings(value)
+ case value
+ when ::Array then determine_encoding_of_strings(value.first)
+ when ::String then value.encoding
+ end
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb
index 845ff5b6a9..775eecaf85 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb
@@ -1,10 +1,8 @@
module ActiveRecord
- Point = Struct.new(:x, :y)
-
module ConnectionAdapters
module PostgreSQL
module OID # :nodoc:
- class Rails51Point < Type::Value # :nodoc:
+ class LegacyPoint < Type::Value # :nodoc:
include Type::Helpers::Mutable
def type
@@ -14,23 +12,20 @@ module ActiveRecord
def cast(value)
case value
when ::String
- return if value.blank?
-
if value[0] == "(" && value[-1] == ")"
value = value[1...-1]
end
- x, y = value.split(",")
- build_point(x, y)
+ cast(value.split(","))
when ::Array
- build_point(*value)
+ value.map { |v| Float(v) }
else
value
end
end
def serialize(value)
- if value.is_a?(ActiveRecord::Point)
- "(#{number_for_point(value.x)},#{number_for_point(value.y)})"
+ if value.is_a?(::Array)
+ "(#{number_for_point(value[0])},#{number_for_point(value[1])})"
else
super
end
@@ -41,10 +36,6 @@ module ActiveRecord
def number_for_point(number)
number.to_s.gsub(/\.0$/, "")
end
-
- def build_point(x, y)
- ActiveRecord::Point.new(Float(x), Float(y))
- end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb
index bb4db2564c..7c764e7287 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb
@@ -1,4 +1,6 @@
module ActiveRecord
+ Point = Struct.new(:x, :y)
+
module ConnectionAdapters
module PostgreSQL
module OID # :nodoc:
@@ -12,20 +14,34 @@ module ActiveRecord
def cast(value)
case value
when ::String
+ return if value.blank?
+
if value[0] == "(" && value[-1] == ")"
value = value[1...-1]
end
- cast(value.split(","))
+ x, y = value.split(",")
+ build_point(x, y)
when ::Array
- value.map { |v| Float(v) }
+ build_point(*value)
else
value
end
end
def serialize(value)
- if value.is_a?(::Array)
- "(#{number_for_point(value[0])},#{number_for_point(value[1])})"
+ case value
+ when ActiveRecord::Point
+ "(#{number_for_point(value.x)},#{number_for_point(value.y)})"
+ when ::Array
+ serialize(build_point(*value))
+ else
+ super
+ end
+ end
+
+ def type_cast_for_schema(value)
+ if ActiveRecord::Point === value
+ [value.x, value.y]
else
super
end
@@ -36,6 +52,10 @@ module ActiveRecord
def number_for_point(number)
number.to_s.gsub(/\.0$/, "")
end
+
+ def build_point(x, y)
+ ActiveRecord::Point.new(Float(x), Float(y))
+ end
end
end
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 696f2cd703..29a77580f5 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
@@ -360,7 +360,7 @@ module ActiveRecord
# Resets the sequence of a table's primary key to the maximum value.
def reset_pk_sequence!(table, pk = nil, sequence = nil) #:nodoc:
- unless pk and sequence
+ unless pk && sequence
default_pk, default_sequence = pk_and_sequence_for(table)
pk ||= default_pk
@@ -403,7 +403,7 @@ module ActiveRecord
AND dep.refobjid = '#{quote_table_name(table)}'::regclass
end_sql
- if result.nil? or result.empty?
+ if result.nil? || result.empty?
result = query(<<-end_sql, "SCHEMA")[0]
SELECT attr.attname, nsp.nspname,
CASE
@@ -625,31 +625,32 @@ module ActiveRecord
# Maps logical Rails types to PostgreSQL-specific data types.
def type_to_sql(type, limit = nil, precision = nil, scale = nil, array = nil)
- sql = case type.to_s
- when "binary"
- # PostgreSQL doesn't support limits on binary (bytea) columns.
- # The hard limit is 1GB, because of a 32-bit size field, and TOAST.
- case limit
- when nil, 0..0x3fffffff; super(type)
- else raise(ActiveRecordError, "No binary type has byte size #{limit}.")
- end
- when "text"
- # PostgreSQL doesn't support limits on text columns.
- # The hard limit is 1GB, according to section 8.3 in the manual.
- case limit
- when nil, 0..0x3fffffff; super(type)
- else raise(ActiveRecordError, "The limit on text can be at most 1GB - 1byte.")
- end
- when "integer"
- case limit
- when 1, 2; "smallint"
- when nil, 3, 4; "integer"
- when 5..8; "bigint"
- else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with scale 0 instead.")
- end
- else
- super(type, limit, precision, scale)
- end
+ sql = \
+ case type.to_s
+ when "binary"
+ # PostgreSQL doesn't support limits on binary (bytea) columns.
+ # The hard limit is 1GB, because of a 32-bit size field, and TOAST.
+ case limit
+ when nil, 0..0x3fffffff; super(type)
+ else raise(ActiveRecordError, "No binary type has byte size #{limit}.")
+ end
+ when "text"
+ # PostgreSQL doesn't support limits on text columns.
+ # The hard limit is 1GB, according to section 8.3 in the manual.
+ case limit
+ when nil, 0..0x3fffffff; super(type)
+ else raise(ActiveRecordError, "The limit on text can be at most 1GB - 1byte.")
+ end
+ when "integer"
+ case limit
+ when 1, 2; "smallint"
+ when nil, 3, 4; "integer"
+ when 5..8; "bigint"
+ else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with scale 0 instead.")
+ end
+ else
+ super(type, limit, precision, scale)
+ end
sql << "[]" if array && type != :primary_key
sql
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index bd53123511..03ee0eec5b 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -437,7 +437,7 @@ module ActiveRecord
type_map.fetch(oid, fmod, sql_type) {
warn "unknown OID #{oid}: failed to recognize type of '#{column_name}'. It will be treated as String."
- Type::Value.new.tap do |cast_type|
+ Type.default_value.tap do |cast_type|
type_map.register_type(oid, cast_type)
end
}
@@ -838,8 +838,8 @@ module ActiveRecord
ActiveRecord::Type.register(:json, OID::Json, adapter: :postgresql)
ActiveRecord::Type.register(:jsonb, OID::Jsonb, adapter: :postgresql)
ActiveRecord::Type.register(:money, OID::Money, adapter: :postgresql)
- ActiveRecord::Type.register(:point, OID::Rails51Point, adapter: :postgresql)
- ActiveRecord::Type.register(:legacy_point, OID::Point, adapter: :postgresql)
+ ActiveRecord::Type.register(:point, OID::Point, adapter: :postgresql)
+ ActiveRecord::Type.register(:legacy_point, OID::LegacyPoint, adapter: :postgresql)
ActiveRecord::Type.register(:uuid, OID::Uuid, adapter: :postgresql)
ActiveRecord::Type.register(:vector, OID::Vector, adapter: :postgresql)
ActiveRecord::Type.register(:xml, OID::Xml, adapter: :postgresql)
diff --git a/activerecord/lib/active_record/connection_handling.rb b/activerecord/lib/active_record/connection_handling.rb
index b4cd6cdd38..2ede92feff 100644
--- a/activerecord/lib/active_record/connection_handling.rb
+++ b/activerecord/lib/active_record/connection_handling.rb
@@ -109,7 +109,7 @@ module ActiveRecord
end
def connection_pool
- connection_handler.retrieve_connection_pool(connection_specification_name) or raise ConnectionNotEstablished
+ connection_handler.retrieve_connection_pool(connection_specification_name) || raise(ConnectionNotEstablished)
end
def retrieve_connection
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index aef4761be4..3465b68ac6 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -229,7 +229,7 @@ module ActiveRecord
end
def find_by!(*args) # :nodoc:
- find_by(*args) or raise RecordNotFound.new("Couldn't find #{name}", name)
+ find_by(*args) || raise(RecordNotFound.new("Couldn't find #{name}", name))
end
def initialize_generated_modules # :nodoc:
@@ -366,6 +366,8 @@ module ActiveRecord
self.class.define_attribute_methods
+ yield self if block_given?
+
_run_find_callbacks
_run_initialize_callbacks
@@ -498,7 +500,7 @@ module ActiveRecord
# We check defined?(@attributes) not to issue warnings if the object is
# allocated but not initialized.
inspection = if defined?(@attributes) && @attributes
- self.class.column_names.collect do |name|
+ self.class.attribute_names.collect do |name|
if has_attribute?(name)
"#{name}: #{attribute_for_inspect(name)}"
end
diff --git a/activerecord/lib/active_record/dynamic_matchers.rb b/activerecord/lib/active_record/dynamic_matchers.rb
index fd2fa7410a..bbd8ca2377 100644
--- a/activerecord/lib/active_record/dynamic_matchers.rb
+++ b/activerecord/lib/active_record/dynamic_matchers.rb
@@ -2,7 +2,7 @@ require "active_support/core_ext/regexp"
module ActiveRecord
module DynamicMatchers #:nodoc:
- def respond_to?(name, include_private = false)
+ def respond_to_missing?(name, include_private = false)
if self == Base
super
else
@@ -63,10 +63,10 @@ module ActiveRecord
def define
model.class_eval <<-CODE, __FILE__, __LINE__ + 1
- def self.#{name}(#{signature})
- #{body}
- end
- CODE
+ def self.#{name}(#{signature})
+ #{body}
+ end
+ CODE
end
private
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index 40a9aa2783..8b47fbdbe4 100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -902,7 +902,7 @@ module ActiveRecord
def fixtures(*fixture_set_names)
if fixture_set_names.first == :all
- fixture_set_names = Dir["#{fixture_path}/{**,*}/*.{yml}"]
+ fixture_set_names = Dir["#{fixture_path}/{**,*}/*.{yml}"].uniq
fixture_set_names.map! { |f| f[(fixture_path.to_s.size + 1)..-5] }
else
fixture_set_names = fixture_set_names.flatten.map(&:to_s)
diff --git a/activerecord/lib/active_record/migration/command_recorder.rb b/activerecord/lib/active_record/migration/command_recorder.rb
index 6b2c5d8da5..44ea756028 100644
--- a/activerecord/lib/active_record/migration/command_recorder.rb
+++ b/activerecord/lib/active_record/migration/command_recorder.rb
@@ -92,7 +92,7 @@ module ActiveRecord
send(method, args, &block)
end
- def respond_to?(*args) # :nodoc:
+ def respond_to_missing?(*args) # :nodoc:
super || delegate.respond_to?(*args)
end
@@ -125,10 +125,10 @@ module ActiveRecord
}.each do |cmd, inv|
[[inv, cmd], [cmd, inv]].uniq.each do |method, inverse|
class_eval <<-EOV, __FILE__, __LINE__ + 1
- def invert_#{method}(args, &block) # def invert_create_table(args, &block)
- [:#{inverse}, args, block] # [:drop_table, args, block]
- end # end
- EOV
+ def invert_#{method}(args, &block) # def invert_create_table(args, &block)
+ [:#{inverse}, args, block] # [:drop_table, args, block]
+ end # end
+ EOV
end
end
end
diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb
index 5718e7fdd0..f49f8da2ed 100644
--- a/activerecord/lib/active_record/model_schema.rb
+++ b/activerecord/lib/active_record/model_schema.rb
@@ -268,7 +268,7 @@ module ActiveRecord
def attribute_types # :nodoc:
load_schema
- @attribute_types ||= Hash.new(Type::Value.new)
+ @attribute_types ||= Hash.new(Type.default_value)
end
def yaml_encoder # :nodoc:
@@ -370,7 +370,6 @@ module ActiveRecord
def load_schema!
@columns_hash = connection.schema_cache.columns_hash(table_name).except(*ignored_columns)
@columns_hash.each do |name, column|
- warn_if_deprecated_type(column)
define_attribute(
name,
connection.lookup_cast_type_from_column(column),
@@ -421,28 +420,6 @@ module ActiveRecord
base.table_name
end
end
-
- def warn_if_deprecated_type(column)
- return if attributes_to_define_after_schema_loads.key?(column.name)
- if column.respond_to?(:oid) && column.sql_type.start_with?("point")
- if column.array?
- array_arguments = ", array: true"
- else
- array_arguments = ""
- end
- ActiveSupport::Deprecation.warn(<<-WARNING.strip_heredoc)
- The behavior of the `:point` type will be changing in Rails 5.1 to
- return a `Point` object, rather than an `Array`. If you'd like to
- keep the old behavior, you can add this line to #{name}:
-
- attribute :#{column.name}, :legacy_point#{array_arguments}
-
- If you'd like the new behavior today, you can add this line:
-
- attribute :#{column.name}, :point#{array_arguments}
- WARNING
- end
- end
end
end
end
diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb
index 86f8cb5d26..f0f88b120a 100644
--- a/activerecord/lib/active_record/nested_attributes.rb
+++ b/activerecord/lib/active_record/nested_attributes.rb
@@ -354,13 +354,13 @@ module ActiveRecord
# associations are just regular associations.
def generate_association_writer(association_name, type)
generated_association_methods.module_eval <<-eoruby, __FILE__, __LINE__ + 1
- if method_defined?(:#{association_name}_attributes=)
- remove_method(:#{association_name}_attributes=)
- end
- def #{association_name}_attributes=(attributes)
- assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes)
- end
- eoruby
+ if method_defined?(:#{association_name}_attributes=)
+ remove_method(:#{association_name}_attributes=)
+ end
+ def #{association_name}_attributes=(attributes)
+ assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes)
+ end
+ eoruby
end
end
@@ -519,14 +519,15 @@ module ActiveRecord
# larger than the limit.
def check_record_limit!(limit, attributes_collection)
if limit
- limit = case limit
- when Symbol
- send(limit)
- when Proc
- limit.call
- else
- limit
- end
+ limit = \
+ case limit
+ when Symbol
+ send(limit)
+ when Proc
+ limit.call
+ else
+ limit
+ end
if limit && attributes_collection.size > limit
raise TooManyRecords, "Maximum #{limit} records are allowed. Got #{attributes_collection.size} records instead."
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index dc4af4f390..a04ef2e263 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -63,10 +63,10 @@ module ActiveRecord
#
# See <tt>ActiveRecord::Inheritance#discriminate_class_for_record</tt> to see
# how this "single-table" inheritance mapping is implemented.
- def instantiate(attributes, column_types = {})
+ def instantiate(attributes, column_types = {}, &block)
klass = discriminate_class_for_record(attributes)
attributes = klass.attributes_builder.build_from_database(attributes, column_types)
- klass.allocate.init_with("attributes" => attributes, "new_record" => false)
+ klass.allocate.init_with("attributes" => attributes, "new_record" => false, &block)
end
private
@@ -178,7 +178,7 @@ module ActiveRecord
# and #destroy returns +false+.
# See ActiveRecord::Callbacks for further details.
def destroy
- raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
+ _raise_readonly_record_error if readonly?
destroy_associations
self.class.connection.add_transaction_record(self)
destroy_row if persisted?
@@ -535,7 +535,7 @@ module ActiveRecord
end
def create_or_update(*args)
- raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
+ _raise_readonly_record_error if readonly?
result = new_record? ? _create_record : _update_record(*args)
result != false
end
@@ -577,5 +577,9 @@ module ActiveRecord
def belongs_to_touch_method
:touch
end
+
+ def _raise_readonly_record_error
+ raise ReadOnlyRecord, "#{self.class} is marked as readonly"
+ end
end
end
diff --git a/activerecord/lib/active_record/querying.rb b/activerecord/lib/active_record/querying.rb
index dd7d650207..36689f6559 100644
--- a/activerecord/lib/active_record/querying.rb
+++ b/activerecord/lib/active_record/querying.rb
@@ -35,7 +35,7 @@ module ActiveRecord
#
# Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]
# Post.find_by_sql ["SELECT body FROM comments WHERE author = :user_id OR approved_by = :user_id", { :user_id => user_id }]
- def find_by_sql(sql, binds = [], preparable: nil)
+ def find_by_sql(sql, binds = [], preparable: nil, &block)
result_set = connection.select_all(sanitize_sql(sql), "#{name} Load", binds, preparable: preparable)
column_types = result_set.column_types.dup
columns_hash.each_key { |k| column_types.delete k }
@@ -47,7 +47,7 @@ module ActiveRecord
}
message_bus.instrument("instantiation.active_record", payload) do
- result_set.map { |record| instantiate(record, column_types) }
+ result_set.map { |record| instantiate(record, column_types, &block) }
end
end
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index 8c5e4d042e..9b692f55d2 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -14,18 +14,19 @@ module ActiveRecord
end
def self.create(macro, name, scope, options, ar)
- klass = case macro
- when :composed_of
- AggregateReflection
- when :has_many
- HasManyReflection
- when :has_one
- HasOneReflection
- when :belongs_to
- BelongsToReflection
- else
- raise "Unsupported Macro: #{macro}"
- end
+ klass = \
+ case macro
+ when :composed_of
+ AggregateReflection
+ when :has_many
+ HasManyReflection
+ when :has_one
+ HasOneReflection
+ when :belongs_to
+ BelongsToReflection
+ else
+ raise "Unsupported Macro: #{macro}"
+ end
reflection = klass.new(name, scope, options, ar)
options[:through] ? ThroughReflection.new(reflection) : reflection
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index d7de1032b6..ef629dcb3b 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -243,7 +243,6 @@ module ActiveRecord
# Please see further details in the
# {Active Record Query Interface guide}[http://guides.rubyonrails.org/active_record_querying.html#running-explain].
def explain
- #TODO: Fix for binds.
exec_explain(collecting_queries_for_explain { exec_queries })
end
@@ -562,8 +561,8 @@ module ActiveRecord
# return value is the relation itself, not the records.
#
# Post.where(published: true).load # => #<ActiveRecord::Relation>
- def load
- exec_queries unless loaded?
+ def load(&block)
+ exec_queries(&block) unless loaded?
self
end
@@ -678,8 +677,8 @@ module ActiveRecord
private
- def exec_queries
- @records = eager_loading? ? find_with_associations.freeze : @klass.find_by_sql(arel, bound_attributes).freeze
+ def exec_queries(&block)
+ @records = eager_loading? ? find_with_associations.freeze : @klass.find_by_sql(arel, bound_attributes, &block).freeze
preload = preload_values
preload += includes_values unless eager_loading?
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index b569abc7a8..a796e35261 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -312,7 +312,7 @@ module ActiveRecord
key = group_columns.map { |aliaz, col_name|
column = type_for(col_name) do
calculated_data.column_types.fetch(aliaz) do
- Type::Value.new
+ Type.default_value
end
end
type_cast_calculated_value(row[aliaz], column)
diff --git a/activerecord/lib/active_record/relation/delegation.rb b/activerecord/lib/active_record/relation/delegation.rb
index e1c36982dd..d16de4b06c 100644
--- a/activerecord/lib/active_record/relation/delegation.rb
+++ b/activerecord/lib/active_record/relation/delegation.rb
@@ -108,7 +108,7 @@ module ActiveRecord
end
end
- def respond_to?(method, include_private = false)
+ def respond_to_missing?(method, include_private = false)
super || @klass.respond_to?(method, include_private) ||
arel.respond_to?(method, include_private)
end
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 376867675b..5e580ac865 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -466,9 +466,9 @@ module ActiveRecord
if ActiveRecord::Base === id
id = id.id
ActiveSupport::Deprecation.warn(<<-MSG.squish)
- You are passing an instance of ActiveRecord::Base to `find`.
- Please pass the id of the object by calling `.id`.
- MSG
+ You are passing an instance of ActiveRecord::Base to `find`.
+ Please pass the id of the object by calling `.id`.
+ MSG
end
relation = where(primary_key => id)
diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb
index 29422bf131..780a1ee422 100644
--- a/activerecord/lib/active_record/relation/predicate_builder.rb
+++ b/activerecord/lib/active_record/relation/predicate_builder.rb
@@ -4,7 +4,6 @@ module ActiveRecord
require "active_record/relation/predicate_builder/association_query_handler"
require "active_record/relation/predicate_builder/base_handler"
require "active_record/relation/predicate_builder/basic_object_handler"
- require "active_record/relation/predicate_builder/case_sensitive_handler"
require "active_record/relation/predicate_builder/class_handler"
require "active_record/relation/predicate_builder/polymorphic_array_handler"
require "active_record/relation/predicate_builder/range_handler"
@@ -17,7 +16,6 @@ module ActiveRecord
@handlers = []
register_handler(BasicObject, BasicObjectHandler.new)
- register_handler(CaseSensitiveHandler::Value, CaseSensitiveHandler.new)
register_handler(Class, ClassHandler.new(self))
register_handler(Base, BaseHandler.new(self))
register_handler(Range, RangeHandler.new)
@@ -33,9 +31,9 @@ module ActiveRecord
expand_from_hash(attributes)
end
- def create_binds(attributes, options)
+ def create_binds(attributes)
attributes = convert_dot_notation_to_hash(attributes)
- create_binds_for_hash(attributes, options)
+ create_binds_for_hash(attributes)
end
def self.references(attributes)
@@ -84,14 +82,14 @@ module ActiveRecord
end
end
- def create_binds_for_hash(attributes, options)
+ def create_binds_for_hash(attributes)
result = attributes.dup
binds = []
attributes.each do |column_name, value|
case
when value.is_a?(Hash) && !table.has_column?(column_name)
- attrs, bvs = associated_predicate_builder(column_name).create_binds_for_hash(value, options)
+ attrs, bvs = associated_predicate_builder(column_name).create_binds_for_hash(value)
result[column_name] = attrs
binds += bvs
next
@@ -110,15 +108,11 @@ module ActiveRecord
end
result[column_name] = RangeHandler::RangeWithBinds.new(first, last, value.exclude_end?)
- when can_be_bound?(column_name, value)
- result[column_name] =
- if perform_case_sensitive?(options)
- CaseSensitiveHandler::Value.new(
- Arel::Nodes::BindParam.new, table, options[:case_sensitive])
- else
- Arel::Nodes::BindParam.new
- end
- binds << build_bind_param(column_name, value)
+ else
+ if can_be_bound?(column_name, value)
+ result[column_name] = Arel::Nodes::BindParam.new
+ binds << build_bind_param(column_name, value)
+ end
end
# Find the foreign key when using queries such as:
@@ -170,10 +164,6 @@ module ActiveRecord
end
end
- def perform_case_sensitive?(options)
- options.key?(:case_sensitive)
- end
-
def build_bind_param(column_name, value)
Relation::QueryAttribute.new(column_name.to_s, value, table.type(column_name))
end
diff --git a/activerecord/lib/active_record/relation/predicate_builder/case_sensitive_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/case_sensitive_handler.rb
deleted file mode 100644
index acf0bbd829..0000000000
--- a/activerecord/lib/active_record/relation/predicate_builder/case_sensitive_handler.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-module ActiveRecord
- class PredicateBuilder
- class CaseSensitiveHandler # :nodoc:
- def call(attribute, value)
- value.call(attribute)
- end
-
- class Value < Struct.new(:value, :table, :case_sensitive?) # :nodoc:
- def call(attribute)
- klass = table.send(:klass)
- column = klass.column_for_attribute(attribute.name)
- if case_sensitive?
- klass.connection.case_sensitive_comparison(attribute, column, value)
- else
- klass.connection.case_insensitive_comparison(attribute, column, value)
- end
- end
- end
- end
- end
-end
diff --git a/activerecord/lib/active_record/relation/predicate_builder/class_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/class_handler.rb
index 73ad864765..0a6574fcf1 100644
--- a/activerecord/lib/active_record/relation/predicate_builder/class_handler.rb
+++ b/activerecord/lib/active_record/relation/predicate_builder/class_handler.rb
@@ -18,9 +18,9 @@ module ActiveRecord
def print_deprecation_warning
ActiveSupport::Deprecation.warn(<<-MSG.squish)
- Passing a class as a value in an Active Record query is deprecated and
- will be removed. Pass a string instead.
- MSG
+ Passing a class as a value in an Active Record query is deprecated and
+ will be removed. Pass a string instead.
+ MSG
end
end
end
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index bd41653df0..78570140e5 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -59,11 +59,12 @@ module ActiveRecord
FROZEN_EMPTY_HASH = {}.freeze
Relation::VALUE_METHODS.each do |name|
- method_name = case name
- when *Relation::MULTI_VALUE_METHODS then "#{name}_values"
- when *Relation::SINGLE_VALUE_METHODS then "#{name}_value"
- when *Relation::CLAUSE_METHODS then "#{name}_clause"
- end
+ method_name = \
+ case name
+ when *Relation::MULTI_VALUE_METHODS then "#{name}_values"
+ when *Relation::SINGLE_VALUE_METHODS then "#{name}_value"
+ when *Relation::CLAUSE_METHODS then "#{name}_clause"
+ end
class_eval <<-CODE, __FILE__, __LINE__ + 1
def #{method_name} # def includes_values
get_value(#{name.inspect}) # get_value(:includes)
@@ -80,14 +81,14 @@ module ActiveRecord
limit_bind = Attribute.with_cast_value(
"LIMIT".freeze,
connection.sanitize_limit(limit_value),
- Type::Value.new,
+ Type.default_value,
)
end
if offset_value
offset_bind = Attribute.with_cast_value(
"OFFSET".freeze,
offset_value.to_i,
- Type::Value.new,
+ Type.default_value,
)
end
connection.combine_bind_parameters(
@@ -470,7 +471,6 @@ module ActiveRecord
self.left_outer_joins_values += args
self
end
- alias :left_joins! :left_outer_joins!
# Returns a new relation, which is the result of filtering the current relation
# according to the conditions in the arguments.
diff --git a/activerecord/lib/active_record/relation/where_clause_factory.rb b/activerecord/lib/active_record/relation/where_clause_factory.rb
index 122ab04c00..dc00149130 100644
--- a/activerecord/lib/active_record/relation/where_clause_factory.rb
+++ b/activerecord/lib/active_record/relation/where_clause_factory.rb
@@ -17,7 +17,7 @@ module ActiveRecord
attributes = klass.send(:expand_hash_conditions_for_aggregates, attributes)
attributes.stringify_keys!
- attributes, binds = predicate_builder.create_binds(attributes, other.last || {})
+ attributes, binds = predicate_builder.create_binds(attributes)
parts = predicate_builder.build_from_hash(attributes)
when Arel::Nodes::Node
diff --git a/activerecord/lib/active_record/result.rb b/activerecord/lib/active_record/result.rb
index f5383f4c14..9ed70a9c2b 100644
--- a/activerecord/lib/active_record/result.rb
+++ b/activerecord/lib/active_record/result.rb
@@ -32,8 +32,6 @@ module ActiveRecord
class Result
include Enumerable
- IDENTITY_TYPE = Type::Value.new # :nodoc:
-
attr_reader :columns, :rows, :column_types
def initialize(columns, rows, column_types = {})
@@ -105,7 +103,7 @@ module ActiveRecord
def column_type(name, type_overrides = {})
type_overrides.fetch(name) do
- column_types.fetch(name, IDENTITY_TYPE)
+ column_types.fetch(name, Type.default_value)
end
end
diff --git a/activerecord/lib/active_record/statement_cache.rb b/activerecord/lib/active_record/statement_cache.rb
index fd67032235..d19bb96ede 100644
--- a/activerecord/lib/active_record/statement_cache.rb
+++ b/activerecord/lib/active_record/statement_cache.rb
@@ -99,12 +99,12 @@ module ActiveRecord
@bind_map = bind_map
end
- def execute(params, klass, connection)
+ def execute(params, klass, connection, &block)
bind_values = bind_map.bind params
sql = query_builder.sql_for bind_values, connection
- klass.find_by_sql(sql, bind_values, preparable: true)
+ klass.find_by_sql(sql, bind_values, preparable: true, &block)
end
alias :call :execute
end
diff --git a/activerecord/lib/active_record/table_metadata.rb b/activerecord/lib/active_record/table_metadata.rb
index a2cb3ea1be..58184f3872 100644
--- a/activerecord/lib/active_record/table_metadata.rb
+++ b/activerecord/lib/active_record/table_metadata.rb
@@ -31,7 +31,7 @@ module ActiveRecord
if klass
klass.type_for_attribute(column_name.to_s)
else
- Type::Value.new
+ Type.default_value
end
end
diff --git a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
index c8b89f1fdf..3a5e0b8dfe 100644
--- a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
@@ -105,7 +105,7 @@ module ActiveRecord
GRANT ALL PRIVILEGES ON #{configuration['database']}.*
TO '#{configuration['username']}'@'localhost'
IDENTIFIED BY '#{configuration['password']}' WITH GRANT OPTION;
- SQL
+ SQL
end
def root_configuration_without_database
diff --git a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
index 6eac9af236..a3a9430c03 100644
--- a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
@@ -46,14 +46,15 @@ module ActiveRecord
def structure_dump(filename)
set_psql_env
- search_path = case ActiveRecord::Base.dump_schemas
- when :schema_search_path
- configuration["schema_search_path"]
- when :all
- nil
- when String
- ActiveRecord::Base.dump_schemas
- end
+ search_path = \
+ case ActiveRecord::Base.dump_schemas
+ when :schema_search_path
+ configuration["schema_search_path"]
+ when :all
+ nil
+ when String
+ ActiveRecord::Base.dump_schemas
+ end
args = ["-s", "-x", "-O", "-f", filename]
unless search_path.blank?
diff --git a/activerecord/lib/active_record/type.rb b/activerecord/lib/active_record/type.rb
index 1b2fc1b034..0b48d2186a 100644
--- a/activerecord/lib/active_record/type.rb
+++ b/activerecord/lib/active_record/type.rb
@@ -37,6 +37,10 @@ module ActiveRecord
registry.lookup(*args, adapter: adapter, **kwargs)
end
+ def default_value # :nodoc:
+ @default_value ||= Value.new
+ end
+
private
def current_adapter_name
diff --git a/activerecord/lib/active_record/type/type_map.rb b/activerecord/lib/active_record/type/type_map.rb
index 9618ff8787..7bce82a1ff 100644
--- a/activerecord/lib/active_record/type/type_map.rb
+++ b/activerecord/lib/active_record/type/type_map.rb
@@ -11,7 +11,7 @@ module ActiveRecord
end
def lookup(lookup_key, *args)
- fetch(lookup_key, *args) { default_value }
+ fetch(lookup_key, *args) { Type.default_value }
end
def fetch(lookup_key, *args, &block)
@@ -55,10 +55,6 @@ module ActiveRecord
yield lookup_key, *args
end
end
-
- def default_value
- @default_value ||= ActiveModel::Type::Value.new
- end
end
end
end
diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb
index 08c4b01439..8c4930a81d 100644
--- a/activerecord/lib/active_record/validations/uniqueness.rb
+++ b/activerecord/lib/active_record/validations/uniqueness.rb
@@ -50,7 +50,37 @@ module ActiveRecord
end
def build_relation(klass, attribute, value) # :nodoc:
- klass.unscoped.where!({ attribute => value }, options)
+ if reflection = klass._reflect_on_association(attribute)
+ attribute = reflection.foreign_key
+ value = value.attributes[reflection.klass.primary_key] unless value.nil?
+ end
+
+ if value.nil?
+ return klass.unscoped.where!(attribute => value)
+ end
+
+ # the attribute may be an aliased attribute
+ if klass.attribute_alias?(attribute)
+ attribute = klass.attribute_alias(attribute)
+ end
+
+ attribute_name = attribute.to_s
+
+ table = klass.arel_table
+ column = klass.columns_hash[attribute_name]
+ cast_type = klass.type_for_attribute(attribute_name)
+
+ comparison = if !options[:case_sensitive]
+ # will use SQL LOWER function before comparison, unless it detects a case insensitive collation
+ klass.connection.case_insensitive_comparison(table, attribute, column, value)
+ else
+ klass.connection.case_sensitive_comparison(table, attribute, column, value)
+ end
+ klass.unscoped.tap do |scope|
+ parts = [comparison]
+ binds = [Relation::QueryAttribute.new(attribute_name, value, cast_type)]
+ scope.where_clause += Relation::WhereClause.new(parts, binds)
+ end
end
def scope_relation(record, relation)
diff --git a/activerecord/test/cases/adapters/mysql2/connection_test.rb b/activerecord/test/cases/adapters/mysql2/connection_test.rb
index 9ede57d395..e014229650 100644
--- a/activerecord/test/cases/adapters/mysql2/connection_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/connection_test.rb
@@ -63,6 +63,27 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase
assert @connection.active?
end
+ def test_execute_after_disconnect
+ @connection.disconnect!
+ error = assert_raise(ActiveRecord::StatementInvalid) do
+ @connection.execute("SELECT 1")
+ end
+ assert_match /closed MySQL connection/, error.message
+ end
+
+ def test_quote_after_disconnect
+ @connection.disconnect!
+ error = assert_raise(Mysql2::Error) do
+ @connection.quote("string")
+ end
+ assert_match /closed MySQL connection/, error.message
+ end
+
+ def test_active_after_disconnect
+ @connection.disconnect!
+ assert_equal false, @connection.active?
+ end
+
def test_mysql_connection_collation_is_configured
assert_equal "utf8_unicode_ci", @connection.show_variable("collation_connection")
assert_equal "utf8_general_ci", ARUnit2Model.connection.show_variable("collation_connection")
diff --git a/activerecord/test/cases/adapters/postgresql/array_test.rb b/activerecord/test/cases/adapters/postgresql/array_test.rb
index 60da9d8859..97960b6c51 100644
--- a/activerecord/test/cases/adapters/postgresql/array_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/array_test.rb
@@ -311,6 +311,12 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase
assert_equal ["has already been taken"], e2.errors[:tags], "Should have uniqueness message for tags"
end
+ def test_encoding_arrays_of_utf8_strings
+ string_with_utf8 = "novĂ˝"
+ assert_equal [string_with_utf8], @type.deserialize(@type.serialize([string_with_utf8]))
+ assert_equal [[string_with_utf8]], @type.deserialize(@type.serialize([[string_with_utf8]]))
+ end
+
private
def assert_cycle(field, array)
# test creation
diff --git a/activerecord/test/cases/adapters/postgresql/geometric_test.rb b/activerecord/test/cases/adapters/postgresql/geometric_test.rb
index 27a7467326..a65d4d1ad9 100644
--- a/activerecord/test/cases/adapters/postgresql/geometric_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/geometric_test.rb
@@ -27,22 +27,10 @@ class PostgresqlPointTest < ActiveRecord::PostgreSQLTestCase
t.point :legacy_y, default: [12.2, 13.3]
t.point :legacy_z, default: "(14.4,15.5)"
end
- @connection.create_table("deprecated_points") do |t|
- t.point :x
- end
end
teardown do
@connection.drop_table "postgresql_points", if_exists: true
- @connection.drop_table "deprecated_points", if_exists: true
- end
-
- class DeprecatedPoint < ActiveRecord::Base; end
-
- def test_deprecated_legacy_type
- assert_deprecated do
- DeprecatedPoint.new
- end
end
def test_column
diff --git a/activerecord/test/cases/adapters/postgresql/rename_table_test.rb b/activerecord/test/cases/adapters/postgresql/rename_table_test.rb
index 461353d239..e9e7f717ac 100644
--- a/activerecord/test/cases/adapters/postgresql/rename_table_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/rename_table_test.rb
@@ -26,9 +26,9 @@ class PostgresqlRenameTableTest < ActiveRecord::PostgreSQLTestCase
def num_indices_named(name)
@connection.execute(<<-SQL).values.length
- SELECT 1 FROM "pg_index"
- JOIN "pg_class" ON "pg_index"."indexrelid" = "pg_class"."oid"
- WHERE "pg_class"."relname" = '#{name}'
- SQL
+ SELECT 1 FROM "pg_index"
+ JOIN "pg_class" ON "pg_index"."indexrelid" = "pg_class"."oid"
+ WHERE "pg_class"."relname" = '#{name}'
+ SQL
end
end
diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
index d2f0710cb2..66f9349111 100644
--- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
@@ -431,9 +431,9 @@ module ActiveRecord
def with_example_table(definition = nil, table_name = "ex", &block)
definition ||= <<-SQL
- id integer PRIMARY KEY AUTOINCREMENT,
- number integer
- SQL
+ id integer PRIMARY KEY AUTOINCREMENT,
+ number integer
+ SQL
super(@conn, table_name, definition, &block)
end
end
diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb
index 3f42cb9b9d..2418346d1b 100644
--- a/activerecord/test/cases/associations/belongs_to_associations_test.rb
+++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb
@@ -626,6 +626,12 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
assert_queries(0) { tagging.super_tag }
end
+ def test_dont_find_target_when_saving_foreign_key_after_stale_association_loaded
+ client = Client.create!(name: "Test client", firm_with_basic_id: Firm.find(1))
+ client.firm_id = Firm.create!(name: "Test firm").id
+ assert_queries(1) { client.save! }
+ end
+
def test_field_name_same_as_foreign_key
computer = Computer.find(1)
assert_not_nil computer.developer, ":foreign key == attribute didn't lock up" # '
diff --git a/activerecord/test/cases/associations/inverse_associations_test.rb b/activerecord/test/cases/associations/inverse_associations_test.rb
index 0b23cea420..6fe6ee6783 100644
--- a/activerecord/test/cases/associations/inverse_associations_test.rb
+++ b/activerecord/test/cases/associations/inverse_associations_test.rb
@@ -494,6 +494,33 @@ class InverseHasManyTests < ActiveRecord::TestCase
assert !man.persisted?
end
+
+ def test_inverse_instance_should_be_set_before_find_callbacks_are_run
+ reset_callbacks(Interest, :find) do
+ Interest.after_find { raise unless association(:man).loaded? && man.present? }
+
+ assert Man.first.interests.reload.any?
+ assert Man.includes(:interests).first.interests.any?
+ assert Man.joins(:interests).includes(:interests).first.interests.any?
+ end
+ end
+
+ def test_inverse_instance_should_be_set_before_initialize_callbacks_are_run
+ reset_callbacks(Interest, :initialize) do
+ Interest.after_initialize { raise unless association(:man).loaded? && man.present? }
+
+ assert Man.first.interests.reload.any?
+ assert Man.includes(:interests).first.interests.any?
+ assert Man.joins(:interests).includes(:interests).first.interests.any?
+ end
+ end
+
+ def reset_callbacks(target, type)
+ old_callbacks = target.send(:get_callbacks, type).deep_dup
+ yield
+ ensure
+ target.send(:set_callbacks, type, old_callbacks) if old_callbacks
+ end
end
class InverseBelongsToTests < ActiveRecord::TestCase
diff --git a/activerecord/test/cases/attribute_methods/read_test.rb b/activerecord/test/cases/attribute_methods/read_test.rb
index 2d2ecb4079..074cfe7ffb 100644
--- a/activerecord/test/cases/attribute_methods/read_test.rb
+++ b/activerecord/test/cases/attribute_methods/read_test.rb
@@ -1,5 +1,4 @@
require "cases/helper"
-require "thread"
module ActiveRecord
module AttributeMethods
diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb
index 7a2041937d..993d9f8b94 100644
--- a/activerecord/test/cases/attribute_methods_test.rb
+++ b/activerecord/test/cases/attribute_methods_test.rb
@@ -1003,10 +1003,10 @@ class AttributeMethodsTest < ActiveRecord::TestCase
def privatize(method_signature)
@target.class_eval(<<-private_method, __FILE__, __LINE__ + 1)
- private
- def #{method_signature}
- "I'm private"
- end
- private_method
+ private
+ def #{method_signature}
+ "I'm private"
+ end
+ private_method
end
end
diff --git a/activerecord/test/cases/attributes_test.rb b/activerecord/test/cases/attributes_test.rb
index 7ec1f6f18c..c18851257e 100644
--- a/activerecord/test/cases/attributes_test.rb
+++ b/activerecord/test/cases/attributes_test.rb
@@ -249,5 +249,11 @@ module ActiveRecord
model.foo = "lol"
refute model.changed?
end
+
+ test "attributes not backed by database columns appear in inspect" do
+ inspection = OverloadedType.new.inspect
+
+ assert inspection.include?("non_existent_decimal")
+ end
end
end
diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb
index 7eae2363f8..08df945063 100644
--- a/activerecord/test/cases/autosave_association_test.rb
+++ b/activerecord/test/cases/autosave_association_test.rb
@@ -1,5 +1,6 @@
require "cases/helper"
require "models/bird"
+require "models/post"
require "models/comment"
require "models/company"
require "models/customer"
@@ -11,7 +12,6 @@ require "models/order"
require "models/parrot"
require "models/person"
require "models/pirate"
-require "models/post"
require "models/reader"
require "models/ship"
require "models/ship_part"
diff --git a/activerecord/test/cases/enum_test.rb b/activerecord/test/cases/enum_test.rb
index c2009843f0..b7641fcf32 100644
--- a/activerecord/test/cases/enum_test.rb
+++ b/activerecord/test/cases/enum_test.rb
@@ -18,6 +18,7 @@ class EnumTest < ActiveRecord::TestCase
assert @book.author_visibility_visible?
assert @book.illustrator_visibility_visible?
assert @book.with_medium_font_size?
+ assert @book.medium_to_read?
end
test "query state with strings" do
@@ -26,6 +27,7 @@ class EnumTest < ActiveRecord::TestCase
assert_equal "english", @book.language
assert_equal "visible", @book.author_visibility
assert_equal "visible", @book.illustrator_visibility
+ assert_equal "medium", @book.difficulty
end
test "find via scope" do
@@ -34,6 +36,7 @@ class EnumTest < ActiveRecord::TestCase
assert_equal @book, Book.in_english.first
assert_equal @book, Book.author_visibility_visible.first
assert_equal @book, Book.illustrator_visibility_visible.first
+ assert_equal @book, Book.medium_to_read.first
end
test "find via where with values" do
@@ -422,6 +425,43 @@ class EnumTest < ActiveRecord::TestCase
assert_not @book.in_french?
end
+ test "query state by predicate with custom suffix" do
+ assert @book.medium_to_read?
+ assert_not @book.easy_to_read?
+ assert_not @book.hard_to_read?
+ end
+
+ test "enum methods with custom suffix defined" do
+ assert @book.class.respond_to?(:easy_to_read)
+ assert @book.class.respond_to?(:medium_to_read)
+ assert @book.class.respond_to?(:hard_to_read)
+
+ assert @book.respond_to?(:easy_to_read?)
+ assert @book.respond_to?(:medium_to_read?)
+ assert @book.respond_to?(:hard_to_read?)
+
+ assert @book.respond_to?(:easy_to_read!)
+ assert @book.respond_to?(:medium_to_read!)
+ assert @book.respond_to?(:hard_to_read!)
+ end
+
+ test "update enum attributes with custom suffix" do
+ @book.medium_to_read!
+ assert_not @book.easy_to_read?
+ assert @book.medium_to_read?
+ assert_not @book.hard_to_read?
+
+ @book.easy_to_read!
+ assert @book.easy_to_read?
+ assert_not @book.medium_to_read?
+ assert_not @book.hard_to_read?
+
+ @book.hard_to_read!
+ assert_not @book.easy_to_read?
+ assert_not @book.medium_to_read?
+ assert @book.hard_to_read?
+ end
+
test "uses default status when no status is provided in fixtures" do
book = books(:tlg)
assert book.proposed?, "expected fixture to default to proposed status"
diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb
index 24a9894f19..66b230d9d2 100644
--- a/activerecord/test/cases/fixtures_test.rb
+++ b/activerecord/test/cases/fixtures_test.rb
@@ -728,7 +728,7 @@ class LoadAllFixturesTest < ActiveRecord::TestCase
self.class.fixtures :all
if File.symlink? FIXTURES_ROOT + "/all/admin"
- assert_equal %w(admin/accounts admin/users developers people tasks), fixture_table_names.sort
+ assert_equal %w(admin/accounts admin/users developers namespaced/accounts people tasks), fixture_table_names.sort
end
ensure
ActiveRecord::FixtureSet.reset_cache
@@ -741,7 +741,7 @@ class LoadAllFixturesWithPathnameTest < ActiveRecord::TestCase
self.class.fixtures :all
if File.symlink? FIXTURES_ROOT + "/all/admin"
- assert_equal %w(admin/accounts admin/users developers people tasks), fixture_table_names.sort
+ assert_equal %w(admin/accounts admin/users developers namespaced/accounts people tasks), fixture_table_names.sort
end
ensure
ActiveRecord::FixtureSet.reset_cache
diff --git a/activerecord/test/cases/migration/column_attributes_test.rb b/activerecord/test/cases/migration/column_attributes_test.rb
index ab8229dbae..03d781d3d2 100644
--- a/activerecord/test/cases/migration/column_attributes_test.rb
+++ b/activerecord/test/cases/migration/column_attributes_test.rb
@@ -63,8 +63,6 @@ module ActiveRecord
# Do a manual insertion
if current_adapter?(:OracleAdapter)
connection.execute "insert into test_models (id, wealth) values (people_seq.nextval, 12345678901234567890.0123456789)"
- elsif current_adapter?(:PostgreSQLAdapter)
- connection.execute "insert into test_models (wealth) values (12345678901234567890.0123456789)"
else
connection.execute "insert into test_models (wealth) values (12345678901234567890.0123456789)"
end
diff --git a/activerecord/test/cases/migration/columns_test.rb b/activerecord/test/cases/migration/columns_test.rb
index 70d40ed87a..870a7f4fa7 100644
--- a/activerecord/test/cases/migration/columns_test.rb
+++ b/activerecord/test/cases/migration/columns_test.rb
@@ -192,8 +192,8 @@ module ActiveRecord
new_columns = connection.columns(TestModel.table_name)
- assert_not new_columns.find { |c| c.name == "age" and c.type == :integer }
- assert new_columns.find { |c| c.name == "age" and c.type == :string }
+ assert_not new_columns.find { |c| c.name == "age" && c.type == :integer }
+ assert new_columns.find { |c| c.name == "age" && c.type == :string }
old_columns = connection.columns(TestModel.table_name)
assert old_columns.find { |c|
@@ -206,11 +206,11 @@ module ActiveRecord
assert_not new_columns.find { |c|
default = connection.lookup_cast_type_from_column(c).deserialize(c.default)
- c.name == "approved" and c.type == :boolean and default == true
+ c.name == "approved" && c.type == :boolean && default == true
}
assert new_columns.find { |c|
default = connection.lookup_cast_type_from_column(c).deserialize(c.default)
- c.name == "approved" and c.type == :boolean and default == false
+ c.name == "approved" && c.type == :boolean && default == false
}
change_column :test_models, :approved, :boolean, default: true
end
diff --git a/activerecord/test/cases/quoting_test.rb b/activerecord/test/cases/quoting_test.rb
index 1c276aa765..296dafacc2 100644
--- a/activerecord/test/cases/quoting_test.rb
+++ b/activerecord/test/cases/quoting_test.rb
@@ -133,16 +133,12 @@ module ActiveRecord
end
def test_quote_string_no_column
- assert_equal "'lo\\\\l'", @quoter.quote('lo\l', nil)
+ assert_equal "'lo\\\\l'", @quoter.quote('lo\l')
end
def test_quote_as_mb_chars_no_column
string = ActiveSupport::Multibyte::Chars.new('lo\l')
- assert_equal "'lo\\\\l'", @quoter.quote(string, nil)
- end
-
- def test_string_with_crazy_column
- assert_equal "'lo\\\\l'", @quoter.quote('lo\l')
+ assert_equal "'lo\\\\l'", @quoter.quote(string)
end
def test_quote_duration
diff --git a/activerecord/test/cases/relation/where_test.rb b/activerecord/test/cases/relation/where_test.rb
index ce4e041793..925af49ffe 100644
--- a/activerecord/test/cases/relation/where_test.rb
+++ b/activerecord/test/cases/relation/where_test.rb
@@ -4,10 +4,10 @@ require "models/binary"
require "models/cake_designer"
require "models/car"
require "models/chef"
+require "models/post"
require "models/comment"
require "models/edge"
require "models/essay"
-require "models/post"
require "models/price_estimate"
require "models/topic"
require "models/treasure"
diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb
index 32b8781a6b..23d27ab90a 100644
--- a/activerecord/test/cases/relation_test.rb
+++ b/activerecord/test/cases/relation_test.rb
@@ -310,10 +310,10 @@ module ActiveRecord
def skip_if_sqlite3_version_includes_quoting_bug
if sqlite3_version_includes_quoting_bug?
skip <<-ERROR.squish
- You are using an outdated version of SQLite3 which has a bug in
- quoted column names. Please update SQLite3 and rebuild the sqlite3
- ruby gem
- ERROR
+ You are using an outdated version of SQLite3 which has a bug in
+ quoted column names. Please update SQLite3 and rebuild the sqlite3
+ ruby gem
+ ERROR
end
end
diff --git a/activerecord/test/cases/view_test.rb b/activerecord/test/cases/view_test.rb
index aa3ff6160c..3cbfbc22c6 100644
--- a/activerecord/test/cases/view_test.rb
+++ b/activerecord/test/cases/view_test.rb
@@ -100,9 +100,9 @@ if ActiveRecord::Base.connection.supports_views?
setup do
@connection = ActiveRecord::Base.connection
@connection.execute <<-SQL
- CREATE VIEW paperbacks
- AS SELECT name, status FROM books WHERE format = 'paperback'
- SQL
+ CREATE VIEW paperbacks
+ AS SELECT name, status FROM books WHERE format = 'paperback'
+ SQL
end
teardown do
@@ -162,9 +162,9 @@ if ActiveRecord::Base.connection.supports_views?
setup do
@connection = ActiveRecord::Base.connection
@connection.execute <<-SQL
- CREATE VIEW printed_books
- AS SELECT id, name, status, format FROM books WHERE format = 'paperback'
- SQL
+ CREATE VIEW printed_books
+ AS SELECT id, name, status, format FROM books WHERE format = 'paperback'
+ SQL
end
teardown do
diff --git a/activerecord/test/fixtures/all/namespaced/accounts.yml b/activerecord/test/fixtures/all/namespaced/accounts.yml
new file mode 100644
index 0000000000..9e341a15af
--- /dev/null
+++ b/activerecord/test/fixtures/all/namespaced/accounts.yml
@@ -0,0 +1,2 @@
+signals37:
+ name: 37signals
diff --git a/activerecord/test/fixtures/books.yml b/activerecord/test/fixtures/books.yml
index a304fba399..b3625ee72e 100644
--- a/activerecord/test/fixtures/books.yml
+++ b/activerecord/test/fixtures/books.yml
@@ -9,6 +9,7 @@ awdr:
author_visibility: :visible
illustrator_visibility: :visible
font_size: :medium
+ difficulty: :medium
rfr:
author_id: 1
diff --git a/activerecord/test/models/book.rb b/activerecord/test/models/book.rb
index 4c275fdebb..17bf3fbcb4 100644
--- a/activerecord/test/models/book.rb
+++ b/activerecord/test/models/book.rb
@@ -14,6 +14,7 @@ class Book < ActiveRecord::Base
enum author_visibility: [:visible, :invisible], _prefix: true
enum illustrator_visibility: [:visible, :invisible], _prefix: true
enum font_size: [:small, :medium, :large], _prefix: :with, _suffix: true
+ enum difficulty: [:easy, :medium, :hard], _suffix: :to_read
enum cover: { hard: "hard", soft: "soft" }
def published!
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 9997ddee77..a4756ec75a 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -98,6 +98,7 @@ ActiveRecord::Schema.define do
t.column :author_visibility, :integer, default: 0
t.column :illustrator_visibility, :integer, default: 0
t.column :font_size, :integer, default: 0
+ t.column :difficulty, :integer, default: 0
t.column :cover, :string, default: "hard"
end