aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/CHANGELOG.md6
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb10
-rw-r--r--activerecord/lib/active_record/attribute_methods.rb14
-rw-r--r--activerecord/lib/active_record/attribute_methods/dirty.rb12
-rw-r--r--activerecord/lib/active_record/persistence.rb9
-rw-r--r--activerecord/lib/active_record/reflection.rb20
-rw-r--r--activerecord/lib/active_record/result.rb4
-rw-r--r--activerecord/lib/rails/generators/active_record/migration.rb4
-rw-r--r--activerecord/lib/rails/generators/active_record/migration/migration_generator.rb1
-rw-r--r--activerecord/test/cases/associations/inverse_associations_test.rb12
-rw-r--r--guides/source/configuring.md3
-rw-r--r--guides/source/upgrading_ruby_on_rails.md11
-rw-r--r--railties/CHANGELOG.md15
-rw-r--r--railties/test/generators/migration_generator_test.rb9
14 files changed, 98 insertions, 32 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index a30f178190..0f5afc0416 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -10,8 +10,6 @@
Enable `action_dispatch.use_cookies_with_metadata` to use this feature, which
writes cookies with the new purpose and expiry metadata embedded.
- Pull Request: #32937
-
*Assain Jaleel*
* Raises `ActionController::RespondToMismatchError` with confliciting `respond_to` invocations.
@@ -39,7 +37,7 @@
*Aaron Kromer*
-* Pass along arguments to underlying `get` method in `follow_redirect!`
+* Pass along arguments to underlying `get` method in `follow_redirect!`.
Now all arguments passed to `follow_redirect!` are passed to the underlying
`get` method. This for example allows to set custom headers for the
@@ -56,7 +54,7 @@
*Vinicius Stock*
-* Introduce ActionDispatch::DebugExceptions.register_interceptor
+* Introduce `ActionDispatch::DebugExceptions.register_interceptor`.
Exception aware plugin authors can use the newly introduced
`.register_interceptor` method to get the processed exception, instead of
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index 52664dd1fb..21859e5356 100644
--- a/actionpack/lib/action_controller/metal/strong_parameters.rb
+++ b/actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -904,6 +904,16 @@ module ActionController
PERMITTED_SCALAR_TYPES.any? { |type| value.is_a?(type) }
end
+ # Adds existing keys to the params if their values are scalar.
+ #
+ # For example:
+ #
+ # puts self.keys #=> ["zipcode(90210i)"]
+ # params = {}
+ #
+ # permitted_scalar_filter(params, "zipcode")
+ #
+ # puts params.keys # => ["zipcode"]
def permitted_scalar_filter(params, key)
if has_key?(key) && permitted_scalar?(self[key])
params[key] = self[key]
diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb
index 1d18119c66..701f19a6ae 100644
--- a/activerecord/lib/active_record/attribute_methods.rb
+++ b/activerecord/lib/active_record/attribute_methods.rb
@@ -451,14 +451,6 @@ module ActiveRecord
defined?(@attributes) && @attributes.key?(attr_name)
end
- def attributes_with_values_for_create(attribute_names)
- attributes_with_values(attributes_for_create(attribute_names))
- end
-
- def attributes_with_values_for_update(attribute_names)
- attributes_with_values(attributes_for_update(attribute_names))
- end
-
def attributes_with_values(attribute_names)
attribute_names.each_with_object({}) do |name, attrs|
attrs[name] = _read_attribute(name)
@@ -467,7 +459,8 @@ module ActiveRecord
# Filters the primary keys and readonly attributes from the attribute names.
def attributes_for_update(attribute_names)
- attribute_names.reject do |name|
+ attribute_names &= self.class.column_names
+ attribute_names.delete_if do |name|
readonly_attribute?(name)
end
end
@@ -475,7 +468,8 @@ module ActiveRecord
# Filters out the primary keys, from the attribute names, when the primary
# key is to be generated (e.g. the id attribute has no value).
def attributes_for_create(attribute_names)
- attribute_names.reject do |name|
+ attribute_names &= self.class.column_names
+ attribute_names.delete_if do |name|
pk_attribute?(name) && id.nil?
end
end
diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb
index bc25837fab..ebc2252c50 100644
--- a/activerecord/lib/active_record/attribute_methods/dirty.rb
+++ b/activerecord/lib/active_record/attribute_methods/dirty.rb
@@ -164,20 +164,20 @@ module ActiveRecord
result
end
- def _update_record(*)
- affected_rows = partial_writes? ? super(keys_for_partial_write) : super
+ def _update_record(attribute_names = attribute_names_for_partial_writes)
+ affected_rows = super
changes_applied
affected_rows
end
- def _create_record(*)
- id = partial_writes? ? super(keys_for_partial_write) : super
+ def _create_record(attribute_names = attribute_names_for_partial_writes)
+ id = super
changes_applied
id
end
- def keys_for_partial_write
- changed_attribute_names_to_save & self.class.column_names
+ def attribute_names_for_partial_writes
+ partial_writes? ? changed_attribute_names_to_save : attribute_names
end
end
end
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index 05963e5546..24af56cf0b 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -718,7 +718,6 @@ module ActiveRecord
# Updates the associated record with values matching those of the instance attributes.
# Returns the number of affected rows.
def _update_record(attribute_names = self.attribute_names)
- attribute_names &= self.class.column_names
attribute_names = attributes_for_update(attribute_names)
if attribute_names.empty?
@@ -737,10 +736,12 @@ module ActiveRecord
# Creates a record with values matching those of the instance attributes
# and returns its id.
def _create_record(attribute_names = self.attribute_names)
- attribute_names &= self.class.column_names
- attributes_values = attributes_with_values_for_create(attribute_names)
+ attribute_names = attributes_for_create(attribute_names)
+
+ new_id = self.class._insert_record(
+ attributes_with_values(attribute_names)
+ )
- new_id = self.class._insert_record(attributes_values)
self.id ||= new_id if self.class.primary_key
@new_record = false
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index 6d2f75a3ae..b2110f727c 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -612,9 +612,21 @@ module ActiveRecord
# returns either +nil+ or the inverse association name that it finds.
def automatic_inverse_of
- if can_find_inverse_of_automatically?(self)
- inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_record.name.demodulize).to_sym
+ return unless can_find_inverse_of_automatically?(self)
+ inverse_name_candidates =
+ if options[:as]
+ [options[:as]]
+ else
+ active_record_name = active_record.name.demodulize
+ [active_record_name, ActiveSupport::Inflector.pluralize(active_record_name)]
+ end
+
+ inverse_name_candidates.map! do |candidate|
+ ActiveSupport::Inflector.underscore(candidate).to_sym
+ end
+
+ inverse_name_candidates.detect do |inverse_name|
begin
reflection = klass._reflect_on_association(inverse_name)
rescue NameError
@@ -623,9 +635,7 @@ module ActiveRecord
reflection = false
end
- if valid_inverse_reflection?(reflection)
- return inverse_name
- end
+ valid_inverse_reflection?(reflection)
end
end
diff --git a/activerecord/lib/active_record/result.rb b/activerecord/lib/active_record/result.rb
index 7f1c2fd7eb..3b2556b1c8 100644
--- a/activerecord/lib/active_record/result.rb
+++ b/activerecord/lib/active_record/result.rb
@@ -140,6 +140,8 @@ module ActiveRecord
# We freeze the strings to prevent them getting duped when
# used as keys in ActiveRecord::Base's @attributes hash
columns = @columns.map(&:-@)
+ length = columns.length
+
@rows.map { |row|
# In the past we used Hash[columns.zip(row)]
# though elegant, the verbose way is much more efficient
@@ -148,8 +150,6 @@ module ActiveRecord
hash = {}
index = 0
- length = columns.length
-
while index < length
hash[columns[index]] = row[index]
index += 1
diff --git a/activerecord/lib/rails/generators/active_record/migration.rb b/activerecord/lib/rails/generators/active_record/migration.rb
index 4ceb502c5d..4a17082d66 100644
--- a/activerecord/lib/rails/generators/active_record/migration.rb
+++ b/activerecord/lib/rails/generators/active_record/migration.rb
@@ -24,7 +24,9 @@ module ActiveRecord
end
def db_migrate_path
- if defined?(Rails.application) && Rails.application
+ if migrations_paths = options[:migrations_paths]
+ migrations_paths
+ elsif defined?(Rails.application) && Rails.application
Rails.application.config.paths["db/migrate"].to_ary.first
else
"db/migrate"
diff --git a/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb b/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb
index a07b00ef79..281b7afb50 100644
--- a/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb
+++ b/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb
@@ -8,6 +8,7 @@ module ActiveRecord
argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]"
class_option :primary_key_type, type: :string, desc: "The type for primary key"
+ class_option :migrations_paths, type: :string, desc: "The migration path for your generated migrations. If this is not set it will default to db/migrate"
def create_migration_file
set_local_assigns!
diff --git a/activerecord/test/cases/associations/inverse_associations_test.rb b/activerecord/test/cases/associations/inverse_associations_test.rb
index da3a42e2b5..eb4dc73423 100644
--- a/activerecord/test/cases/associations/inverse_associations_test.rb
+++ b/activerecord/test/cases/associations/inverse_associations_test.rb
@@ -20,6 +20,8 @@ require "models/company"
require "models/project"
require "models/author"
require "models/post"
+require "models/department"
+require "models/hotel"
class AutomaticInverseFindingTests < ActiveRecord::TestCase
fixtures :ratings, :comments, :cars
@@ -724,6 +726,16 @@ class InversePolymorphicBelongsToTests < ActiveRecord::TestCase
# fails because Interest does have the correct inverse_of
assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) { Face.first.polymorphic_man = Interest.first }
end
+
+ def test_favors_has_one_associations_for_inverse_of
+ inverse_name = Post.reflect_on_association(:author).inverse_of.name
+ assert_equal :post, inverse_name
+ end
+
+ def test_finds_inverse_of_for_plural_associations
+ inverse_name = Department.reflect_on_association(:hotel).inverse_of.name
+ assert_equal :departments, inverse_name
+ end
end
# NOTE - these tests might not be meaningful, ripped as they were from the parental_control plugin
diff --git a/guides/source/configuring.md b/guides/source/configuring.md
index 35cd2cc843..8c95187fa4 100644
--- a/guides/source/configuring.md
+++ b/guides/source/configuring.md
@@ -516,6 +516,9 @@ Defaults to `'signed cookie'`.
signed and encrypted cookies use the AES-256-GCM cipher or
the older AES-256-CBC cipher. It defaults to `true`.
+* `config.action_dispatch.use_cookies_with_metadata` enables writing
+ cookies with the purpose and expiry metadata embedded. It defaults to `true`.
+
* `config.action_dispatch.perform_deep_munge` configures whether `deep_munge`
method should be performed on the parameters. See [Security Guide](security.html#unsafe-query-generation)
for more information. It defaults to `true`.
diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md
index 3f8edd953d..befd4e08c0 100644
--- a/guides/source/upgrading_ruby_on_rails.md
+++ b/guides/source/upgrading_ruby_on_rails.md
@@ -85,6 +85,17 @@ Rails 6.1. You are encouraged to enable `config.force_ssl` to enforce HTTPS
connections throughout your application. If you need to exempt certain endpoints
from redirection, you can use `config.ssl_options` to configure that behavior.
+### Purpose in signed or encrypted cookie is now embedded in the cookies values
+
+To improve security, Rails now embeds the purpose information in encrypted or signed cookies value.
+Rails can now thwart attacks that attempt to copy signed/encrypted value
+of a cookie and use it as the value of another cookie.
+
+This new embed information make those cookies incompatible with versions of Rails older than 6.0.
+
+If you require your cookies to be read by 5.2 and older, or you are still validating your 6.0 deploy and want
+to allow you to rollback set
+`Rails.application.config.action_dispatch.use_cookies_with_metadata` to `false`.
Upgrading from Rails 5.1 to Rails 5.2
-------------------------------------
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index 2a8882171f..b855fb7da2 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,3 +1,18 @@
+* Add `--migrations_paths` option to migration generator.
+
+ If you're using multiple databases and have a folder for each database
+ for migrations (ex db/migrate and db/new_db_migrate) you can now pass the
+ `--migrations_paths` option to the generator to make sure the the migration
+ is inserted into the correct folder.
+
+ ```
+ rails g migration CreateHouses --migrations_paths=db/kingston_migrate
+ invoke active_record
+ create db/kingston_migrate/20180830151055_create_houses.rb
+ ```
+
+ *Eileen M. Uchitelle*
+
* Deprecate `rake routes` in favor of `rails routes`.
*Yuji Yaginuma*
diff --git a/railties/test/generators/migration_generator_test.rb b/railties/test/generators/migration_generator_test.rb
index 657a56354b..5c57d607fc 100644
--- a/railties/test/generators/migration_generator_test.rb
+++ b/railties/test/generators/migration_generator_test.rb
@@ -254,6 +254,15 @@ class MigrationGeneratorTest < Rails::Generators::TestCase
end
end
+ def test_migrations_paths_puts_migrations_in_that_folder
+ run_generator ["create_books", "--migrations_paths=db/test_migrate"]
+ assert_migration "db/test_migrate/create_books.rb" do |content|
+ assert_method :change, content do |change|
+ assert_match(/create_table :books/, change)
+ end
+ end
+ end
+
def test_should_create_empty_migrations_if_name_not_start_with_add_or_remove_or_create
migration = "delete_books"
run_generator [migration, "title:string", "content:text"]