aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/lib/active_record/associations/join_dependency.rb29
-rw-r--r--activerecord/lib/active_record/associations/join_dependency/join_part.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb5
-rw-r--r--activerecord/lib/active_record/integration.rb43
-rw-r--r--activerecord/lib/active_record/nested_attributes.rb2
-rw-r--r--activerecord/lib/active_record/relation.rb2
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb8
-rw-r--r--activerecord/test/cases/associations/inverse_associations_test.rb14
-rw-r--r--activerecord/test/cases/cache_key_test.rb8
-rw-r--r--activerecord/test/cases/integration_test.rb18
-rw-r--r--activerecord/test/cases/migration/references_statements_test.rb8
-rw-r--r--activerecord/test/cases/nested_attributes_test.rb2
-rw-r--r--activerecord/test/cases/relation/mutation_test.rb2
14 files changed, 72 insertions, 75 deletions
diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb
index 8995b1e352..643226267c 100644
--- a/activerecord/lib/active_record/associations/join_dependency.rb
+++ b/activerecord/lib/active_record/associations/join_dependency.rb
@@ -106,12 +106,7 @@ module ActiveRecord
def join_constraints(outer_joins, join_type)
joins = join_root.children.flat_map { |child|
-
- if join_type == Arel::Nodes::OuterJoin
- make_left_outer_joins join_root, child
- else
- make_inner_joins join_root, child
- end
+ make_join_constraints(join_root, child, join_type)
}
joins.concat outer_joins.flat_map { |oj|
@@ -175,27 +170,15 @@ module ActiveRecord
end
def make_outer_joins(parent, child)
- tables = table_aliases_for(parent, child)
- join_type = Arel::Nodes::OuterJoin
- info = make_constraints parent, child, tables, join_type
-
- [info] + child.children.flat_map { |c| make_outer_joins(child, c) }
- end
-
- def make_left_outer_joins(parent, child)
- tables = child.tables
join_type = Arel::Nodes::OuterJoin
- info = make_constraints parent, child, tables, join_type
-
- [info] + child.children.flat_map { |c| make_left_outer_joins(child, c) }
+ make_join_constraints(parent, child, join_type, true)
end
- def make_inner_joins(parent, child)
- tables = child.tables
- join_type = Arel::Nodes::InnerJoin
- info = make_constraints parent, child, tables, join_type
+ def make_join_constraints(parent, child, join_type, aliasing = false)
+ tables = aliasing ? table_aliases_for(parent, child) : child.tables
+ info = make_constraints(parent, child, tables, join_type)
- [info] + child.children.flat_map { |c| make_inner_joins(child, c) }
+ [info] + child.children.flat_map { |c| make_join_constraints(child, c, join_type, aliasing) }
end
def table_aliases_for(parent, node)
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 61cec5403a..80c9fde5d1 100644
--- a/activerecord/lib/active_record/associations/join_dependency/join_part.rb
+++ b/activerecord/lib/active_record/associations/join_dependency/join_part.rb
@@ -22,10 +22,6 @@ module ActiveRecord
@children = children
end
- def name
- reflection.name
- end
-
def match?(other)
self.class == other.class
end
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 46d7f84efd..a30fbe0e05 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -146,7 +146,7 @@ module ActiveRecord
end
def polymorphic_options
- as_options(polymorphic)
+ as_options(polymorphic).merge(null: options[:null])
end
def index_options
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 13629dee7f..16a398f631 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -1280,9 +1280,10 @@ module ActiveRecord
end
def foreign_key_name(table_name, options)
- identifier = "#{table_name}_#{options.fetch(:column)}_fk"
- hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
options.fetch(:name) do
+ identifier = "#{table_name}_#{options.fetch(:column)}_fk"
+ hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
+
"fk_rails_#{hashed_identifier}"
end
end
diff --git a/activerecord/lib/active_record/integration.rb b/activerecord/lib/active_record/integration.rb
index ed652e26aa..441237da1e 100644
--- a/activerecord/lib/active_record/integration.rb
+++ b/activerecord/lib/active_record/integration.rb
@@ -7,8 +7,8 @@ module ActiveRecord
included do
##
# :singleton-method:
- # Indicates the format used to generate the timestamp in the cache key.
- # Accepts any of the symbols in <tt>Time::DATE_FORMATS</tt>.
+ # Indicates the format used to generate the timestamp in the cache key, if
+ # versioning is off. Accepts any of the symbols in <tt>Time::DATE_FORMATS</tt>.
#
# This is +:usec+, by default.
class_attribute :cache_timestamp_format, instance_writer: false
@@ -51,24 +51,16 @@ module ActiveRecord
id && id.to_s # Be sure to stringify the id for routes
end
- # Returns a cache key that can be used to identify this record.
+ # Returns a stable cache key that can be used to identify this record.
#
# Product.new.cache_key # => "products/new"
- # Product.find(5).cache_key # => "products/5" (updated_at not available)
- # Person.find(5).cache_key # => "people/5-20071224150000" (updated_at available)
- #
- # You can also pass a list of named timestamps, and the newest in the list will be
- # used to generate the key:
- #
- # Person.find(5).cache_key(:updated_at, :last_reviewed_at)
+ # Product.find(5).cache_key # => "products/5"
#
- # If ActiveRecord::Base.cache_versioning is turned on, no version will be included
- # in the cache key. The version will instead be supplied by #cache_version. This
- # separation enables recycling of cache keys.
+ # If ActiveRecord::Base.cache_versioning is turned off, as it was in Rails 5.1 and earlier,
+ # the cache key will also include a version.
#
- # Product.cache_versioning = true
- # Product.new.cache_key # => "products/new"
- # Person.find(5).cache_key # => "people/5" (even if updated_at available)
+ # Product.cache_versioning = false
+ # Person.find(5).cache_key # => "people/5-20071224150000" (updated_at available)
def cache_key(*timestamp_names)
if new_record?
"#{model_name.cache_key}/new"
@@ -77,6 +69,11 @@ module ActiveRecord
"#{model_name.cache_key}/#{id}"
else
timestamp = if timestamp_names.any?
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ Specifying a timestamp name for #cache_key has been deprecated in favor of
+ the explicit #cache_version method that can be overwritten.
+ MSG
+
max_updated_column_timestamp(timestamp_names)
else
max_updated_column_timestamp
@@ -99,9 +96,21 @@ module ActiveRecord
# Note, this method will return nil if ActiveRecord::Base.cache_versioning is set to
# +false+ (which it is by default until Rails 6.0).
def cache_version
- try(:updated_at).try(:to_i) if cache_versioning
+ if cache_versioning && timestamp = try(:updated_at)
+ timestamp.utc.to_s(:usec)
+ end
+ end
+
+ # Returns a cache key along with the version.
+ def cache_key_with_version
+ if version = cache_version
+ "#{cache_key}-#{version}"
+ else
+ cache_key
+ end
end
+
module ClassMethods
# Defines your model's +to_param+ method to generate "pretty" URLs
# using +method_name+, which can be any attribute or method that
diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb
index 01ecd79b8f..3f39fb84e8 100644
--- a/activerecord/lib/active_record/nested_attributes.rb
+++ b/activerecord/lib/active_record/nested_attributes.rb
@@ -458,7 +458,7 @@ module ActiveRecord
end
unless attributes_collection.is_a?(Hash) || attributes_collection.is_a?(Array)
- raise ArgumentError, "Hash or Array expected, got #{attributes_collection.class.name} (#{attributes_collection.inspect})"
+ raise ArgumentError, "Hash or Array expected for attribute `#{association_name}`, got #{attributes_collection.class.name} (#{attributes_collection.inspect})"
end
check_record_limit!(options[:limit], attributes_collection)
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 333ad16e11..2d5be32266 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -2,7 +2,7 @@ module ActiveRecord
# = Active Record \Relation
class Relation
MULTI_VALUE_METHODS = [:includes, :eager_load, :preload, :select, :group,
- :order, :joins, :left_joins, :left_outer_joins, :references,
+ :order, :joins, :left_outer_joins, :references,
:extending, :unscope]
SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering,
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 76e529f2de..79e65baae5 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -1100,14 +1100,16 @@ module ActiveRecord
end
VALID_DIRECTIONS = [:asc, :desc, :ASC, :DESC,
- "asc", "desc", "ASC", "DESC"] # :nodoc:
+ "asc", "desc", "ASC", "DESC"].to_set # :nodoc:
def validate_order_args(args)
args.each do |arg|
next unless arg.is_a?(Hash)
arg.each do |_key, value|
- raise ArgumentError, "Direction \"#{value}\" is invalid. Valid " \
- "directions are: #{VALID_DIRECTIONS.inspect}" unless VALID_DIRECTIONS.include?(value)
+ unless VALID_DIRECTIONS.include?(value)
+ raise ArgumentError,
+ "Direction \"#{value}\" is invalid. Valid directions are: #{VALID_DIRECTIONS.to_a.inspect}"
+ end
end
end
end
diff --git a/activerecord/test/cases/associations/inverse_associations_test.rb b/activerecord/test/cases/associations/inverse_associations_test.rb
index 287b3e9ebc..467cc73ecd 100644
--- a/activerecord/test/cases/associations/inverse_associations_test.rb
+++ b/activerecord/test/cases/associations/inverse_associations_test.rb
@@ -651,20 +651,6 @@ class InversePolymorphicBelongsToTests < ActiveRecord::TestCase
assert_equal face.description, new_man.polymorphic_face.description, "Description of face should be the same after changes to replaced-parent-owned instance"
end
- def test_child_instance_should_be_shared_with_replaced_via_method_parent
- face = faces(:confused)
- new_man = Man.new
-
- assert_not_nil face.polymorphic_man
- face.polymorphic_man = new_man
-
- assert_equal face.description, new_man.polymorphic_face.description, "Description of face should be the same before changes to parent instance"
- face.description = "Bongo"
- assert_equal face.description, new_man.polymorphic_face.description, "Description of face should be the same after changes to parent instance"
- new_man.polymorphic_face.description = "Mungo"
- assert_equal face.description, new_man.polymorphic_face.description, "Description of face should be the same after changes to replaced-parent-owned instance"
- end
-
def test_inversed_instance_should_not_be_reloaded_after_stale_state_changed
new_man = Man.new
face = Face.new
diff --git a/activerecord/test/cases/cache_key_test.rb b/activerecord/test/cases/cache_key_test.rb
index f74cb18244..7b8264e6e8 100644
--- a/activerecord/test/cases/cache_key_test.rb
+++ b/activerecord/test/cases/cache_key_test.rb
@@ -39,5 +39,13 @@ module ActiveRecord
assert CacheMeWithVersion.create.cache_version.present?
assert_not CacheMe.create.cache_version.present?
end
+
+ test "cache_key_with_version always has both key and version" do
+ r1 = CacheMeWithVersion.create
+ assert_equal "active_record/cache_key_test/cache_me_with_versions/#{r1.id}-#{r1.updated_at.to_s(:usec)}", r1.cache_key_with_version
+
+ r2 = CacheMe.create
+ assert_equal "active_record/cache_key_test/cache_mes/#{r2.id}-#{r2.updated_at.to_s(:usec)}", r2.cache_key_with_version
+ end
end
end
diff --git a/activerecord/test/cases/integration_test.rb b/activerecord/test/cases/integration_test.rb
index 7ffa86c42f..9104976126 100644
--- a/activerecord/test/cases/integration_test.rb
+++ b/activerecord/test/cases/integration_test.rb
@@ -168,14 +168,18 @@ class IntegrationTest < ActiveRecord::TestCase
end
def test_named_timestamps_for_cache_key
- owner = owners(:blackbeard)
- assert_equal "owners/#{owner.id}-#{owner.happy_at.utc.to_s(:usec)}", owner.cache_key(:updated_at, :happy_at)
+ assert_deprecated do
+ owner = owners(:blackbeard)
+ assert_equal "owners/#{owner.id}-#{owner.happy_at.utc.to_s(:usec)}", owner.cache_key(:updated_at, :happy_at)
+ end
end
def test_cache_key_when_named_timestamp_is_nil
- owner = owners(:blackbeard)
- owner.happy_at = nil
- assert_equal "owners/#{owner.id}", owner.cache_key(:happy_at)
+ assert_deprecated do
+ owner = owners(:blackbeard)
+ owner.happy_at = nil
+ assert_equal "owners/#{owner.id}", owner.cache_key(:happy_at)
+ end
end
def test_cache_key_is_stable_with_versioning_on
@@ -213,13 +217,13 @@ class IntegrationTest < ActiveRecord::TestCase
Developer.cache_versioning = true
developer = Developer.first
- first_key = developer.cache_key(:updated_at)
+ first_key = developer.cache_key_with_version
travel 10.seconds do
developer.touch
end
- second_key = developer.cache_key(:updated_at)
+ second_key = developer.cache_key_with_version
assert_not_equal first_key, second_key
ensure
diff --git a/activerecord/test/cases/migration/references_statements_test.rb b/activerecord/test/cases/migration/references_statements_test.rb
index 06c44c8c52..e9eb9968cb 100644
--- a/activerecord/test/cases/migration/references_statements_test.rb
+++ b/activerecord/test/cases/migration/references_statements_test.rb
@@ -50,6 +50,14 @@ module ActiveRecord
assert column_exists?(table_name, :taggable_type, :string, default: "Photo")
end
+ def test_creates_reference_type_column_with_not_null
+ connection.create_table table_name, force: true do |t|
+ t.references :taggable, null: false, polymorphic: true
+ end
+ assert column_exists?(table_name, :taggable_id, :integer, null: false)
+ assert column_exists?(table_name, :taggable_type, :string, null: false)
+ end
+
def test_does_not_share_options_with_reference_type_column
add_reference table_name, :taggable, type: :integer, limit: 2, polymorphic: true
assert column_exists?(table_name, :taggable_id, :integer, limit: 2)
diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb
index b87419d203..5a62cbd3a6 100644
--- a/activerecord/test/cases/nested_attributes_test.rb
+++ b/activerecord/test/cases/nested_attributes_test.rb
@@ -752,7 +752,7 @@ module NestedAttributesOnACollectionAssociationTests
exception = assert_raise ArgumentError do
@pirate.send(association_setter, "foo")
end
- assert_equal 'Hash or Array expected, got String ("foo")', exception.message
+ assert_equal %{Hash or Array expected for attribute `#{@association_name}`, got String ("foo")}, exception.message
end
def test_should_work_with_update_as_well
diff --git a/activerecord/test/cases/relation/mutation_test.rb b/activerecord/test/cases/relation/mutation_test.rb
index 11ef0d8743..dea787c07f 100644
--- a/activerecord/test/cases/relation/mutation_test.rb
+++ b/activerecord/test/cases/relation/mutation_test.rb
@@ -36,7 +36,7 @@ module ActiveRecord
@relation ||= Relation.new FakeKlass.new("posts"), Post.arel_table, Post.predicate_builder
end
- (Relation::MULTI_VALUE_METHODS - [:references, :extending, :order, :unscope, :select, :left_joins]).each do |method|
+ (Relation::MULTI_VALUE_METHODS - [:references, :extending, :order, :unscope, :select]).each do |method|
test "##{method}!" do
assert relation.public_send("#{method}!", :foo).equal?(relation)
assert_equal [:foo], relation.public_send("#{method}_values")