From a5faf6fb7279ebd1fab92d51bcc705469b7b98d9 Mon Sep 17 00:00:00 2001
From: Brian Abreu <brian@nuts.com>
Date: Tue, 28 Jun 2016 18:32:49 -0700
Subject: Correctly handle frozen options for
 ActiveRecord::Serialization#serializable_hash.

---
 activerecord/lib/active_record/serialization.rb    | 2 +-
 activerecord/test/cases/json_serialization_test.rb | 6 ++----
 2 files changed, 3 insertions(+), 5 deletions(-)

(limited to 'activerecord')

diff --git a/activerecord/lib/active_record/serialization.rb b/activerecord/lib/active_record/serialization.rb
index 5a408e7b8e..db2bd0b55e 100644
--- a/activerecord/lib/active_record/serialization.rb
+++ b/activerecord/lib/active_record/serialization.rb
@@ -9,7 +9,7 @@ module ActiveRecord #:nodoc:
     end
 
     def serializable_hash(options = nil)
-      options = options.try(:clone) || {}
+      options = options.try(:dup) || {}
 
       options[:except] = Array(options[:except]).map(&:to_s)
       options[:except] |= Array(self.class.inheritance_column)
diff --git a/activerecord/test/cases/json_serialization_test.rb b/activerecord/test/cases/json_serialization_test.rb
index a2150483f3..f8120d582b 100644
--- a/activerecord/test/cases/json_serialization_test.rb
+++ b/activerecord/test/cases/json_serialization_test.rb
@@ -149,10 +149,8 @@ class JsonSerializationTest < ActiveRecord::TestCase
   end
 
   def test_serializable_hash_should_not_modify_options_in_argument
-    options = { only: :name }
-    @contact.serializable_hash(options)
-
-    assert_nil options[:except]
+    options = { only: :name }.freeze
+    assert_nothing_raised { @contact.serializable_hash(options) }
   end
 end
 
-- 
cgit v1.2.3


From d3303c31c23e7fdbd9e523c628c111ef6bea0e74 Mon Sep 17 00:00:00 2001
From: Ryuta Kamizono <kamipo@gmail.com>
Date: Thu, 18 May 2017 10:42:26 +0900
Subject: Add a test case for overwriting existing condition on associations

Overwriting existing condition on associations has already supported
(23bcc65 for eager loading, 2bfa2c0 for preloading).

Fixes #27724.
Closes #29154.
---
 .../test/cases/associations/has_many_through_associations_test.rb  | 7 +++++++
 activerecord/test/models/post.rb                                   | 5 +++++
 2 files changed, 12 insertions(+)

(limited to 'activerecord')

diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb
index 1c2138a3d0..a76159fb99 100644
--- a/activerecord/test/cases/associations/has_many_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb
@@ -946,6 +946,13 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
     end
   end
 
+  def test_has_many_through_polymorphic_with_rewhere
+    post = TaggedPost.create!(title: "Tagged", body: "Post")
+    tag = post.tags.create!(name: "Tag")
+    assert_equal [tag], TaggedPost.preload(:tags).last.tags
+    assert_equal [tag], TaggedPost.eager_load(:tags).last.tags
+  end
+
   def test_has_many_through_polymorphic_with_primary_key_option
     assert_equal [categories(:general)], authors(:david).essay_categories
 
diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb
index ed64e0ee52..ada277f3b2 100644
--- a/activerecord/test/models/post.rb
+++ b/activerecord/test/models/post.rb
@@ -199,6 +199,11 @@ class FirstPost < ActiveRecord::Base
   has_one  :comment,  foreign_key: :post_id
 end
 
+class TaggedPost < Post
+  has_many :taggings, -> { rewhere(taggable_type: "TaggedPost") }, as: :taggable
+  has_many :tags, through: :taggings
+end
+
 class PostWithDefaultInclude < ActiveRecord::Base
   self.inheritance_column = :disabled
   self.table_name = "posts"
-- 
cgit v1.2.3


From 006aea643f020250d02673ce49b572c8cfc2dc37 Mon Sep 17 00:00:00 2001
From: Ryuta Kamizono <kamipo@gmail.com>
Date: Thu, 13 Jul 2017 04:31:42 +0900
Subject: Remove extra `.merge!(order: "id")` for `Relation#first` in tests

Since 07e5301, `Relation#first` will order by primary key if no order is
defined.
---
 .../associations/belongs_to_associations_test.rb   |  3 +-
 .../associations/has_many_associations_test.rb     | 57 ++++++++++------------
 2 files changed, 28 insertions(+), 32 deletions(-)

(limited to 'activerecord')

diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb
index a727cc6e60..a7ac291f23 100644
--- a/activerecord/test/cases/associations/belongs_to_associations_test.rb
+++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb
@@ -647,8 +647,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
 
   def test_new_record_with_foreign_key_but_no_object
     client = Client.new("firm_id" => 1)
-    # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first
-    assert_equal Firm.all.merge!(order: "id").first, client.firm_with_basic_id
+    assert_equal Firm.first, client.firm_with_basic_id
   end
 
   def test_setting_foreign_key_after_nil_target_loaded
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index a7e16af88d..2682f256ff 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -497,21 +497,20 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
     assert_predicate person.references, :exists?
   end
 
-  # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first
   def test_counting_with_counter_sql
-    assert_equal 3, Firm.all.merge!(order: "id").first.clients.count
+    assert_equal 3, Firm.first.clients.count
   end
 
   def test_counting
-    assert_equal 3, Firm.all.merge!(order: "id").first.plain_clients.count
+    assert_equal 3, Firm.first.plain_clients.count
   end
 
   def test_counting_with_single_hash
-    assert_equal 1, Firm.all.merge!(order: "id").first.plain_clients.where(name: "Microsoft").count
+    assert_equal 1, Firm.first.plain_clients.where(name: "Microsoft").count
   end
 
   def test_counting_with_column_name_and_hash
-    assert_equal 3, Firm.all.merge!(order: "id").first.plain_clients.count(:name)
+    assert_equal 3, Firm.first.plain_clients.count(:name)
   end
 
   def test_counting_with_association_limit
@@ -521,7 +520,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
   end
 
   def test_finding
-    assert_equal 3, Firm.all.merge!(order: "id").first.clients.length
+    assert_equal 3, Firm.first.clients.length
   end
 
   def test_finding_array_compatibility
@@ -593,27 +592,27 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
   end
 
   def test_finding_default_orders
-    assert_equal "Summit", Firm.all.merge!(order: "id").first.clients.first.name
+    assert_equal "Summit", Firm.first.clients.first.name
   end
 
   def test_finding_with_different_class_name_and_order
-    assert_equal "Apex", Firm.all.merge!(order: "id").first.clients_sorted_desc.first.name
+    assert_equal "Apex", Firm.first.clients_sorted_desc.first.name
   end
 
   def test_finding_with_foreign_key
-    assert_equal "Microsoft", Firm.all.merge!(order: "id").first.clients_of_firm.first.name
+    assert_equal "Microsoft", Firm.first.clients_of_firm.first.name
   end
 
   def test_finding_with_condition
-    assert_equal "Microsoft", Firm.all.merge!(order: "id").first.clients_like_ms.first.name
+    assert_equal "Microsoft", Firm.first.clients_like_ms.first.name
   end
 
   def test_finding_with_condition_hash
-    assert_equal "Microsoft", Firm.all.merge!(order: "id").first.clients_like_ms_with_hash_conditions.first.name
+    assert_equal "Microsoft", Firm.first.clients_like_ms_with_hash_conditions.first.name
   end
 
   def test_finding_using_primary_key
-    assert_equal "Summit", Firm.all.merge!(order: "id").first.clients_using_primary_key.first.name
+    assert_equal "Summit", Firm.first.clients_using_primary_key.first.name
   end
 
   def test_update_all_on_association_accessed_before_save
@@ -636,7 +635,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
   end
 
   def test_find_ids
-    firm = Firm.all.merge!(order: "id").first
+    firm = Firm.first
 
     assert_raise(ActiveRecord::RecordNotFound) { firm.clients.find }
 
@@ -656,7 +655,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
   end
 
   def test_find_one_message_on_primary_key
-    firm = Firm.all.merge!(order: "id").first
+    firm = Firm.first
 
     e = assert_raises(ActiveRecord::RecordNotFound) do
       firm.clients.find(0)
@@ -682,7 +681,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
   end
 
   def test_find_all
-    firm = Firm.all.merge!(order: "id").first
+    firm = Firm.first
     assert_equal 3, firm.clients.where("#{QUOTED_TYPE} = 'Client'").to_a.length
     assert_equal 1, firm.clients.where("name = 'Summit'").to_a.length
   end
@@ -727,29 +726,28 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
   end
 
   def test_find_all_sanitized
-    # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first
-    firm = Firm.all.merge!(order: "id").first
+    firm = Firm.first
     summit = firm.clients.where("name = 'Summit'").to_a
     assert_equal summit, firm.clients.where("name = ?", "Summit").to_a
     assert_equal summit, firm.clients.where("name = :name", name: "Summit").to_a
   end
 
   def test_find_first
-    firm = Firm.all.merge!(order: "id").first
+    firm = Firm.first
     client2 = Client.find(2)
     assert_equal firm.clients.first, firm.clients.order("id").first
     assert_equal client2, firm.clients.where("#{QUOTED_TYPE} = 'Client'").order("id").first
   end
 
   def test_find_first_sanitized
-    firm = Firm.all.merge!(order: "id").first
+    firm = Firm.first
     client2 = Client.find(2)
-    assert_equal client2, firm.clients.merge!(where: ["#{QUOTED_TYPE} = ?", "Client"], order: "id").first
-    assert_equal client2, firm.clients.merge!(where: ["#{QUOTED_TYPE} = :type", { type: "Client" }], order: "id").first
+    assert_equal client2, firm.clients.where("#{QUOTED_TYPE} = ?", "Client").first
+    assert_equal client2, firm.clients.where("#{QUOTED_TYPE} = :type", type: "Client").first
   end
 
   def test_find_first_after_reset_scope
-    firm = Firm.all.merge!(order: "id").first
+    firm = Firm.first
     collection = firm.clients
 
     original_object = collection.first
@@ -760,7 +758,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
   end
 
   def test_find_first_after_reset
-    firm = Firm.all.merge!(order: "id").first
+    firm = Firm.first
     collection = firm.clients
 
     original_object = collection.first
@@ -772,7 +770,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
   end
 
   def test_find_first_after_reload
-    firm = Firm.all.merge!(order: "id").first
+    firm = Firm.first
     collection = firm.clients
 
     original_object = collection.first
@@ -875,7 +873,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
 
   def test_create_with_bang_on_has_many_raises_when_record_not_saved
     assert_raise(ActiveRecord::RecordInvalid) do
-      firm = Firm.all.merge!(order: "id").first
+      firm = Firm.first
       firm.plain_clients.create!
     end
   end
@@ -1557,8 +1555,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
   end
 
   def test_destroy_dependent_when_deleted_from_association
-    # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first
-    firm = Firm.all.merge!(order: "id").first
+    firm = Firm.first
     assert_equal 3, firm.clients.size
 
     client = firm.clients.first
@@ -1668,7 +1665,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
   end
 
   def test_replace_with_less
-    firm = Firm.all.merge!(order: "id").first
+    firm = Firm.first
     firm.clients = [companies(:first_client)]
     assert firm.save, "Could not save firm"
     firm.reload
@@ -1682,7 +1679,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
   end
 
   def test_replace_with_new
-    firm = Firm.all.merge!(order: "id").first
+    firm = Firm.first
     firm.clients = [companies(:second_client), Client.new("name" => "New Client")]
     firm.save
     firm.reload
@@ -2080,7 +2077,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
   end
 
   def test_creating_using_primary_key
-    firm = Firm.all.merge!(order: "id").first
+    firm = Firm.first
     client = firm.clients_using_primary_key.create!(name: "test")
     assert_equal firm.name, client.firm_name
   end
-- 
cgit v1.2.3


From 90bb874ea15a16d3fa363a6f5b2fe7302c913f7b Mon Sep 17 00:00:00 2001
From: "yuuji.yaginuma" <yuuji.yaginuma@gmail.com>
Date: Thu, 13 Jul 2017 07:36:40 +0900
Subject: Fix boolean column migration script

---
 activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb | 2 +-
 activerecord/lib/active_record/railtie.rb                             | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

(limited to 'activerecord')

diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
index b79dbe0733..5174c98c4b 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
@@ -82,7 +82,7 @@ module ActiveRecord
       # Conversion can be accomplished by setting up a rake task which runs
       #
       #   ExampleModel.where("boolean_column = 't'").update_all(boolean_column: 1)
-      #   ExampleModel.where("boolean_column = 't'").update_all(boolean_column: 0)
+      #   ExampleModel.where("boolean_column = 'f'").update_all(boolean_column: 0)
       # for all models and all boolean columns, after which the flag must be set
       # to true by adding the following to your application.rb file:
       #
diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb
index 962ed880b9..9b19e85b33 100644
--- a/activerecord/lib/active_record/railtie.rb
+++ b/activerecord/lib/active_record/railtie.rb
@@ -187,7 +187,7 @@ serialization) before setting this flag to true. Conversion can be accomplished
 by setting up a rake task which runs
 
   ExampleModel.where("boolean_column = 't'").update_all(boolean_column: 1)
-  ExampleModel.where("boolean_column = 't'").update_all(boolean_column: 0)
+  ExampleModel.where("boolean_column = 'f'").update_all(boolean_column: 0)
 
 for all models and all boolean columns, after which the flag must be set to
 true by adding the following to your application.rb file:
-- 
cgit v1.2.3


From 325b3cd6499db1164205198b6e4af90e3d2af865 Mon Sep 17 00:00:00 2001
From: Chris Williams <cswilliams@users.noreply.github.com>
Date: Thu, 13 Jul 2017 17:08:39 -0700
Subject: Catch postgres connection errors when trying to dealloc the statement
 pool

connection_active? will sometimes return true when the connection is actually dead/disconnected (see #3392 for a discussion of why this is).  When this happens, a query is run on the dead connection which causes various postgres connection errors to be raised.  This fix catches any such errors and ignores them.

Closes #29760
---
 activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb | 1 +
 1 file changed, 1 insertion(+)

(limited to 'activerecord')

diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 8baef19030..66c61b5f4a 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -184,6 +184,7 @@ module ActiveRecord
 
           def dealloc(key)
             @connection.query "DEALLOCATE #{key}" if connection_active?
+          rescue PG::Error
           end
 
           def connection_active?
-- 
cgit v1.2.3


From 2992faa45b1b3842e1df30384bba496bb315d09d Mon Sep 17 00:00:00 2001
From: Ryuta Kamizono <kamipo@gmail.com>
Date: Fri, 14 Jul 2017 12:43:00 +0900
Subject: Remove unused `Mutex_m` in Active Model

---
 activerecord/test/cases/attribute_methods/read_test.rb | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

(limited to 'activerecord')

diff --git a/activerecord/test/cases/attribute_methods/read_test.rb b/activerecord/test/cases/attribute_methods/read_test.rb
index 1fc63a49d4..934d5bf8b2 100644
--- a/activerecord/test/cases/attribute_methods/read_test.rb
+++ b/activerecord/test/cases/attribute_methods/read_test.rb
@@ -8,11 +8,10 @@ module ActiveRecord
       end
 
       def setup
-        @klass = Class.new do
+        @klass = Class.new(Class.new { def self.initialize_generated_modules; end }) do
           def self.superclass; Base; end
           def self.base_class; self; end
           def self.decorate_matching_attribute_types(*); end
-          def self.initialize_generated_modules; end
 
           include ActiveRecord::DefineCallbacks
           include ActiveRecord::AttributeMethods
-- 
cgit v1.2.3


From 12e6cba9cf5d2e29438751e0922b27d75da8b0c6 Mon Sep 17 00:00:00 2001
From: Ryuta Kamizono <kamipo@gmail.com>
Date: Fri, 14 Jul 2017 13:26:45 +0900
Subject: Make `generated_attribute_methods` to private

Because `generated_attribute_methods` is an internal API.
---
 activerecord/test/cases/attribute_methods_test.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'activerecord')

diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb
index 4d24a980dc..366577761c 100644
--- a/activerecord/test/cases/attribute_methods_test.rb
+++ b/activerecord/test/cases/attribute_methods_test.rb
@@ -1005,7 +1005,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase
         class_eval(&block)
       end
 
-      assert_empty klass.generated_attribute_methods.instance_methods(false)
+      assert_empty klass.send(:generated_attribute_methods).instance_methods(false)
       klass
     end
 
-- 
cgit v1.2.3


From e9b18724cf6e791b22d940d81ff896b06c94b447 Mon Sep 17 00:00:00 2001
From: Ryuta Kamizono <kamipo@gmail.com>
Date: Sat, 15 Jul 2017 11:29:09 +0900
Subject: Remove useless `aliased_table_name` in `JoinDependency`

If `table.table_alias` is not nil, it is enough to use `table` simply.
---
 activerecord/lib/active_record/associations/join_dependency.rb      | 6 +-----
 .../active_record/associations/join_dependency/join_association.rb  | 4 ----
 .../lib/active_record/associations/join_dependency/join_base.rb     | 4 ----
 .../lib/active_record/associations/join_dependency/join_part.rb     | 5 -----
 4 files changed, 1 insertion(+), 18 deletions(-)

(limited to 'activerecord')

diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb
index 04cdcb6a7f..5c8ecf42b4 100644
--- a/activerecord/lib/active_record/associations/join_dependency.rb
+++ b/activerecord/lib/active_record/associations/join_dependency.rb
@@ -33,12 +33,8 @@ module ActiveRecord
         end
 
         Table = Struct.new(:node, :columns) do # :nodoc:
-          def table
-            Arel::Nodes::TableAlias.new node.table, node.aliased_table_name
-          end
-
           def column_aliases
-            t = table
+            t = node.table
             columns.map { |column| t[column.name].as Arel.sql column.alias }
           end
         end
diff --git a/activerecord/lib/active_record/associations/join_dependency/join_association.rb b/activerecord/lib/active_record/associations/join_dependency/join_association.rb
index b14ddfeeeb..98b2f40357 100644
--- a/activerecord/lib/active_record/associations/join_dependency/join_association.rb
+++ b/activerecord/lib/active_record/associations/join_dependency/join_association.rb
@@ -57,10 +57,6 @@ module ActiveRecord
         def table
           tables.first
         end
-
-        def aliased_table_name
-          table.table_alias || table.name
-        end
       end
     end
   end
diff --git a/activerecord/lib/active_record/associations/join_dependency/join_base.rb b/activerecord/lib/active_record/associations/join_dependency/join_base.rb
index 6e0963425d..f5f22ebfca 100644
--- a/activerecord/lib/active_record/associations/join_dependency/join_base.rb
+++ b/activerecord/lib/active_record/associations/join_dependency/join_base.rb
@@ -12,10 +12,6 @@ module ActiveRecord
         def table
           base_klass.arel_table
         end
-
-        def aliased_table_name
-          base_klass.table_name
-        end
       end
     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 80c9fde5d1..5666e069fc 100644
--- a/activerecord/lib/active_record/associations/join_dependency/join_part.rb
+++ b/activerecord/lib/active_record/associations/join_dependency/join_part.rb
@@ -36,11 +36,6 @@ module ActiveRecord
           raise NotImplementedError
         end
 
-        # The alias for the active_record's table
-        def aliased_table_name
-          raise NotImplementedError
-        end
-
         def extract_record(row, column_names_with_alias)
           # This code is performance critical as it is called per row.
           # see: https://github.com/rails/rails/pull/12185
-- 
cgit v1.2.3


From 8f650d6db83e95a385aeb18571cab34328089cf6 Mon Sep 17 00:00:00 2001
From: Ryuta Kamizono <kamipo@gmail.com>
Date: Sat, 15 Jul 2017 11:59:50 +0900
Subject: Remove outdated `test_scoped_responds_to_delegated_methods`

This test was added at 74ed123 to ensure `respond_to?` delegate methods
to `Array` and `arel_table`. But array method delegation was removed at
9d79334 in favor of including `Enumerable`. And now `Relation` has
`insert`, `update`, and `delete` methods (63480d2, 8d31c9f, d5f9173).
So this delegation test is already outdated.
---
 activerecord/test/cases/relations_test.rb | 8 --------
 1 file changed, 8 deletions(-)

(limited to 'activerecord')

diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index eb3449b331..c77048a756 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -586,14 +586,6 @@ class RelationTest < ActiveRecord::TestCase
     assert_nothing_raised { Topic.reorder([]) }
   end
 
-  def test_scoped_responds_to_delegated_methods
-    relation = Topic.all
-
-    ["map", "uniq", "sort", "insert", "delete", "update"].each do |method|
-      assert_respond_to relation, method, "Topic.all should respond to #{method.inspect}"
-    end
-  end
-
   def test_respond_to_delegates_to_arel
     relation = Topic.all
     fake_arel = Struct.new(:responds) {
-- 
cgit v1.2.3


From f73742455ffd3db0462b18d3d686dbe13a07ee56 Mon Sep 17 00:00:00 2001
From: Ryuta Kamizono <kamipo@gmail.com>
Date: Sat, 15 Jul 2017 22:39:17 +0900
Subject: Extract `NullRelationTest` from `RelationTest`

`test/cases/relations_test.rb` file has too much lines (2000 over).
So I extracted `NullRelationTest` to the dedicated file.
---
 activerecord/test/cases/null_relation_test.rb | 128 ++++++++++++++++++++++++++
 activerecord/test/cases/relations_test.rb     | 118 ------------------------
 2 files changed, 128 insertions(+), 118 deletions(-)
 create mode 100644 activerecord/test/cases/null_relation_test.rb

(limited to 'activerecord')

diff --git a/activerecord/test/cases/null_relation_test.rb b/activerecord/test/cases/null_relation_test.rb
new file mode 100644
index 0000000000..0bb9097495
--- /dev/null
+++ b/activerecord/test/cases/null_relation_test.rb
@@ -0,0 +1,128 @@
+require "cases/helper"
+require "models/aircraft"
+require "models/engine"
+require "models/developer"
+require "models/comment"
+require "models/post"
+require "models/topic"
+
+class NullRelationTest < ActiveRecord::TestCase
+  fixtures :posts, :comments
+
+  def test_none
+    assert_no_queries(ignore_none: false) do
+      assert_equal [], Developer.none
+      assert_equal [], Developer.all.none
+    end
+  end
+
+  def test_none_chainable
+    assert_no_queries(ignore_none: false) do
+      assert_equal [], Developer.none.where(name: "David")
+    end
+  end
+
+  def test_none_chainable_to_existing_scope_extension_method
+    assert_no_queries(ignore_none: false) do
+      assert_equal 1, Topic.anonymous_extension.none.one
+    end
+  end
+
+  def test_none_chained_to_methods_firing_queries_straight_to_db
+    assert_no_queries(ignore_none: false) do
+      assert_equal [],    Developer.none.pluck(:id, :name)
+      assert_equal 0,     Developer.none.delete_all
+      assert_equal 0,     Developer.none.update_all(name: "David")
+      assert_equal 0,     Developer.none.delete(1)
+      assert_equal false, Developer.none.exists?(1)
+    end
+  end
+
+  def test_null_relation_content_size_methods
+    assert_no_queries(ignore_none: false) do
+      assert_equal 0,     Developer.none.size
+      assert_equal 0,     Developer.none.count
+      assert_equal true,  Developer.none.empty?
+      assert_equal true,  Developer.none.none?
+      assert_equal false, Developer.none.any?
+      assert_equal false, Developer.none.one?
+      assert_equal false, Developer.none.many?
+    end
+  end
+
+  def test_null_relation_calculations_methods
+    assert_no_queries(ignore_none: false) do
+      assert_equal 0, Developer.none.count
+      assert_equal 0, Developer.none.calculate(:count, nil)
+      assert_nil Developer.none.calculate(:average, "salary")
+    end
+  end
+
+  def test_null_relation_metadata_methods
+    assert_equal "", Developer.none.to_sql
+    assert_equal({}, Developer.none.where_values_hash)
+  end
+
+  def test_null_relation_where_values_hash
+    assert_equal({ "salary" => 100_000 }, Developer.none.where(salary: 100_000).where_values_hash)
+  end
+
+  def test_null_relation_sum
+    ac = Aircraft.new
+    assert_equal Hash.new, ac.engines.group(:id).sum(:id)
+    assert_equal 0, ac.engines.count
+    ac.save
+    assert_equal Hash.new, ac.engines.group(:id).sum(:id)
+    assert_equal 0, ac.engines.count
+  end
+
+  def test_null_relation_count
+    ac = Aircraft.new
+    assert_equal Hash.new, ac.engines.group(:id).count
+    assert_equal 0, ac.engines.count
+    ac.save
+    assert_equal Hash.new, ac.engines.group(:id).count
+    assert_equal 0, ac.engines.count
+  end
+
+  def test_null_relation_size
+    ac = Aircraft.new
+    assert_equal Hash.new, ac.engines.group(:id).size
+    assert_equal 0, ac.engines.size
+    ac.save
+    assert_equal Hash.new, ac.engines.group(:id).size
+    assert_equal 0, ac.engines.size
+  end
+
+  def test_null_relation_average
+    ac = Aircraft.new
+    assert_equal Hash.new, ac.engines.group(:car_id).average(:id)
+    assert_nil ac.engines.average(:id)
+    ac.save
+    assert_equal Hash.new, ac.engines.group(:car_id).average(:id)
+    assert_nil ac.engines.average(:id)
+  end
+
+  def test_null_relation_minimum
+    ac = Aircraft.new
+    assert_equal Hash.new, ac.engines.group(:car_id).minimum(:id)
+    assert_nil ac.engines.minimum(:id)
+    ac.save
+    assert_equal Hash.new, ac.engines.group(:car_id).minimum(:id)
+    assert_nil ac.engines.minimum(:id)
+  end
+
+  def test_null_relation_maximum
+    ac = Aircraft.new
+    assert_equal Hash.new, ac.engines.group(:car_id).maximum(:id)
+    assert_nil ac.engines.maximum(:id)
+    ac.save
+    assert_equal Hash.new, ac.engines.group(:car_id).maximum(:id)
+    assert_nil ac.engines.maximum(:id)
+  end
+
+  def test_null_relation_in_where_condition
+    assert_operator Comment.count, :>, 0 # precondition, make sure there are comments.
+    assert_equal 0, Comment.where(post_id: Post.none).count
+  end
+end
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index eb3449b331..b91ba8341c 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -15,7 +15,6 @@ require "models/car"
 require "models/engine"
 require "models/tyre"
 require "models/minivan"
-require "models/aircraft"
 require "models/possession"
 require "models/reader"
 require "models/categorization"
@@ -420,123 +419,6 @@ class RelationTest < ActiveRecord::TestCase
     assert_equal [2, 4, 6, 8, 10], even_ids.sort
   end
 
-  def test_none
-    assert_no_queries(ignore_none: false) do
-      assert_equal [], Developer.none
-      assert_equal [], Developer.all.none
-    end
-  end
-
-  def test_none_chainable
-    assert_no_queries(ignore_none: false) do
-      assert_equal [], Developer.none.where(name: "David")
-    end
-  end
-
-  def test_none_chainable_to_existing_scope_extension_method
-    assert_no_queries(ignore_none: false) do
-      assert_equal 1, Topic.anonymous_extension.none.one
-    end
-  end
-
-  def test_none_chained_to_methods_firing_queries_straight_to_db
-    assert_no_queries(ignore_none: false) do
-      assert_equal [],    Developer.none.pluck(:id, :name)
-      assert_equal 0,     Developer.none.delete_all
-      assert_equal 0,     Developer.none.update_all(name: "David")
-      assert_equal 0,     Developer.none.delete(1)
-      assert_equal false, Developer.none.exists?(1)
-    end
-  end
-
-  def test_null_relation_content_size_methods
-    assert_no_queries(ignore_none: false) do
-      assert_equal 0,     Developer.none.size
-      assert_equal 0,     Developer.none.count
-      assert_equal true,  Developer.none.empty?
-      assert_equal true, Developer.none.none?
-      assert_equal false, Developer.none.any?
-      assert_equal false, Developer.none.one?
-      assert_equal false, Developer.none.many?
-    end
-  end
-
-  def test_null_relation_calculations_methods
-    assert_no_queries(ignore_none: false) do
-      assert_equal 0, Developer.none.count
-      assert_equal 0, Developer.none.calculate(:count, nil)
-      assert_nil Developer.none.calculate(:average, "salary")
-    end
-  end
-
-  def test_null_relation_metadata_methods
-    assert_equal "", Developer.none.to_sql
-    assert_equal({}, Developer.none.where_values_hash)
-  end
-
-  def test_null_relation_where_values_hash
-    assert_equal({ "salary" => 100_000 }, Developer.none.where(salary: 100_000).where_values_hash)
-  end
-
-  def test_null_relation_sum
-    ac = Aircraft.new
-    assert_equal Hash.new, ac.engines.group(:id).sum(:id)
-    assert_equal 0, ac.engines.count
-    ac.save
-    assert_equal Hash.new, ac.engines.group(:id).sum(:id)
-    assert_equal 0, ac.engines.count
-  end
-
-  def test_null_relation_count
-    ac = Aircraft.new
-    assert_equal Hash.new, ac.engines.group(:id).count
-    assert_equal 0, ac.engines.count
-    ac.save
-    assert_equal Hash.new, ac.engines.group(:id).count
-    assert_equal 0, ac.engines.count
-  end
-
-  def test_null_relation_size
-    ac = Aircraft.new
-    assert_equal Hash.new, ac.engines.group(:id).size
-    assert_equal 0, ac.engines.size
-    ac.save
-    assert_equal Hash.new, ac.engines.group(:id).size
-    assert_equal 0, ac.engines.size
-  end
-
-  def test_null_relation_average
-    ac = Aircraft.new
-    assert_equal Hash.new, ac.engines.group(:car_id).average(:id)
-    assert_nil ac.engines.average(:id)
-    ac.save
-    assert_equal Hash.new, ac.engines.group(:car_id).average(:id)
-    assert_nil ac.engines.average(:id)
-  end
-
-  def test_null_relation_minimum
-    ac = Aircraft.new
-    assert_equal Hash.new, ac.engines.group(:car_id).minimum(:id)
-    assert_nil ac.engines.minimum(:id)
-    ac.save
-    assert_equal Hash.new, ac.engines.group(:car_id).minimum(:id)
-    assert_nil ac.engines.minimum(:id)
-  end
-
-  def test_null_relation_maximum
-    ac = Aircraft.new
-    assert_equal Hash.new, ac.engines.group(:car_id).maximum(:id)
-    assert_nil ac.engines.maximum(:id)
-    ac.save
-    assert_equal Hash.new, ac.engines.group(:car_id).maximum(:id)
-    assert_nil ac.engines.maximum(:id)
-  end
-
-  def test_null_relation_in_where_condition
-    assert_operator Comment.count, :>, 0 # precondition, make sure there are comments.
-    assert_equal 0, Comment.where(post_id: Post.none).to_a.size
-  end
-
   def test_joins_with_nil_argument
     assert_nothing_raised { DependentFirm.joins(nil).first }
   end
-- 
cgit v1.2.3


From 91565aea80864642fe4ad8e28f4ef8e3aa563d7e Mon Sep 17 00:00:00 2001
From: Ryuta Kamizono <kamipo@gmail.com>
Date: Sat, 15 Jul 2017 23:15:49 +0900
Subject: Ensure calculation methods execute no queries

---
 activerecord/test/cases/null_relation_test.rb | 74 +++++----------------------
 1 file changed, 14 insertions(+), 60 deletions(-)

(limited to 'activerecord')

diff --git a/activerecord/test/cases/null_relation_test.rb b/activerecord/test/cases/null_relation_test.rb
index 0bb9097495..56f5a89686 100644
--- a/activerecord/test/cases/null_relation_test.rb
+++ b/activerecord/test/cases/null_relation_test.rb
@@ -1,6 +1,4 @@
 require "cases/helper"
-require "models/aircraft"
-require "models/engine"
 require "models/developer"
 require "models/comment"
 require "models/post"
@@ -50,14 +48,6 @@ class NullRelationTest < ActiveRecord::TestCase
     end
   end
 
-  def test_null_relation_calculations_methods
-    assert_no_queries(ignore_none: false) do
-      assert_equal 0, Developer.none.count
-      assert_equal 0, Developer.none.calculate(:count, nil)
-      assert_nil Developer.none.calculate(:average, "salary")
-    end
-  end
-
   def test_null_relation_metadata_methods
     assert_equal "", Developer.none.to_sql
     assert_equal({}, Developer.none.where_values_hash)
@@ -67,58 +57,22 @@ class NullRelationTest < ActiveRecord::TestCase
     assert_equal({ "salary" => 100_000 }, Developer.none.where(salary: 100_000).where_values_hash)
   end
 
-  def test_null_relation_sum
-    ac = Aircraft.new
-    assert_equal Hash.new, ac.engines.group(:id).sum(:id)
-    assert_equal 0, ac.engines.count
-    ac.save
-    assert_equal Hash.new, ac.engines.group(:id).sum(:id)
-    assert_equal 0, ac.engines.count
-  end
-
-  def test_null_relation_count
-    ac = Aircraft.new
-    assert_equal Hash.new, ac.engines.group(:id).count
-    assert_equal 0, ac.engines.count
-    ac.save
-    assert_equal Hash.new, ac.engines.group(:id).count
-    assert_equal 0, ac.engines.count
-  end
-
-  def test_null_relation_size
-    ac = Aircraft.new
-    assert_equal Hash.new, ac.engines.group(:id).size
-    assert_equal 0, ac.engines.size
-    ac.save
-    assert_equal Hash.new, ac.engines.group(:id).size
-    assert_equal 0, ac.engines.size
-  end
-
-  def test_null_relation_average
-    ac = Aircraft.new
-    assert_equal Hash.new, ac.engines.group(:car_id).average(:id)
-    assert_nil ac.engines.average(:id)
-    ac.save
-    assert_equal Hash.new, ac.engines.group(:car_id).average(:id)
-    assert_nil ac.engines.average(:id)
-  end
-
-  def test_null_relation_minimum
-    ac = Aircraft.new
-    assert_equal Hash.new, ac.engines.group(:car_id).minimum(:id)
-    assert_nil ac.engines.minimum(:id)
-    ac.save
-    assert_equal Hash.new, ac.engines.group(:car_id).minimum(:id)
-    assert_nil ac.engines.minimum(:id)
+  [:count, :sum].each do |method|
+    define_method "test_null_relation_#{method}" do
+      assert_no_queries(ignore_none: false) do
+        assert_equal 0, Comment.none.public_send(method, :id)
+        assert_equal Hash.new, Comment.none.group(:post_id).public_send(method, :id)
+      end
+    end
   end
 
-  def test_null_relation_maximum
-    ac = Aircraft.new
-    assert_equal Hash.new, ac.engines.group(:car_id).maximum(:id)
-    assert_nil ac.engines.maximum(:id)
-    ac.save
-    assert_equal Hash.new, ac.engines.group(:car_id).maximum(:id)
-    assert_nil ac.engines.maximum(:id)
+  [:average, :minimum, :maximum].each do |method|
+    define_method "test_null_relation_#{method}" do
+      assert_no_queries(ignore_none: false) do
+        assert_nil Comment.none.public_send(method, :id)
+        assert_equal Hash.new, Comment.none.group(:post_id).public_send(method, :id)
+      end
+    end
   end
 
   def test_null_relation_in_where_condition
-- 
cgit v1.2.3


From 189b8a06dc703f7a8477f877f0a02e23dd691ed8 Mon Sep 17 00:00:00 2001
From: Ryuta Kamizono <kamipo@gmail.com>
Date: Sun, 16 Jul 2017 15:19:06 +0900
Subject: Use `where(id: 10)` rather than `where(relation.table[:id].eq(10))`

Because Arel is a private API and to describe `where_values_hash` keys
constructed by `where` are string.
---
 activerecord/test/cases/relation_test.rb | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

(limited to 'activerecord')

diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb
index 382aa17c34..9bc7c9f949 100644
--- a/activerecord/test/cases/relation_test.rb
+++ b/activerecord/test/cases/relation_test.rb
@@ -52,8 +52,8 @@ module ActiveRecord
 
     def test_has_values
       relation = Relation.new(Post, Post.arel_table, Post.predicate_builder)
-      relation.where! relation.table[:id].eq(10)
-      assert_equal({ id: 10 }, relation.where_values_hash)
+      relation.where!(id: 10)
+      assert_equal({ "id" => 10 }, relation.where_values_hash)
     end
 
     def test_values_wrong_table
@@ -90,9 +90,9 @@ module ActiveRecord
 
     def test_create_with_value_with_wheres
       relation = Relation.new(Post, Post.arel_table, Post.predicate_builder)
-      relation.where! relation.table[:id].eq(10)
+      relation.where!(id: 10)
       relation.create_with_value = { hello: "world" }
-      assert_equal({ hello: "world", id: 10 }, relation.scope_for_create)
+      assert_equal({ hello: "world", "id" => 10 }, relation.scope_for_create)
     end
 
     # FIXME: is this really wanted or expected behavior?
@@ -100,7 +100,7 @@ module ActiveRecord
       relation = Relation.new(Post, Post.arel_table, Post.predicate_builder)
       assert_equal({}, relation.scope_for_create)
 
-      relation.where! relation.table[:id].eq(10)
+      relation.where!(id: 10)
       assert_equal({}, relation.scope_for_create)
 
       relation.create_with_value = { hello: "world" }
-- 
cgit v1.2.3


From 01c85097d4977b0c141b7c89df15c0750f37c62d Mon Sep 17 00:00:00 2001
From: Ryuta Kamizono <kamipo@gmail.com>
Date: Thu, 13 Jul 2017 07:14:59 +0900
Subject: Fix `create_with` using both string and symbol

This is related with #27680.

Since `where_values_hash` keys constructed by `where` are string, so we
need `stringify_keys` to `create_with_value` before merging it.
---
 activerecord/lib/active_record/associations/association.rb         | 7 +++++--
 .../lib/active_record/associations/collection_association.rb       | 4 ----
 .../lib/active_record/associations/singular_association.rb         | 5 ++---
 activerecord/lib/active_record/relation.rb                         | 2 +-
 activerecord/lib/active_record/relation/query_methods.rb           | 2 +-
 activerecord/lib/active_record/relation/where_clause.rb            | 4 ++--
 activerecord/test/cases/relation_test.rb                           | 7 +++----
 activerecord/test/cases/relations_test.rb                          | 2 +-
 activerecord/test/cases/scoping/default_scoping_test.rb            | 5 +++++
 9 files changed, 20 insertions(+), 18 deletions(-)

(limited to 'activerecord')

diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb
index 1138ae3462..6acf831759 100644
--- a/activerecord/lib/active_record/associations/association.rb
+++ b/activerecord/lib/active_record/associations/association.rb
@@ -171,8 +171,8 @@ module ActiveRecord
         skip_assign = [reflection.foreign_key, reflection.type].compact
         assigned_keys = record.changed_attribute_names_to_save
         assigned_keys += except_from_scope_attributes.keys.map(&:to_s)
-        attributes = create_scope.except(*(assigned_keys - skip_assign))
-        record.assign_attributes(attributes)
+        attributes = scope_for_create.except(*(assigned_keys - skip_assign))
+        record.send(:_assign_attributes, attributes) if attributes.any?
         set_inverse_instance(record)
       end
 
@@ -185,6 +185,9 @@ module ActiveRecord
       end
 
       private
+        def scope_for_create
+          scope.scope_for_create
+        end
 
         def find_target?
           !loaded? && (!owner.new_record? || foreign_key_present?) && klass
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index a49fb155ee..69401162aa 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -374,10 +374,6 @@ module ActiveRecord
           end
         end
 
-        def create_scope
-          scope.scope_for_create.stringify_keys
-        end
-
         def delete_or_destroy(records, method)
           records = records.flatten
           records.each { |record| raise_on_type_mismatch!(record) }
diff --git a/activerecord/lib/active_record/associations/singular_association.rb b/activerecord/lib/active_record/associations/singular_association.rb
index f8bbe4c2ed..4896afcca7 100644
--- a/activerecord/lib/active_record/associations/singular_association.rb
+++ b/activerecord/lib/active_record/associations/singular_association.rb
@@ -30,9 +30,8 @@ module ActiveRecord
       end
 
       private
-
-        def create_scope
-          scope.scope_for_create.stringify_keys.except(klass.primary_key)
+        def scope_for_create
+          super.except(klass.primary_key)
         end
 
         def find_target
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 76cf47a3ed..82018436a0 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -591,7 +591,7 @@ module ActiveRecord
     end
 
     def scope_for_create
-      @scope_for_create ||= where_values_hash.merge(create_with_value)
+      @scope_for_create ||= where_values_hash.merge!(create_with_value.stringify_keys)
     end
 
     # Returns true if relation needs eager loading.
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 79495ead91..9d6db3dc64 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -797,7 +797,7 @@ module ActiveRecord
         value = sanitize_forbidden_attributes(value)
         self.create_with_value = create_with_value.merge(value)
       else
-        self.create_with_value = {}
+        self.create_with_value = FROZEN_EMPTY_HASH
       end
 
       self
diff --git a/activerecord/lib/active_record/relation/where_clause.rb b/activerecord/lib/active_record/relation/where_clause.rb
index 119910ee79..0feb2c6cb2 100644
--- a/activerecord/lib/active_record/relation/where_clause.rb
+++ b/activerecord/lib/active_record/relation/where_clause.rb
@@ -52,8 +52,8 @@ module ActiveRecord
         binds = self.binds.map { |attr| [attr.name, attr.value] }.to_h
 
         equalities.map { |node|
-          name = node.left.name
-          [name, binds.fetch(name.to_s) {
+          name = node.left.name.to_s
+          [name, binds.fetch(name) {
             case node.right
             when Array then node.right.map(&:val)
             when Arel::Nodes::Casted, Arel::Nodes::Quoted
diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb
index 9bc7c9f949..d2859cbafd 100644
--- a/activerecord/test/cases/relation_test.rb
+++ b/activerecord/test/cases/relation_test.rb
@@ -83,16 +83,15 @@ module ActiveRecord
 
     def test_create_with_value
       relation = Relation.new(Post, Post.arel_table, Post.predicate_builder)
-      hash = { hello: "world" }
-      relation.create_with_value = hash
-      assert_equal hash, relation.scope_for_create
+      relation.create_with_value = { hello: "world" }
+      assert_equal({ "hello" => "world" }, relation.scope_for_create)
     end
 
     def test_create_with_value_with_wheres
       relation = Relation.new(Post, Post.arel_table, Post.predicate_builder)
       relation.where!(id: 10)
       relation.create_with_value = { hello: "world" }
-      assert_equal({ hello: "world", "id" => 10 }, relation.scope_for_create)
+      assert_equal({ "hello" => "world", "id" => 10 }, relation.scope_for_create)
     end
 
     # FIXME: is this really wanted or expected behavior?
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index eb3449b331..6c35940c2e 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -1482,7 +1482,7 @@ class RelationTest < ActiveRecord::TestCase
     assert_equal bird, Bird.find_or_initialize_by(name: "bob")
   end
 
-  def test_explicit_create_scope
+  def test_explicit_create_with
     hens = Bird.where(name: "hen")
     assert_equal "hen", hens.new.name
 
diff --git a/activerecord/test/cases/scoping/default_scoping_test.rb b/activerecord/test/cases/scoping/default_scoping_test.rb
index 89fb434b27..e310739f7b 100644
--- a/activerecord/test/cases/scoping/default_scoping_test.rb
+++ b/activerecord/test/cases/scoping/default_scoping_test.rb
@@ -342,6 +342,11 @@ class DefaultScopingTest < ActiveRecord::TestCase
     assert_equal "Aaron", aaron.name
   end
 
+  def test_create_with_using_both_string_and_symbol
+    jamis = PoorDeveloperCalledJamis.create_with(name: "foo").create_with("name" => "Aaron").new
+    assert_equal "Aaron", jamis.name
+  end
+
   def test_create_with_reset
     jamis = PoorDeveloperCalledJamis.create_with(name: "Aaron").create_with(nil).new
     assert_equal "Jamis", jamis.name
-- 
cgit v1.2.3


From 555b383383699e289822dd3ebb0fbff1c14e5f9a Mon Sep 17 00:00:00 2001
From: Ryuta Kamizono <kamipo@gmail.com>
Date: Sun, 16 Jul 2017 16:19:41 +0900
Subject: Remove unused `@last`, `@order_clause`, and `@join_dependency`

Using `@last` and `@order_clause` was removed at 8bb5274 and 90d1524.
`@join_dependency` was added at b959950 but it is unused in the first
place.
---
 activerecord/lib/active_record/relation.rb | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

(limited to 'activerecord')

diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 76cf47a3ed..a0a2466af4 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -556,8 +556,7 @@ module ActiveRecord
     end
 
     def reset
-      @last = @to_sql = @order_clause = @scope_for_create = @arel = @loaded = nil
-      @should_eager_load = @join_dependency = nil
+      @to_sql = @scope_for_create = @arel = @loaded = @should_eager_load = nil
       @records = [].freeze
       @offsets = {}
       self
-- 
cgit v1.2.3


From b8533ec9f0ef4afe1bba701effc68824f0c6cfed Mon Sep 17 00:00:00 2001
From: Ryuta Kamizono <kamipo@gmail.com>
Date: Fri, 14 Jul 2017 13:44:03 +0900
Subject: Remove unused requires

---
 activerecord/lib/active_record/attribute_methods.rb | 3 ---
 activerecord/lib/active_record/core.rb              | 2 --
 2 files changed, 5 deletions(-)

(limited to 'activerecord')

diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb
index 83c61fad19..4e6a43a039 100644
--- a/activerecord/lib/active_record/attribute_methods.rb
+++ b/activerecord/lib/active_record/attribute_methods.rb
@@ -1,7 +1,4 @@
-require "active_support/core_ext/enumerable"
-require "active_support/core_ext/string/filters"
 require "mutex_m"
-require "concurrent/map"
 
 module ActiveRecord
   # = Active Record Attribute Methods
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index 198c712abc..02d8cf82d2 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -1,6 +1,4 @@
-require "thread"
 require "active_support/core_ext/hash/indifferent_access"
-require "active_support/core_ext/object/duplicable"
 require "active_support/core_ext/string/filters"
 
 module ActiveRecord
-- 
cgit v1.2.3


From a18cf23a9cbcbeed61e8049442640c7153e0a8fb Mon Sep 17 00:00:00 2001
From: "yuuji.yaginuma" <yuuji.yaginuma@gmail.com>
Date: Fri, 14 Jul 2017 08:01:49 +0900
Subject: Set `represent_boolean_as_integer` via `configuration`

---
 .../active_record/connection_adapters/sqlite3_adapter.rb   |  2 +-
 activerecord/lib/active_record/railtie.rb                  | 14 ++++++++++++--
 2 files changed, 13 insertions(+), 3 deletions(-)

(limited to 'activerecord')

diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
index 5174c98c4b..2fede7b847 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
@@ -86,7 +86,7 @@ module ActiveRecord
       # for all models and all boolean columns, after which the flag must be set
       # to true by adding the following to your application.rb file:
       #
-      #   ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer = true
+      #   Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true
       class_attribute :represent_boolean_as_integer, default: false
 
       class StatementPool < ConnectionAdapters::StatementPool
diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb
index 9b19e85b33..0b82926081 100644
--- a/activerecord/lib/active_record/railtie.rb
+++ b/activerecord/lib/active_record/railtie.rb
@@ -26,6 +26,9 @@ module ActiveRecord
     config.active_record.use_schema_cache_dump = true
     config.active_record.maintain_test_schema = true
 
+    config.active_record.sqlite3 = ActiveSupport::OrderedOptions.new
+    config.active_record.sqlite3.represent_boolean_as_integer = nil
+
     config.eager_load_namespaces << ActiveRecord
 
     rake_tasks do
@@ -108,7 +111,9 @@ module ActiveRecord
 
     initializer "active_record.set_configs" do |app|
       ActiveSupport.on_load(:active_record) do
-        app.config.active_record.each do |k, v|
+        configs = app.config.active_record.dup
+        configs.delete(:sqlite3)
+        configs.each do |k, v|
           send "#{k}=", v
         end
       end
@@ -178,6 +183,11 @@ end_warning
     initializer "active_record.check_represent_sqlite3_boolean_as_integer" do
       config.after_initialize do
         ActiveSupport.on_load(:active_record_sqlite3adapter) do
+          represent_boolean_as_integer = Rails.application.config.active_record.sqlite3.delete(:represent_boolean_as_integer)
+          unless represent_boolean_as_integer.nil?
+            ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer = represent_boolean_as_integer
+          end
+
           unless ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer
             ActiveSupport::Deprecation.warn <<-MSG
 Leaving `ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer`
@@ -192,7 +202,7 @@ by setting up a rake task which runs
 for all models and all boolean columns, after which the flag must be set to
 true by adding the following to your application.rb file:
 
-  ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer = true
+  Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true
 MSG
           end
         end
-- 
cgit v1.2.3


From 57e9495e64f6ff6e59bc7e25ee05df43aac472e1 Mon Sep 17 00:00:00 2001
From: Ryuta Kamizono <kamipo@gmail.com>
Date: Sun, 16 Jul 2017 21:06:51 +0900
Subject: Fix `create_with` with multiparameter attributes

---
 activerecord/lib/active_record/scoping.rb          |  5 +--
 .../test/cases/multiparameter_attributes_test.rb   | 45 +++++++++++++++-------
 2 files changed, 34 insertions(+), 16 deletions(-)

(limited to 'activerecord')

diff --git a/activerecord/lib/active_record/scoping.rb b/activerecord/lib/active_record/scoping.rb
index 94e0ef6724..82e20a32d0 100644
--- a/activerecord/lib/active_record/scoping.rb
+++ b/activerecord/lib/active_record/scoping.rb
@@ -33,9 +33,8 @@ module ActiveRecord
     def populate_with_current_scope_attributes # :nodoc:
       return unless self.class.scope_attributes?
 
-      self.class.scope_attributes.each do |att, value|
-        send("#{att}=", value) if respond_to?("#{att}=")
-      end
+      attributes = self.class.scope_attributes
+      _assign_attributes(attributes) if attributes.any?
     end
 
     def initialize_internals_callback # :nodoc:
diff --git a/activerecord/test/cases/multiparameter_attributes_test.rb b/activerecord/test/cases/multiparameter_attributes_test.rb
index ceb5724377..a5f3722be1 100644
--- a/activerecord/test/cases/multiparameter_attributes_test.rb
+++ b/activerecord/test/cases/multiparameter_attributes_test.rb
@@ -271,6 +271,12 @@ class MultiParameterAttributeTest < ActiveRecord::TestCase
     ensure
       Topic.reset_column_information
     end
+
+    def test_multiparameter_attributes_setting_time_attribute
+      topic = Topic.new("bonus_time(4i)" => "01", "bonus_time(5i)" => "05")
+      assert_equal 1, topic.bonus_time.hour
+      assert_equal 5, topic.bonus_time.min
+    end
   end
 
   def test_multiparameter_attributes_on_time_with_empty_seconds
@@ -285,14 +291,6 @@ class MultiParameterAttributeTest < ActiveRecord::TestCase
     end
   end
 
-  unless current_adapter? :OracleAdapter
-    def test_multiparameter_attributes_setting_time_attribute
-      topic = Topic.new("bonus_time(4i)" => "01", "bonus_time(5i)" => "05")
-      assert_equal 1, topic.bonus_time.hour
-      assert_equal 5, topic.bonus_time.min
-    end
-  end
-
   def test_multiparameter_attributes_setting_date_attribute
     topic = Topic.new("written_on(1i)" => "1952", "written_on(2i)" => "3", "written_on(3i)" => "11")
     assert_equal 1952, topic.written_on.year
@@ -300,13 +298,34 @@ class MultiParameterAttributeTest < ActiveRecord::TestCase
     assert_equal 11, topic.written_on.day
   end
 
+  def test_create_with_multiparameter_attributes_setting_date_attribute
+    topic = Topic.create_with("written_on(1i)" => "1952", "written_on(2i)" => "3", "written_on(3i)" => "11").new
+    assert_equal 1952, topic.written_on.year
+    assert_equal 3, topic.written_on.month
+    assert_equal 11, topic.written_on.day
+  end
+
   def test_multiparameter_attributes_setting_date_and_time_attribute
     topic = Topic.new(
-        "written_on(1i)" => "1952",
-        "written_on(2i)" => "3",
-        "written_on(3i)" => "11",
-        "written_on(4i)" => "13",
-        "written_on(5i)" => "55")
+      "written_on(1i)" => "1952",
+      "written_on(2i)" => "3",
+      "written_on(3i)" => "11",
+      "written_on(4i)" => "13",
+      "written_on(5i)" => "55")
+    assert_equal 1952, topic.written_on.year
+    assert_equal 3, topic.written_on.month
+    assert_equal 11, topic.written_on.day
+    assert_equal 13, topic.written_on.hour
+    assert_equal 55, topic.written_on.min
+  end
+
+  def test_create_with_multiparameter_attributes_setting_date_and_time_attribute
+    topic = Topic.create_with(
+      "written_on(1i)" => "1952",
+      "written_on(2i)" => "3",
+      "written_on(3i)" => "11",
+      "written_on(4i)" => "13",
+      "written_on(5i)" => "55").new
     assert_equal 1952, topic.written_on.year
     assert_equal 3, topic.written_on.month
     assert_equal 11, topic.written_on.day
-- 
cgit v1.2.3


From d476553d1cdeee0805585c2d4e2e6ee6be841288 Mon Sep 17 00:00:00 2001
From: Ryuta Kamizono <kamipo@gmail.com>
Date: Sun, 16 Jul 2017 21:31:08 +0900
Subject: Don't cache `scope_for_create`

I investigated where `scope_for_create` is reused in tests with the
following code:

```diff
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -590,6 +590,10 @@ def where_values_hash(relation_table_name = table_name)
     end

     def scope_for_create
+      if defined?(@scope_for_create) && @scope_for_create
+        puts caller
+        puts "defined"
+      end
       @scope_for_create ||= where_values_hash.merge!(create_with_value.stringify_keys)
     end
```

It was hit only `test_scope_for_create_is_cached`. This means that
`scope_for_create` will not be reused in normal use cases. So we can
remove caching `scope_for_create` to respect changing `where_clause` and
`create_with_value`.
---
 activerecord/lib/active_record/associations/association.rb   |  2 +-
 .../lib/active_record/associations/singular_association.rb   |  2 +-
 activerecord/lib/active_record/relation.rb                   |  4 ++--
 activerecord/test/cases/relation_test.rb                     | 12 ++----------
 4 files changed, 6 insertions(+), 14 deletions(-)

(limited to 'activerecord')

diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb
index 6acf831759..c166cfd68f 100644
--- a/activerecord/lib/active_record/associations/association.rb
+++ b/activerecord/lib/active_record/associations/association.rb
@@ -171,7 +171,7 @@ module ActiveRecord
         skip_assign = [reflection.foreign_key, reflection.type].compact
         assigned_keys = record.changed_attribute_names_to_save
         assigned_keys += except_from_scope_attributes.keys.map(&:to_s)
-        attributes = scope_for_create.except(*(assigned_keys - skip_assign))
+        attributes = scope_for_create.except!(*(assigned_keys - skip_assign))
         record.send(:_assign_attributes, attributes) if attributes.any?
         set_inverse_instance(record)
       end
diff --git a/activerecord/lib/active_record/associations/singular_association.rb b/activerecord/lib/active_record/associations/singular_association.rb
index 4896afcca7..66993b9bf7 100644
--- a/activerecord/lib/active_record/associations/singular_association.rb
+++ b/activerecord/lib/active_record/associations/singular_association.rb
@@ -31,7 +31,7 @@ module ActiveRecord
 
       private
         def scope_for_create
-          super.except(klass.primary_key)
+          super.except!(klass.primary_key)
         end
 
         def find_target
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 23cb1baaed..c5d98e970a 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -556,7 +556,7 @@ module ActiveRecord
     end
 
     def reset
-      @to_sql = @scope_for_create = @arel = @loaded = @should_eager_load = nil
+      @to_sql = @arel = @loaded = @should_eager_load = nil
       @records = [].freeze
       @offsets = {}
       self
@@ -590,7 +590,7 @@ module ActiveRecord
     end
 
     def scope_for_create
-      @scope_for_create ||= where_values_hash.merge!(create_with_value.stringify_keys)
+      where_values_hash.merge!(create_with_value.stringify_keys)
     end
 
     # Returns true if relation needs eager loading.
diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb
index d2859cbafd..82b071fb98 100644
--- a/activerecord/test/cases/relation_test.rb
+++ b/activerecord/test/cases/relation_test.rb
@@ -88,22 +88,14 @@ module ActiveRecord
     end
 
     def test_create_with_value_with_wheres
-      relation = Relation.new(Post, Post.arel_table, Post.predicate_builder)
-      relation.where!(id: 10)
-      relation.create_with_value = { hello: "world" }
-      assert_equal({ "hello" => "world", "id" => 10 }, relation.scope_for_create)
-    end
-
-    # FIXME: is this really wanted or expected behavior?
-    def test_scope_for_create_is_cached
       relation = Relation.new(Post, Post.arel_table, Post.predicate_builder)
       assert_equal({}, relation.scope_for_create)
 
       relation.where!(id: 10)
-      assert_equal({}, relation.scope_for_create)
+      assert_equal({ "id" => 10 }, relation.scope_for_create)
 
       relation.create_with_value = { hello: "world" }
-      assert_equal({}, relation.scope_for_create)
+      assert_equal({ "hello" => "world", "id" => 10 }, relation.scope_for_create)
     end
 
     def test_bad_constants_raise_errors
-- 
cgit v1.2.3


From 8f6bd6fa6f165f5a069f0cf6844cf2278d97ea6e Mon Sep 17 00:00:00 2001
From: Robin Dupret <robin.dupret@gmail.com>
Date: Sun, 16 Jul 2017 17:33:49 +0200
Subject: Fix code formatting for QueryMethods#select

[ci skip]
---
 activerecord/lib/active_record/relation/query_methods.rb | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

(limited to 'activerecord')

diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 9d6db3dc64..8c2d546aff 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -202,12 +202,13 @@ module ActiveRecord
 
     # Works in two unique ways.
     #
-    # First: takes a block so it can be used just like +Array#select+.
+    # First: takes a block so it can be used just like <tt>Array#select</tt>.
     #
     #   Model.all.select { |m| m.field == value }
     #
     # This will build an array of objects from the database for the scope,
-    # converting them into an array and iterating through them using +Array#select+.
+    # converting them into an array and iterating through them using
+    # <tt>Array#select</tt>.
     #
     # Second: Modifies the SELECT statement for the query so that only certain
     # fields are retrieved:
-- 
cgit v1.2.3


From 4183d5dfa1d6d651232a4db44a1fcf71d220af4e Mon Sep 17 00:00:00 2001
From: Ryuta Kamizono <kamipo@gmail.com>
Date: Sun, 16 Jul 2017 18:11:03 +0900
Subject: Enable `Layout/FirstParameterIndentation` cop

We have some indentation cops. But now there is a little inconsistent
params indentations. Enable `Layout/FirstParameterIndentation` cop to
prevent newly inconsistent indentation added and auto-correct to
existing violations.
---
 activerecord/test/cases/scoping/default_scoping_test.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'activerecord')

diff --git a/activerecord/test/cases/scoping/default_scoping_test.rb b/activerecord/test/cases/scoping/default_scoping_test.rb
index e310739f7b..bd05cb4787 100644
--- a/activerecord/test/cases/scoping/default_scoping_test.rb
+++ b/activerecord/test/cases/scoping/default_scoping_test.rb
@@ -332,7 +332,7 @@ class DefaultScopingTest < ActiveRecord::TestCase
 
   def test_create_with_merge
     aaron = PoorDeveloperCalledJamis.create_with(name: "foo", salary: 20).merge(
-              PoorDeveloperCalledJamis.create_with(name: "Aaron")).new
+      PoorDeveloperCalledJamis.create_with(name: "Aaron")).new
     assert_equal 20, aaron.salary
     assert_equal "Aaron", aaron.name
 
-- 
cgit v1.2.3


From a0ebab52b2a708a09739e0c4ecc16ad16d4e676d Mon Sep 17 00:00:00 2001
From: Ryuta Kamizono <kamipo@gmail.com>
Date: Mon, 17 Jul 2017 17:19:56 +0900
Subject: Remove useless `arel_engine`

`arel_engine` is only used in `raise_record_not_found_exception!` to use
`engine.connection` (and `connection.visitor`) in `arel.where_sql`.

https://github.com/rails/arel/blob/v8.0.0/lib/arel/select_manager.rb#L183

But `klass.connection` will work as expected even if not using
`arel_engine` (described by `test_connection`). So `arel_engine` is no
longer needed.
---
 activerecord/lib/active_record/core.rb                    | 10 ----------
 activerecord/lib/active_record/model_schema.rb            |  1 -
 activerecord/lib/active_record/relation/finder_methods.rb |  2 +-
 activerecord/test/cases/multiple_db_test.rb               |  9 ++-------
 4 files changed, 3 insertions(+), 19 deletions(-)

(limited to 'activerecord')

diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index 02d8cf82d2..3ea7b644c2 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -263,16 +263,6 @@ module ActiveRecord
         @arel_table ||= Arel::Table.new(table_name, type_caster: type_caster)
       end
 
-      # Returns the Arel engine.
-      def arel_engine # :nodoc:
-        @arel_engine ||=
-          if Base == self || connection_handler.retrieve_connection_pool(connection_specification_name)
-            self
-          else
-            superclass.arel_engine
-          end
-      end
-
       def arel_attribute(name, table = arel_table) # :nodoc:
         name = attribute_alias(name) if attribute_alias?(name)
         table[name]
diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb
index 14e0f5bff7..2d3c9175bd 100644
--- a/activerecord/lib/active_record/model_schema.rb
+++ b/activerecord/lib/active_record/model_schema.rb
@@ -467,7 +467,6 @@ module ActiveRecord
         end
 
         def reload_schema_from_cache
-          @arel_engine = nil
           @arel_table = nil
           @column_names = nil
           @attribute_types = nil
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index ac0b4f597e..7121dcade8 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -329,7 +329,7 @@ module ActiveRecord
     # the expected number of results should be provided in the +expected_size+
     # argument.
     def raise_record_not_found_exception!(ids = nil, result_size = nil, expected_size = nil, key = primary_key) # :nodoc:
-      conditions = arel.where_sql(@klass.arel_engine)
+      conditions = arel.where_sql(@klass)
       conditions = " [#{conditions}]" if conditions
       name = @klass.name
 
diff --git a/activerecord/test/cases/multiple_db_test.rb b/activerecord/test/cases/multiple_db_test.rb
index e3bb51bd77..4e3daeabb6 100644
--- a/activerecord/test/cases/multiple_db_test.rb
+++ b/activerecord/test/cases/multiple_db_test.rb
@@ -90,14 +90,9 @@ class MultipleDbTest < ActiveRecord::TestCase
     assert_equal "Ruby Developer", Entrant.find(1).name
   end
 
-  def test_arel_table_engines
-    assert_not_equal Entrant.arel_engine, Bird.arel_engine
-    assert_not_equal Entrant.arel_engine, Course.arel_engine
-  end
-
   def test_connection
-    assert_equal Entrant.arel_engine.connection.object_id, Bird.arel_engine.connection.object_id
-    assert_not_equal Entrant.arel_engine.connection.object_id, Course.arel_engine.connection.object_id
+    assert_same Entrant.connection, Bird.connection
+    assert_not_same Entrant.connection, Course.connection
   end
 
   unless in_memory_db?
-- 
cgit v1.2.3


From 5c71000d086cc42516934415b79380c2224e1614 Mon Sep 17 00:00:00 2001
From: Sean Griffin <sean@seantheprogrammer.com>
Date: Mon, 17 Jul 2017 10:07:02 -0400
Subject: Post.joins(:users) should not be affected by `User.current_scope`

This change was introduced by #18109. The intent of that change was to
specifically apply `unscoped`, not to allow all changes to
`current_scope` to affect the join. The idea of allowing `current_scope`
to affect joins is interesting and potentially more consistent, but has
sever problems associated with it. The fact that we're specifically
stripping out joins indicates one such problem (and potentially leads to
invalid queries).

Ultimately it's difficult to reason about what `Posts.joins(:users)`
actually means if it's affected by `User.current_scope`, and it's
difficult to specifically control what does or doesn't get added. If we
were starting from scratch, I don't think I'd have `joins` be affected
by `default_scope` either, but that's too big of a breaking change to
make at this point.

With this change, we no longer apply `current_scope` when bringing in
joins, with the singular exception of the motivating use case which
introduced this bug, which is providing a way to *opt-out* of having the
default scope apply to joins.

Fixes #29338.
---
 activerecord/CHANGELOG.md                               |  7 +++++++
 activerecord/lib/active_record/reflection.rb            |  6 ++----
 activerecord/test/cases/scoping/default_scoping_test.rb | 10 ++++++++++
 3 files changed, 19 insertions(+), 4 deletions(-)

(limited to 'activerecord')

diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 5ffbed28f6..6c7e2b19e7 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,10 @@
+*   `Relation#joins` is no longer affected by the target model's
+    `current_scope`, with the exception of `unscoped`.
+
+    Fixes #29338.
+
+    *Sean Griffin*
+
 *   Change sqlite3 boolean serialization to use 1 and 0
 
     SQLite natively recognizes 1 and 0 as true and false, but does not natively
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index a453ca55c7..4f53280b5c 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -219,10 +219,8 @@ module ActiveRecord
       end
 
       def klass_join_scope(table, predicate_builder) # :nodoc:
-        if klass.current_scope
-          klass.current_scope.clone.tap { |scope|
-            scope.joins_values = scope.left_outer_joins_values = [].freeze
-          }
+        if klass.current_scope && klass.current_scope.values.empty?
+          klass.unscoped
         else
           klass.default_scoped(build_scope(table, predicate_builder))
         end
diff --git a/activerecord/test/cases/scoping/default_scoping_test.rb b/activerecord/test/cases/scoping/default_scoping_test.rb
index bd05cb4787..a5061cfce7 100644
--- a/activerecord/test/cases/scoping/default_scoping_test.rb
+++ b/activerecord/test/cases/scoping/default_scoping_test.rb
@@ -377,6 +377,16 @@ class DefaultScopingTest < ActiveRecord::TestCase
                  Comment.joins(:post).count
   end
 
+  def test_joins_not_affected_by_scope_other_than_default_or_unscoped
+    without_scope_on_post = Comment.joins(:post).to_a
+    with_scope_on_post = nil
+    Post.where(id: [1, 5, 6]).scoping do
+      with_scope_on_post = Comment.joins(:post).to_a
+    end
+
+    assert_equal with_scope_on_post, without_scope_on_post
+  end
+
   def test_unscoped_with_joins_should_not_have_default_scope
     assert_equal SpecialPostWithDefaultScope.unscoped { Comment.joins(:special_post_with_default_scope).to_a },
                  Comment.joins(:post).to_a
-- 
cgit v1.2.3


From 1519e976b224871c7f7dd476351930d5d0d7faf6 Mon Sep 17 00:00:00 2001
From: Sean Griffin <sean@seantheprogrammer.com>
Date: Mon, 17 Jul 2017 11:14:11 -0400
Subject: Allow multiparameter assigned attributes to be used with `text_field`

Between 4.2 and 5.0 the behavior of how multiparameter attributes
interact with `_before_type_cast` changed. In 4.2 it returns the
post-type-cast value. After 5.0, it returns the hash that gets sent to
the type. This behavior is correct, but will cause an issue if you then
tried to render that value in an input like `text_field` or
`hidden_field`.

In this case, we want those fields to use the post-type-cast form,
instead of the `_before_type_cast` (the main reason it uses
`_before_type_cast` at all is to avoid losing data when casting a
non-numeric string to integer).

I've opted to modify `came_from_user?` rather than introduce a new
method for this as I want to avoid complicating that contract further,
and technically the multiparameter hash didn't come from assignment, it
was constructed internally by AR.

Close #27888.
---
 activerecord/CHANGELOG.md                                 |  5 +++++
 activerecord/lib/active_record/attribute.rb               |  2 +-
 activerecord/test/cases/multiparameter_attributes_test.rb | 11 +++++++++++
 3 files changed, 17 insertions(+), 1 deletion(-)

(limited to 'activerecord')

diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 6c7e2b19e7..1bd0199e4c 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,8 @@
+*   Values constructed using multi-parameter assignment will now use the
+    post-type-cast value for rendering in single-field form inputs.
+
+    *Sean Griffin*
+
 *   `Relation#joins` is no longer affected by the target model's
     `current_scope`, with the exception of `unscoped`.
 
diff --git a/activerecord/lib/active_record/attribute.rb b/activerecord/lib/active_record/attribute.rb
index 78662433eb..f89261923b 100644
--- a/activerecord/lib/active_record/attribute.rb
+++ b/activerecord/lib/active_record/attribute.rb
@@ -174,7 +174,7 @@ module ActiveRecord
         end
 
         def came_from_user?
-          true
+          !type.value_constructed_by_mass_assignment?(value_before_type_cast)
         end
       end
 
diff --git a/activerecord/test/cases/multiparameter_attributes_test.rb b/activerecord/test/cases/multiparameter_attributes_test.rb
index a5f3722be1..aa521e907c 100644
--- a/activerecord/test/cases/multiparameter_attributes_test.rb
+++ b/activerecord/test/cases/multiparameter_attributes_test.rb
@@ -383,4 +383,15 @@ class MultiParameterAttributeTest < ActiveRecord::TestCase
 
     assert_equal("address", ex.errors[0].attribute)
   end
+
+  def test_multiparameter_assigned_attributes_did_not_come_from_user
+    topic = Topic.new(
+      "written_on(1i)" => "1952",
+      "written_on(2i)" => "3",
+      "written_on(3i)" => "11",
+      "written_on(4i)" => "13",
+      "written_on(5i)" => "55",
+    )
+    refute_predicate topic, :written_on_came_from_user?
+  end
 end
-- 
cgit v1.2.3


From 972f0d6cb6c9d510b9b32e7f4138184154ab70eb Mon Sep 17 00:00:00 2001
From: Ryuta Kamizono <kamipo@gmail.com>
Date: Sun, 16 Jul 2017 22:34:51 +0900
Subject: `Persistence#delete` should not be affected by scoping

`self.class.delete` is delegated to `all` and `all` is affected by
scoping. It should use `unscoped` to not be affected by that.
---
 activerecord/lib/active_record/persistence.rb | 6 +++++-
 activerecord/test/cases/persistence_test.rb   | 7 +++++++
 2 files changed, 12 insertions(+), 1 deletion(-)

(limited to 'activerecord')

diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index a9509e562a..2e6901eb0e 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -175,7 +175,7 @@ module ActiveRecord
     # callbacks or any <tt>:dependent</tt> association
     # options, use <tt>#destroy</tt>.
     def delete
-      self.class.delete(id) if persisted?
+      _relation_for_itself.delete_all if persisted?
       @destroyed = true
       freeze
     end
@@ -555,6 +555,10 @@ module ActiveRecord
     end
 
     def relation_for_destroy
+      _relation_for_itself
+    end
+
+    def _relation_for_itself
       self.class.unscoped.where(self.class.primary_key => id)
     end
 
diff --git a/activerecord/test/cases/persistence_test.rb b/activerecord/test/cases/persistence_test.rb
index 5895c51714..5830f9916a 100644
--- a/activerecord/test/cases/persistence_test.rb
+++ b/activerecord/test/cases/persistence_test.rb
@@ -437,6 +437,13 @@ class PersistenceTest < ActiveRecord::TestCase
     assert_not_nil Topic.find(2)
   end
 
+  def test_delete_isnt_affected_by_scoping
+    topic = Topic.find(1)
+    assert_difference("Topic.count", -1) do
+      Topic.where("1=0").scoping { topic.delete }
+    end
+  end
+
   def test_destroy
     topic = Topic.find(1)
     assert_equal topic, topic.destroy, "topic.destroy did not return self"
-- 
cgit v1.2.3


From 26ba655f36c20315390497a0963c23014cadeb91 Mon Sep 17 00:00:00 2001
From: Ryuta Kamizono <kamipo@gmail.com>
Date: Sat, 15 Jul 2017 08:38:29 +0900
Subject: Fix `where` with a custom table

Without this fix, SELECT clause doesn't use a custom table alias name:

```
% ARCONN=sqlite3 be ruby -w -Itest test/cases/relations_test.rb -n test_using_a_custom_table_affects_the_wheres
Using sqlite3
Run options: -n test_using_a_custom_table_affects_the_wheres --seed 31818

E

Error:
RelationTest#test_using_a_custom_table_affects_the_wheres:
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such table: posts: SELECT  "posts".* FROM "posts" "omg_posts" WHERE "omg_posts"."title" = ? LIMIT ?
```
---
 activerecord/lib/active_record/relation/query_methods.rb | 2 +-
 activerecord/test/cases/relations_test.rb                | 8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)

(limited to 'activerecord')

diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 8c2d546aff..c26c176c7b 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -1048,7 +1048,7 @@ module ActiveRecord
         if select_values.any?
           arel.project(*arel_columns(select_values.uniq))
         else
-          arel.project(@klass.arel_table[Arel.star])
+          arel.project(table[Arel.star])
         end
       end
 
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index 6c35940c2e..ca15c95432 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -1915,11 +1915,11 @@ class RelationTest < ActiveRecord::TestCase
 
     table_metadata = ActiveRecord::TableMetadata.new(Post, table_alias)
     predicate_builder = ActiveRecord::PredicateBuilder.new(table_metadata)
-    relation = ActiveRecord::Relation.new(Post, table_alias, predicate_builder)
-    relation.where!(foo: "bar")
+    relation = ActiveRecord::Relation.create(Post, table_alias, predicate_builder)
 
-    node = relation.arel.constraints.first.grep(Arel::Attributes::Attribute).first
-    assert_equal table_alias, node.relation
+    post = posts(:welcome)
+
+    assert_equal post, relation.where!(title: post.title).take
   end
 
   test "#load" do
-- 
cgit v1.2.3


From ea09bf5419ec752dd020d26b03533afa457d09d6 Mon Sep 17 00:00:00 2001
From: Ryuta Kamizono <kamipo@gmail.com>
Date: Tue, 18 Jul 2017 04:15:45 +0900
Subject: Fix `JoinDependency` with using a custom table

Without this fix, `JoinDependency` doesn't use a custom table alias:

```
% ARCONN=sqlite3 be ruby -w -Itest test/cases/relations_test.rb -n test_using_a_custom_table_with_joins_affects_the_wheres
Using sqlite3
Run options: -n test_using_a_custom_table_with_joins_affects_the_wheres --seed 14531

E

Error:RelationTest#test_using_a_custom_table_with_joins_affects_the_wheres:
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: posts.author_id: SELECT  "omg_posts".* FROM "posts" "omg_posts" INNER JOIN "authors" ON "authors"."id" = "posts"."author_id" WHERE "omg_posts"."title" = ? LIMIT ?
```
---
 .../lib/active_record/associations/join_dependency.rb |  4 ++--
 .../associations/join_dependency/join_base.rb         | 11 +++++++----
 .../lib/active_record/relation/finder_methods.rb      |  2 +-
 activerecord/lib/active_record/relation/merger.rb     |  7 ++++---
 .../lib/active_record/relation/query_methods.rb       |  4 +---
 activerecord/test/cases/relations_test.rb             | 19 ++++++++++++++-----
 6 files changed, 29 insertions(+), 18 deletions(-)

(limited to 'activerecord')

diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb
index 5c8ecf42b4..4a3fb6eaec 100644
--- a/activerecord/lib/active_record/associations/join_dependency.rb
+++ b/activerecord/lib/active_record/associations/join_dependency.rb
@@ -88,11 +88,11 @@ module ActiveRecord
       #    associations # => [:appointments]
       #    joins # =>  []
       #
-      def initialize(base, associations, joins, eager_loading: true)
+      def initialize(base, table, associations, joins, eager_loading: true)
         @alias_tracker = AliasTracker.create_with_joins(base.connection, base.table_name, joins)
         @eager_loading = eager_loading
         tree = self.class.make_tree associations
-        @join_root = JoinBase.new base, build(tree, base)
+        @join_root = JoinBase.new(base, table, build(tree, base))
         @join_root.children.each { |child| construct_tables! @join_root, child }
       end
 
diff --git a/activerecord/lib/active_record/associations/join_dependency/join_base.rb b/activerecord/lib/active_record/associations/join_dependency/join_base.rb
index f5f22ebfca..d4e26d5397 100644
--- a/activerecord/lib/active_record/associations/join_dependency/join_base.rb
+++ b/activerecord/lib/active_record/associations/join_dependency/join_base.rb
@@ -4,14 +4,17 @@ module ActiveRecord
   module Associations
     class JoinDependency # :nodoc:
       class JoinBase < JoinPart # :nodoc:
+        attr_reader :table
+
+        def initialize(base_klass, table, children)
+          super(base_klass, children)
+          @table = table
+        end
+
         def match?(other)
           return true if self == other
           super && base_klass == other.base_klass
         end
-
-        def table
-          base_klass.arel_table
-        end
       end
     end
   end
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 7121dcade8..57b7d3c2e9 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -397,7 +397,7 @@ module ActiveRecord
 
       def construct_join_dependency(joins = [], eager_loading: true)
         including = eager_load_values + includes_values
-        ActiveRecord::Associations::JoinDependency.new(@klass, including, joins, eager_loading: eager_loading)
+        ActiveRecord::Associations::JoinDependency.new(klass, table, including, joins, eager_loading: eager_loading)
       end
 
       def construct_relation_for_association_calculations
diff --git a/activerecord/lib/active_record/relation/merger.rb b/activerecord/lib/active_record/relation/merger.rb
index 5dac00724a..6251f6fc33 100644
--- a/activerecord/lib/active_record/relation/merger.rb
+++ b/activerecord/lib/active_record/relation/merger.rb
@@ -119,9 +119,10 @@ module ActiveRecord
               end
             end
 
-            join_dependency = ActiveRecord::Associations::JoinDependency.new(other.klass,
-                                                                             joins_dependency,
-                                                                             [])
+            join_dependency = ActiveRecord::Associations::JoinDependency.new(
+              other.klass, other.table, joins_dependency, []
+            )
+
             relation.joins! rest
 
             @relation = relation.joins join_dependency
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index c26c176c7b..efb55391e7 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -1020,9 +1020,7 @@ module ActiveRecord
         join_list = join_nodes + convert_join_strings_to_ast(manager, string_joins)
 
         join_dependency = ActiveRecord::Associations::JoinDependency.new(
-          @klass,
-          association_joins,
-          join_list
+          klass, table, association_joins, join_list
         )
 
         join_infos = join_dependency.join_constraints stashed_association_joins, join_type
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index 82e1077e87..316ea75e36 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -1785,15 +1785,15 @@ class RelationTest < ActiveRecord::TestCase
   end
 
   test "using a custom table affects the wheres" do
-    table_alias = Post.arel_table.alias("omg_posts")
+    post = posts(:welcome)
 
-    table_metadata = ActiveRecord::TableMetadata.new(Post, table_alias)
-    predicate_builder = ActiveRecord::PredicateBuilder.new(table_metadata)
-    relation = ActiveRecord::Relation.create(Post, table_alias, predicate_builder)
+    assert_equal post, custom_post_relation.where!(title: post.title).take
+  end
 
+  test "using a custom table with joins affects the joins" do
     post = posts(:welcome)
 
-    assert_equal post, relation.where!(title: post.title).take
+    assert_equal post, custom_post_relation.joins(:author).where!(title: post.title).take
   end
 
   test "#load" do
@@ -1950,4 +1950,13 @@ class RelationTest < ActiveRecord::TestCase
       end
     end
   end
+
+  private
+    def custom_post_relation
+      table_alias = Post.arel_table.alias("omg_posts")
+      table_metadata = ActiveRecord::TableMetadata.new(Post, table_alias)
+      predicate_builder = ActiveRecord::PredicateBuilder.new(table_metadata)
+
+      ActiveRecord::Relation.create(Post, table_alias, predicate_builder)
+    end
 end
-- 
cgit v1.2.3


From 26feaf9c3cb09902fec745f8efc1d51baa8d41cd Mon Sep 17 00:00:00 2001
From: Sean Griffin <sean@seantheprogrammer.com>
Date: Tue, 18 Jul 2017 10:13:56 -0400
Subject: Remove incorrect comment

This method needs to be protected.
---
 activerecord/lib/active_record/attribute_set.rb | 2 --
 1 file changed, 2 deletions(-)

(limited to 'activerecord')

diff --git a/activerecord/lib/active_record/attribute_set.rb b/activerecord/lib/active_record/attribute_set.rb
index 6399e3de70..a963ba015a 100644
--- a/activerecord/lib/active_record/attribute_set.rb
+++ b/activerecord/lib/active_record/attribute_set.rb
@@ -98,8 +98,6 @@ module ActiveRecord
       attributes == other.attributes
     end
 
-    # TODO Change this to private once we've dropped Ruby 2.2 support.
-    # Workaround for Ruby 2.2 "private attribute?" warning.
     protected
 
       attr_reader :attributes
-- 
cgit v1.2.3


From 020abadf047997cb3df18a59d210dfe4406cf166 Mon Sep 17 00:00:00 2001
From: Sean Griffin <sean@seantheprogrammer.com>
Date: Tue, 18 Jul 2017 10:33:53 -0400
Subject: Remove deprecated code concerning dirty methods in after callbacks

---
 .../lib/active_record/attribute_methods/dirty.rb   | 87 ++--------------------
 activerecord/test/cases/dirty_test.rb              |  7 +-
 2 files changed, 11 insertions(+), 83 deletions(-)

(limited to 'activerecord')

diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb
index 07d194cc57..1931a58ec8 100644
--- a/activerecord/lib/active_record/attribute_methods/dirty.rb
+++ b/activerecord/lib/active_record/attribute_methods/dirty.rb
@@ -17,8 +17,8 @@ module ActiveRecord
 
         class_attribute :partial_writes, instance_writer: false, default: true
 
-        after_create { changes_internally_applied }
-        after_update { changes_internally_applied }
+        after_create { changes_applied }
+        after_update { changes_applied }
 
         # Attribute methods for "changed in last call to save?"
         attribute_method_affix(prefix: "saved_change_to_", suffix: "?")
@@ -30,25 +30,10 @@ module ActiveRecord
         attribute_method_suffix("_change_to_be_saved", "_in_database")
       end
 
-      # Attempts to +save+ the record and clears changed attributes if successful.
-      def save(*)
-        if status = super
-          changes_applied
-        end
-        status
-      end
-
-      # Attempts to <tt>save!</tt> the record and clears changed attributes if successful.
-      def save!(*)
-        super.tap do
-          changes_applied
-        end
-      end
-
       # <tt>reload</tt> the record and clears changed attributes.
       def reload(*)
         super.tap do
-          @previous_mutation_tracker = nil
+          @mutations_before_last_save = nil
           clear_mutation_trackers
           @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
         end
@@ -62,20 +47,16 @@ module ActiveRecord
         clear_mutation_trackers
       end
 
-      def changes_internally_applied # :nodoc:
+      def changes_applied
         @mutations_before_last_save = mutation_tracker
-        forget_attribute_assignments
         @mutations_from_database = AttributeMutationTracker.new(@attributes)
-      end
-
-      def changes_applied
-        @previous_mutation_tracker = mutation_tracker
         @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
+        forget_attribute_assignments
         clear_mutation_trackers
       end
 
       def clear_changes_information
-        @previous_mutation_tracker = nil
+        @mutations_before_last_save = nil
         @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
         forget_attribute_assignments
         clear_mutation_trackers
@@ -100,28 +81,18 @@ module ActiveRecord
         if defined?(@cached_changed_attributes)
           @cached_changed_attributes
         else
-          emit_warning_if_needed("changed_attributes", "saved_changes.transform_values(&:first)")
           super.reverse_merge(mutation_tracker.changed_values).freeze
         end
       end
 
       def changes
         cache_changed_attributes do
-          emit_warning_if_needed("changes", "saved_changes")
           super
         end
       end
 
       def previous_changes
-        unless previous_mutation_tracker.equal?(mutations_before_last_save)
-          ActiveSupport::Deprecation.warn(<<-EOW.strip_heredoc)
-            The behavior of `previous_changes` inside of after callbacks is
-            deprecated without replacement. In the next release of Rails,
-            this method inside of `after_save` will return the changes that
-            were just saved.
-          EOW
-        end
-        previous_mutation_tracker.changes
+        mutations_before_last_save.changes
       end
 
       def attribute_changed_in_place?(attr_name)
@@ -211,31 +182,6 @@ module ActiveRecord
         changes_to_save.transform_values(&:first)
       end
 
-      def attribute_was(*)
-        emit_warning_if_needed("attribute_was", "attribute_before_last_save")
-        super
-      end
-
-      def attribute_change(*)
-        emit_warning_if_needed("attribute_change", "saved_change_to_attribute")
-        super
-      end
-
-      def attribute_changed?(*)
-        emit_warning_if_needed("attribute_changed?", "saved_change_to_attribute?")
-        super
-      end
-
-      def changed?(*)
-        emit_warning_if_needed("changed?", "saved_changes?")
-        super
-      end
-
-      def changed(*)
-        emit_warning_if_needed("changed", "saved_changes.keys")
-        super
-      end
-
       private
 
         def mutation_tracker
@@ -245,18 +191,6 @@ module ActiveRecord
           @mutation_tracker ||= AttributeMutationTracker.new(@attributes)
         end
 
-        def emit_warning_if_needed(method_name, new_method_name)
-          unless mutation_tracker.equal?(mutations_from_database)
-            ActiveSupport::Deprecation.warn(<<-EOW.squish)
-              The behavior of `#{method_name}` inside of after callbacks will
-              be changing in the next version of Rails. The new return value will reflect the
-              behavior of calling the method after `save` returned (e.g. the opposite of what
-              it returns now). To maintain the current behavior, use `#{new_method_name}`
-              instead.
-            EOW
-          end
-        end
-
         def mutations_from_database
           unless defined?(@mutations_from_database)
             @mutations_from_database = nil
@@ -307,15 +241,10 @@ module ActiveRecord
         def clear_mutation_trackers
           @mutation_tracker = nil
           @mutations_from_database = nil
-          @mutations_before_last_save = nil
-        end
-
-        def previous_mutation_tracker
-          @previous_mutation_tracker ||= NullMutationTracker.instance
         end
 
         def mutations_before_last_save
-          @mutations_before_last_save ||= previous_mutation_tracker
+          @mutations_before_last_save ||= NullMutationTracker.instance
         end
 
         def cache_changed_attributes
diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb
index f72e0d2ead..6a5ec8214e 100644
--- a/activerecord/test/cases/dirty_test.rb
+++ b/activerecord/test/cases/dirty_test.rb
@@ -839,15 +839,14 @@ class DirtyTest < ActiveRecord::TestCase
     assert_equal %w(first_name lock_version updated_at).sort, person.saved_changes.keys.sort
   end
 
-  test "changed? in after callbacks returns true but is deprecated" do
+  test "changed? in after callbacks returns false" do
     klass = Class.new(ActiveRecord::Base) do
       self.table_name = "people"
 
       after_save do
-        ActiveSupport::Deprecation.silence do
-          raise "changed? should be true" unless changed?
-        end
+        raise "changed? should be false" if changed?
         raise "has_changes_to_save? should be false" if has_changes_to_save?
+        rause "saved_changes? should be true" unless saved_changes?
       end
     end
 
-- 
cgit v1.2.3


From c0d8f587757670b3b717f196ba024be9ee60aef6 Mon Sep 17 00:00:00 2001
From: Sean Griffin <sean@seantheprogrammer.com>
Date: Tue, 18 Jul 2017 10:37:31 -0400
Subject: Remove deprecated code concerning non-attributes and `*_will_change!`

---
 activerecord/lib/active_record/attribute_methods/dirty.rb    | 12 +-----------
 activerecord/lib/active_record/attribute_mutation_tracker.rb |  9 ++-------
 activerecord/test/cases/dirty_test.rb                        |  8 +++-----
 activerecord/test/models/parrot.rb                           |  2 +-
 4 files changed, 7 insertions(+), 24 deletions(-)

(limited to 'activerecord')

diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb
index 1931a58ec8..5efe051125 100644
--- a/activerecord/lib/active_record/attribute_methods/dirty.rb
+++ b/activerecord/lib/active_record/attribute_methods/dirty.rb
@@ -209,17 +209,7 @@ module ActiveRecord
 
         def attribute_will_change!(attr_name)
           super
-          if self.class.has_attribute?(attr_name)
-            mutations_from_database.force_change(attr_name)
-          else
-            ActiveSupport::Deprecation.warn(<<-EOW.squish)
-              #{attr_name} is not an attribute known to Active Record.
-              This behavior is deprecated and will be removed in the next
-              version of Rails. If you'd like #{attr_name} to be managed
-              by Active Record, add `attribute :#{attr_name}` to your class.
-            EOW
-            mutations_from_database.deprecated_force_change(attr_name)
-          end
+          mutations_from_database.force_change(attr_name)
         end
 
         def _update_record(*)
diff --git a/activerecord/lib/active_record/attribute_mutation_tracker.rb b/activerecord/lib/active_record/attribute_mutation_tracker.rb
index a01a58f8a5..e275ae72ba 100644
--- a/activerecord/lib/active_record/attribute_mutation_tracker.rb
+++ b/activerecord/lib/active_record/attribute_mutation_tracker.rb
@@ -5,7 +5,6 @@ module ActiveRecord
     def initialize(attributes)
       @attributes = attributes
       @forced_changes = Set.new
-      @deprecated_forced_changes = Set.new
     end
 
     def changed_values
@@ -33,7 +32,7 @@ module ActiveRecord
     end
 
     def any_changes?
-      attr_names.any? { |attr| changed?(attr) } || deprecated_forced_changes.any?
+      attr_names.any? { |attr| changed?(attr) }
     end
 
     def changed?(attr_name, from: OPTION_NOT_GIVEN, to: OPTION_NOT_GIVEN)
@@ -62,15 +61,11 @@ module ActiveRecord
       forced_changes << attr_name.to_s
     end
 
-    def deprecated_force_change(attr_name)
-      deprecated_forced_changes << attr_name.to_s
-    end
-
     # TODO Change this to private once we've dropped Ruby 2.2 support.
     # Workaround for Ruby 2.2 "private attribute?" warning.
     protected
 
-      attr_reader :attributes, :forced_changes, :deprecated_forced_changes
+      attr_reader :attributes, :forced_changes
 
     private
 
diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb
index 6a5ec8214e..9f57bd5e7f 100644
--- a/activerecord/test/cases/dirty_test.rb
+++ b/activerecord/test/cases/dirty_test.rb
@@ -299,11 +299,9 @@ class DirtyTest < ActiveRecord::TestCase
   end
 
   def test_virtual_attribute_will_change
-    assert_deprecated do
-      parrot = Parrot.create!(name: "Ruby")
-      parrot.send(:attribute_will_change!, :cancel_save_from_callback)
-      assert parrot.has_changes_to_save?
-    end
+    parrot = Parrot.create!(name: "Ruby")
+    parrot.send(:attribute_will_change!, :cancel_save_from_callback)
+    assert parrot.has_changes_to_save?
   end
 
   def test_association_assignment_changes_foreign_key
diff --git a/activerecord/test/models/parrot.rb b/activerecord/test/models/parrot.rb
index 1e5f9285a8..255ac19365 100644
--- a/activerecord/test/models/parrot.rb
+++ b/activerecord/test/models/parrot.rb
@@ -8,7 +8,7 @@ class Parrot < ActiveRecord::Base
 
   validates_presence_of :name
 
-  attr_accessor :cancel_save_from_callback
+  attribute :cancel_save_from_callback
   before_save :cancel_save_callback_method, if: :cancel_save_from_callback
   def cancel_save_callback_method
     throw(:abort)
-- 
cgit v1.2.3


From b623a62c7f484992b6c639a10bfcb15be6e98e9f Mon Sep 17 00:00:00 2001
From: Ryuta Kamizono <kamipo@gmail.com>
Date: Wed, 19 Jul 2017 00:08:00 +0900
Subject: Fix typo s/rause/raise/

---
 activerecord/test/cases/dirty_test.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'activerecord')

diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb
index 9f57bd5e7f..bb584b0c6f 100644
--- a/activerecord/test/cases/dirty_test.rb
+++ b/activerecord/test/cases/dirty_test.rb
@@ -844,7 +844,7 @@ class DirtyTest < ActiveRecord::TestCase
       after_save do
         raise "changed? should be false" if changed?
         raise "has_changes_to_save? should be false" if has_changes_to_save?
-        rause "saved_changes? should be true" unless saved_changes?
+        raise "saved_changes? should be true" unless saved_changes?
       end
     end
 
-- 
cgit v1.2.3


From d13f54d50a166d49c683f79d49341185788faed8 Mon Sep 17 00:00:00 2001
From: Ryuta Kamizono <kamipo@gmail.com>
Date: Tue, 18 Jul 2017 10:22:05 +0900
Subject: Fix unscoping `default_scope` in STI associations

Since 5c71000, it has lost to be able to unscope `default_scope` in STI
associations. This change will use `.empty_scope?` instead of
`.values.empty?` to regard as an empty scope if only have
`type_condition`.
---
 activerecord/lib/active_record/reflection.rb            |  6 ++++--
 activerecord/lib/active_record/relation.rb              |  4 ++++
 activerecord/test/cases/scoping/default_scoping_test.rb | 16 ++++++++++++++++
 activerecord/test/models/comment.rb                     |  1 +
 activerecord/test/schema/schema.rb                      |  1 +
 5 files changed, 26 insertions(+), 2 deletions(-)

(limited to 'activerecord')

diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index 4f53280b5c..1026e20f79 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -219,8 +219,10 @@ module ActiveRecord
       end
 
       def klass_join_scope(table, predicate_builder) # :nodoc:
-        if klass.current_scope && klass.current_scope.values.empty?
-          klass.unscoped
+        current_scope = klass.current_scope
+
+        if current_scope && current_scope.empty_scope?
+          build_scope(table, predicate_builder)
         else
           klass.default_scoped(build_scope(table, predicate_builder))
         end
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index c5d98e970a..d9e1e5c39c 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -642,6 +642,10 @@ module ActiveRecord
       "#<#{self.class.name} [#{entries.join(', ')}]>"
     end
 
+    def empty_scope? # :nodoc:
+      @values == klass.unscoped.values
+    end
+
     protected
 
       def load_records(records)
diff --git a/activerecord/test/cases/scoping/default_scoping_test.rb b/activerecord/test/cases/scoping/default_scoping_test.rb
index a5061cfce7..83f3868f3f 100644
--- a/activerecord/test/cases/scoping/default_scoping_test.rb
+++ b/activerecord/test/cases/scoping/default_scoping_test.rb
@@ -392,6 +392,22 @@ class DefaultScopingTest < ActiveRecord::TestCase
                  Comment.joins(:post).to_a
   end
 
+  def test_sti_association_with_unscoped_not_affected_by_default_scope
+    post = posts(:thinking)
+    comments = [comments(:does_it_hurt)]
+
+    post.special_comments.update_all(deleted_at: Time.now)
+
+    assert_raises(ActiveRecord::RecordNotFound) { Post.joins(:special_comments).find(post.id) }
+    assert_equal [], post.special_comments
+
+    SpecialComment.unscoped do
+      assert_equal post, Post.joins(:special_comments).find(post.id)
+      assert_equal comments, Post.joins(:special_comments).find(post.id).special_comments
+      assert_equal comments, Post.eager_load(:special_comments).find(post.id).special_comments
+    end
+  end
+
   def test_default_scope_select_ignored_by_aggregations
     assert_equal DeveloperWithSelect.all.to_a.count, DeveloperWithSelect.count
   end
diff --git a/activerecord/test/models/comment.rb b/activerecord/test/models/comment.rb
index eecf923046..dc2d421cd7 100644
--- a/activerecord/test/models/comment.rb
+++ b/activerecord/test/models/comment.rb
@@ -54,6 +54,7 @@ class Comment < ActiveRecord::Base
 end
 
 class SpecialComment < Comment
+  default_scope { where(deleted_at: nil) }
 end
 
 class SubSpecialComment < SpecialComment
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index f534e9c00e..90185ff6c5 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -189,6 +189,7 @@ ActiveRecord::Schema.define do
     t.string :resource_id
     t.string :resource_type
     t.integer :developer_id
+    t.datetime :deleted_at
   end
 
   create_table :companies, force: true do |t|
-- 
cgit v1.2.3


From 9aa04315febfb37b50f52471a2837c40313a2d5f Mon Sep 17 00:00:00 2001
From: Ryuta Kamizono <kamipo@gmail.com>
Date: Tue, 18 Jul 2017 10:39:09 +0900
Subject: Fix unscoping `default_scope` for `Preloader`

---
 .../lib/active_record/associations/preloader/association.rb  | 12 +++++++++++-
 activerecord/test/cases/scoping/default_scoping_test.rb      |  2 ++
 2 files changed, 13 insertions(+), 1 deletion(-)

(limited to 'activerecord')

diff --git a/activerecord/lib/active_record/associations/preloader/association.rb b/activerecord/lib/active_record/associations/preloader/association.rb
index 85343040db..698fd29beb 100644
--- a/activerecord/lib/active_record/associations/preloader/association.rb
+++ b/activerecord/lib/active_record/associations/preloader/association.rb
@@ -114,8 +114,18 @@ module ActiveRecord
             @reflection_scope ||= reflection.scope_for(klass)
           end
 
+          def klass_scope
+            current_scope = klass.current_scope
+
+            if current_scope && current_scope.empty_scope?
+              klass.unscoped
+            else
+              klass.default_scoped
+            end
+          end
+
           def build_scope
-            scope = klass.default_scoped
+            scope = klass_scope
 
             if reflection.type
               scope.where!(reflection.type => model.base_class.sti_name)
diff --git a/activerecord/test/cases/scoping/default_scoping_test.rb b/activerecord/test/cases/scoping/default_scoping_test.rb
index 83f3868f3f..a8c79628e7 100644
--- a/activerecord/test/cases/scoping/default_scoping_test.rb
+++ b/activerecord/test/cases/scoping/default_scoping_test.rb
@@ -405,6 +405,8 @@ class DefaultScopingTest < ActiveRecord::TestCase
       assert_equal post, Post.joins(:special_comments).find(post.id)
       assert_equal comments, Post.joins(:special_comments).find(post.id).special_comments
       assert_equal comments, Post.eager_load(:special_comments).find(post.id).special_comments
+      assert_equal comments, Post.includes(:special_comments).find(post.id).special_comments
+      assert_equal comments, Post.preload(:special_comments).find(post.id).special_comments
     end
   end
 
-- 
cgit v1.2.3


From 8ebe1f2feed30809abb3f114242dda7379e66e4b Mon Sep 17 00:00:00 2001
From: Sean Griffin <sean@seantheprogrammer.com>
Date: Tue, 18 Jul 2017 13:04:47 -0400
Subject: Don't convert dates to strings when using prepared statements in
 mysql

Dates are able to be natively handled by the mysql2 gem. libmysql (and
the wire protocol) represent each portion of the date as an integer,
which is significantly faster to encode and decode. By passing the Ruby
date objects through directly, we can save a good bit of time and
memory.
---
 .../lib/active_record/connection_adapters/mysql/quoting.rb |  8 ++++++++
 activerecord/test/cases/quoting_test.rb                    | 14 +++++++++++---
 2 files changed, 19 insertions(+), 3 deletions(-)

(limited to 'activerecord')

diff --git a/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb b/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb
index d4f5906b33..0cc0ac74fe 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb
@@ -39,6 +39,14 @@ module ActiveRecord
         def quoted_binary(value)
           "x'#{value.hex}'"
         end
+
+        def _type_cast(value)
+          case value
+          when Type::Time::Value then value.__getobj__
+          when Date, Time then value
+          else super
+          end
+        end
       end
     end
   end
diff --git a/activerecord/test/cases/quoting_test.rb b/activerecord/test/cases/quoting_test.rb
index b21adccc4b..98b20915c6 100644
--- a/activerecord/test/cases/quoting_test.rb
+++ b/activerecord/test/cases/quoting_test.rb
@@ -174,13 +174,21 @@ module ActiveRecord
 
       def test_type_cast_date
         date = Date.today
-        expected = @conn.quoted_date(date)
+        if current_adapter?(:Mysql2Adapter)
+          expected = date
+        else
+          expected = @conn.quoted_date(date)
+        end
         assert_equal expected, @conn.type_cast(date)
       end
 
       def test_type_cast_time
         time = Time.now
-        expected = @conn.quoted_date(time)
+        if current_adapter?(:Mysql2Adapter)
+          expected = time
+        else
+          expected = @conn.quoted_date(time)
+        end
         assert_equal expected, @conn.type_cast(time)
       end
 
@@ -257,7 +265,7 @@ module ActiveRecord
 
         def test_type_cast_ar_object
           value = DatetimePrimaryKey.new(id: @time)
-          assert_equal "2017-02-14 12:34:56.789000",  @connection.type_cast(value)
+          assert_equal @connection.type_cast(value.id),  @connection.type_cast(value)
         end
       end
     end
-- 
cgit v1.2.3