aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/CHANGELOG.md4
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb17
-rw-r--r--actionpack/test/controller/parameters/accessors_test.rb9
-rw-r--r--actionpack/test/controller/parameters/mutators_test.rb9
-rw-r--r--activerecord/lib/active_record/associations/collection_proxy.rb2
-rw-r--r--activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb10
-rw-r--r--activerecord/test/cases/calculations_test.rb15
-rw-r--r--activerecord/test/cases/relations_test.rb2
-rw-r--r--guides/source/engines.md57
9 files changed, 81 insertions, 44 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 32721ac233..a84f72eca9 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,3 +1,7 @@
+* Added `deep_transform_keys` and `deep_transform_keys!` methods to ActionController::Parameters.
+
+ *Gustavo Gutierrez*
+
* Calling `ActionController::Parameters#transform_keys/!` without a block now returns
an enumerator for the parameters instead of the underlying hash.
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index 016a633f71..6a07a73d94 100644
--- a/actionpack/lib/action_controller/metal/strong_parameters.rb
+++ b/actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -693,6 +693,23 @@ module ActionController
self
end
+ # Returns a new <tt>ActionController::Parameters</tt> instance with the
+ # results of running +block+ once for every key. This includes the keys
+ # from the root hash and from all nested hashes and arrays. The values are unchanged.
+ def deep_transform_keys(&block)
+ new_instance_with_inherited_permitted_status(
+ @parameters.deep_transform_keys(&block)
+ )
+ end
+
+ # Returns the <tt>ActionController::Parameters</tt> instance changing its keys.
+ # This includes the keys from the root hash and from all nested hashes and arrays.
+ # The values are unchanged.
+ def deep_transform_keys!(&block)
+ @parameters.deep_transform_keys!(&block)
+ self
+ end
+
# Deletes a key-value pair from +Parameters+ and returns the value. If
# +key+ is not found, returns +nil+ (or, with optional code block, yields
# +key+ and returns the result). Cf. +#extract!+, which returns the
diff --git a/actionpack/test/controller/parameters/accessors_test.rb b/actionpack/test/controller/parameters/accessors_test.rb
index 7b9b716a42..cb49eeb1b7 100644
--- a/actionpack/test/controller/parameters/accessors_test.rb
+++ b/actionpack/test/controller/parameters/accessors_test.rb
@@ -213,6 +213,15 @@ class ParametersAccessorsTest < ActiveSupport::TestCase
assert_kind_of ActionController::Parameters, @params.transform_keys!.each { |k| k }
end
+ test "deep_transform_keys retains permitted status" do
+ @params.permit!
+ assert_predicate @params.deep_transform_keys { |k| k }, :permitted?
+ end
+
+ test "deep_transform_keys retains unpermitted status" do
+ assert_not_predicate @params.deep_transform_keys { |k| k }, :permitted?
+ end
+
test "transform_values retains permitted status" do
@params.permit!
assert_predicate @params.transform_values { |v| v }, :permitted?
diff --git a/actionpack/test/controller/parameters/mutators_test.rb b/actionpack/test/controller/parameters/mutators_test.rb
index 312b1e5b27..31ee7964f5 100644
--- a/actionpack/test/controller/parameters/mutators_test.rb
+++ b/actionpack/test/controller/parameters/mutators_test.rb
@@ -118,4 +118,13 @@ class ParametersMutatorsTest < ActiveSupport::TestCase
test "transform_values! retains unpermitted status" do
assert_not_predicate @params.transform_values! { |v| v }, :permitted?
end
+
+ test "deep_transform_keys! retains permitted status" do
+ @params.permit!
+ assert_predicate @params.deep_transform_keys! { |k| k }, :permitted?
+ end
+
+ test "deep_transform_keys! retains unpermitted status" do
+ assert_not_predicate @params.deep_transform_keys! { |k| k }, :permitted?
+ end
end
diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb
index 85e0f076da..797d647900 100644
--- a/activerecord/lib/active_record/associations/collection_proxy.rb
+++ b/activerecord/lib/active_record/associations/collection_proxy.rb
@@ -1029,7 +1029,7 @@ module ActiveRecord
alias_method :append, :<<
alias_method :concat, :<<
- def prepend(*args)
+ def prepend(*args) # :nodoc:
raise NoMethodError, "prepend on association is not defined. Please use <<, push or append"
end
diff --git a/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb b/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb
index c32475c683..3756f74c95 100644
--- a/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb
@@ -22,7 +22,7 @@ class Mysql2CaseSensitivityTest < ActiveRecord::Mysql2TestCase
CollationTest.validates_uniqueness_of(:string_ci_column, case_sensitive: false)
CollationTest.create!(string_ci_column: "A")
invalid = CollationTest.new(string_ci_column: "a")
- queries = assert_sql { invalid.save }
+ queries = capture_sql { invalid.save }
ci_uniqueness_query = queries.detect { |q| q.match(/string_ci_column/) }
assert_no_match(/lower/i, ci_uniqueness_query)
end
@@ -31,7 +31,7 @@ class Mysql2CaseSensitivityTest < ActiveRecord::Mysql2TestCase
CollationTest.validates_uniqueness_of(:string_cs_column, case_sensitive: false)
CollationTest.create!(string_cs_column: "A")
invalid = CollationTest.new(string_cs_column: "a")
- queries = assert_sql { invalid.save }
+ queries = capture_sql { invalid.save }
cs_uniqueness_query = queries.detect { |q| q.match(/string_cs_column/) }
assert_match(/lower/i, cs_uniqueness_query)
end
@@ -40,7 +40,7 @@ class Mysql2CaseSensitivityTest < ActiveRecord::Mysql2TestCase
CollationTest.validates_uniqueness_of(:string_ci_column, case_sensitive: true)
CollationTest.create!(string_ci_column: "A")
invalid = CollationTest.new(string_ci_column: "A")
- queries = assert_sql { invalid.save }
+ queries = capture_sql { invalid.save }
ci_uniqueness_query = queries.detect { |q| q.match(/string_ci_column/) }
assert_match(/binary/i, ci_uniqueness_query)
end
@@ -49,7 +49,7 @@ class Mysql2CaseSensitivityTest < ActiveRecord::Mysql2TestCase
CollationTest.validates_uniqueness_of(:string_cs_column, case_sensitive: true)
CollationTest.create!(string_cs_column: "A")
invalid = CollationTest.new(string_cs_column: "A")
- queries = assert_sql { invalid.save }
+ queries = capture_sql { invalid.save }
cs_uniqueness_query = queries.detect { |q| q.match(/string_cs_column/) }
assert_no_match(/binary/i, cs_uniqueness_query)
end
@@ -58,7 +58,7 @@ class Mysql2CaseSensitivityTest < ActiveRecord::Mysql2TestCase
CollationTest.validates_uniqueness_of(:binary_column, case_sensitive: true)
CollationTest.create!(binary_column: "A")
invalid = CollationTest.new(binary_column: "A")
- queries = assert_sql { invalid.save }
+ queries = capture_sql { invalid.save }
bin_uniqueness_query = queries.detect { |q| q.match(/binary_column/) }
assert_no_match(/\bBINARY\b/, bin_uniqueness_query)
end
diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb
index 33475e2e09..0d13174e12 100644
--- a/activerecord/test/cases/calculations_test.rb
+++ b/activerecord/test/cases/calculations_test.rb
@@ -185,7 +185,7 @@ class CalculationsTest < ActiveRecord::TestCase
def test_limit_is_kept
return if current_adapter?(:OracleAdapter)
- queries = assert_sql { Account.limit(1).count }
+ queries = capture_sql { Account.limit(1).count }
assert_equal 1, queries.length
assert_match(/LIMIT/, queries.first)
end
@@ -193,7 +193,7 @@ class CalculationsTest < ActiveRecord::TestCase
def test_offset_is_kept
return if current_adapter?(:OracleAdapter)
- queries = assert_sql { Account.offset(1).count }
+ queries = capture_sql { Account.offset(1).count }
assert_equal 1, queries.length
assert_match(/OFFSET/, queries.first)
end
@@ -201,14 +201,14 @@ class CalculationsTest < ActiveRecord::TestCase
def test_limit_with_offset_is_kept
return if current_adapter?(:OracleAdapter)
- queries = assert_sql { Account.limit(1).offset(1).count }
+ queries = capture_sql { Account.limit(1).offset(1).count }
assert_equal 1, queries.length
assert_match(/LIMIT/, queries.first)
assert_match(/OFFSET/, queries.first)
end
def test_no_limit_no_offset
- queries = assert_sql { Account.count }
+ queries = capture_sql { Account.count }
assert_equal 1, queries.length
assert_no_match(/LIMIT/, queries.first)
assert_no_match(/OFFSET/, queries.first)
@@ -224,15 +224,12 @@ class CalculationsTest < ActiveRecord::TestCase
end
def test_apply_distinct_in_count
- queries = assert_sql do
+ queries = capture_sql do
Account.distinct.count
Account.group(:firm_id).distinct.count
end
queries.each do |query|
- # `table_alias_length` in `column_alias_for` would execute
- # "SHOW max_identifier_length" statement in PostgreSQL adapter.
- next if query == "SHOW max_identifier_length"
assert_match %r{\ASELECT(?! DISTINCT) COUNT\(DISTINCT\b}, query
end
end
@@ -464,7 +461,7 @@ class CalculationsTest < ActiveRecord::TestCase
def test_should_not_perform_joined_include_by_default
assert_equal Account.count, Account.includes(:firm).count
- queries = assert_sql { Account.includes(:firm).count }
+ queries = capture_sql { Account.includes(:firm).count }
assert_no_match(/join/i, queries.last)
end
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index 2417775ef1..4ec695c4c6 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -706,7 +706,7 @@ class RelationTest < ActiveRecord::TestCase
end
def test_to_sql_on_eager_join
- expected = assert_sql {
+ expected = capture_sql {
Post.eager_load(:last_comment).order("comments.id DESC").to_a
}.first
actual = Post.eager_load(:last_comment).order("comments.id DESC").to_sql
diff --git a/guides/source/engines.md b/guides/source/engines.md
index 3031c62928..90b08b00f0 100644
--- a/guides/source/engines.md
+++ b/guides/source/engines.md
@@ -1511,34 +1511,35 @@ These are the hooks you can use in your own code.
To hook into the initialization process of one of the following classes use the available hook.
-| Class | Available Hooks |
-| --------------------------------- | ------------------------------------ |
-| `ActionCable` | `action_cable` |
-| `ActionCable::Channel::Base` | `action_cable_channel` |
-| `ActionCable::Connection::Base` | `action_cable_connection` |
-| `ActionController::API` | `action_controller_api` |
-| `ActionController::API` | `action_controller` |
-| `ActionController::Base` | `action_controller_base` |
-| `ActionController::Base` | `action_controller` |
-| `ActionController::TestCase` | `action_controller_test_case` |
-| `ActionDispatch::IntegrationTest` | `action_dispatch_integration_test` |
-| `ActionDispatch::SystemTestCase` | `action_dispatch_system_test_case` |
-| `ActionMailbox::Base` | `action_mailbox` |
-| `ActionMailbox::InboundEmail` | `action_mailbox_inbound_email` |
-| `ActionMailbox::TestCase` | `action_mailbox_test_case` |
-| `ActionMailer::Base` | `action_mailer` |
-| `ActionMailer::TestCase` | `action_mailer_test_case` |
-| `ActionText::Content` | `action_text_content` |
-| `ActionText::RichText` | `action_text_rich_text` |
-| `ActionView::Base` | `action_view` |
-| `ActionView::TestCase` | `action_view_test_case` |
-| `ActiveJob::Base` | `active_job` |
-| `ActiveJob::TestCase` | `active_job_test_case` |
-| `ActiveRecord::Base` | `active_record` |
-| `ActiveStorage::Attachment` | `active_storage_attachment` |
-| `ActiveStorage::Blob` | `active_storage_blob` |
-| `ActiveSupport::TestCase` | `active_support_test_case` |
-| `i18n` | `i18n` |
+| Class | Available Hooks |
+| -------------------------------------| ------------------------------------ |
+| `ActionCable` | `action_cable` |
+| `ActionCable::Channel::Base` | `action_cable_channel` |
+| `ActionCable::Connection::Base` | `action_cable_connection` |
+| `ActionCable::Connection::TestCase` | `action_cable_connection_test_case` |
+| `ActionController::API` | `action_controller_api` |
+| `ActionController::API` | `action_controller` |
+| `ActionController::Base` | `action_controller_base` |
+| `ActionController::Base` | `action_controller` |
+| `ActionController::TestCase` | `action_controller_test_case` |
+| `ActionDispatch::IntegrationTest` | `action_dispatch_integration_test` |
+| `ActionDispatch::SystemTestCase` | `action_dispatch_system_test_case` |
+| `ActionMailbox::Base` | `action_mailbox` |
+| `ActionMailbox::InboundEmail` | `action_mailbox_inbound_email` |
+| `ActionMailbox::TestCase` | `action_mailbox_test_case` |
+| `ActionMailer::Base` | `action_mailer` |
+| `ActionMailer::TestCase` | `action_mailer_test_case` |
+| `ActionText::Content` | `action_text_content` |
+| `ActionText::RichText` | `action_text_rich_text` |
+| `ActionView::Base` | `action_view` |
+| `ActionView::TestCase` | `action_view_test_case` |
+| `ActiveJob::Base` | `active_job` |
+| `ActiveJob::TestCase` | `active_job_test_case` |
+| `ActiveRecord::Base` | `active_record` |
+| `ActiveStorage::Attachment` | `active_storage_attachment` |
+| `ActiveStorage::Blob` | `active_storage_blob` |
+| `ActiveSupport::TestCase` | `active_support_test_case` |
+| `i18n` | `i18n` |
## Configuration hooks