aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock2
-rw-r--r--actioncable/README.md4
-rw-r--r--actionpack/CHANGELOG.md7
-rw-r--r--actionpack/lib/action_dispatch/system_testing/server.rb14
-rw-r--r--actionpack/test/dispatch/system_testing/server_test.rb4
-rw-r--r--activerecord/lib/active_record/associations.rb6
-rw-r--r--activerecord/lib/active_record/associations/builder/association.rb5
-rw-r--r--activerecord/lib/active_record/associations/preloader.rb6
-rw-r--r--activerecord/lib/active_record/associations/preloader/association.rb32
-rw-r--r--activerecord/lib/active_record/associations/preloader/belongs_to.rb7
-rw-r--r--activerecord/lib/active_record/associations/preloader/collection_association.rb11
-rw-r--r--activerecord/lib/active_record/associations/preloader/has_many.rb7
-rw-r--r--activerecord/lib/active_record/associations/preloader/has_one.rb7
-rw-r--r--activerecord/lib/active_record/associations/preloader/singular_association.rb11
-rw-r--r--activerecord/lib/active_record/associations/preloader/through_association.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/column.rb9
-rw-r--r--activerecord/lib/active_record/migration.rb4
-rw-r--r--activerecord/lib/active_record/migration/compatibility.rb15
-rw-r--r--activerecord/lib/active_record/persistence.rb94
-rw-r--r--activerecord/lib/active_record/querying.rb2
-rw-r--r--activerecord/lib/active_record/reflection.rb18
-rw-r--r--activerecord/lib/active_record/relation.rb94
-rw-r--r--activerecord/test/cases/adapters/postgresql/serial_test.rb36
-rw-r--r--activerecord/test/cases/attributes_test.rb2
-rw-r--r--activerecord/test/cases/migration/compatibility_test.rb30
-rw-r--r--activerecord/test/cases/persistence_test.rb20
-rw-r--r--activestorage/README.md4
-rw-r--r--activestorage/app/models/active_storage/variation.rb2
-rw-r--r--activestorage/config/routes.rb10
-rw-r--r--activestorage/lib/active_storage/attached/many.rb2
-rw-r--r--activestorage/lib/active_storage/attached/one.rb2
-rw-r--r--activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb12
-rw-r--r--activesupport/lib/active_support/ordered_options.rb4
-rw-r--r--guides/source/5_1_release_notes.md2
-rw-r--r--guides/source/action_controller_overview.md6
-rw-r--r--guides/source/active_job_basics.md19
-rw-r--r--guides/source/autoloading_and_reloading_constants.md8
-rw-r--r--guides/source/caching_with_rails.md4
-rw-r--r--guides/source/getting_started.md2
-rw-r--r--guides/source/i18n.md2
-rw-r--r--guides/source/plugins.md2
-rw-r--r--guides/source/security.md8
-rw-r--r--guides/source/working_with_javascript_in_rails.md2
-rw-r--r--railties/CHANGELOG.md4
-rw-r--r--railties/lib/rails/generators/rails/app/templates/Gemfile5
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/storage.yml10
-rw-r--r--railties/lib/rails/generators/rails/credentials/credentials_generator.rb2
-rw-r--r--railties/lib/rails/generators/rails/resource/USAGE2
-rw-r--r--railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb2
-rw-r--r--railties/lib/rails/generators/test_unit/generator/templates/generator_test.rb2
-rw-r--r--railties/lib/rails/generators/test_unit/integration/templates/integration_test.rb2
-rw-r--r--railties/lib/rails/generators/test_unit/mailer/templates/functional_test.rb2
-rw-r--r--railties/lib/rails/generators/test_unit/mailer/templates/preview.rb2
-rw-r--r--railties/lib/rails/generators/test_unit/model/templates/unit_test.rb2
-rw-r--r--railties/lib/rails/generators/test_unit/plugin/templates/test_helper.rb2
-rw-r--r--railties/lib/rails/generators/test_unit/scaffold/templates/api_functional_test.rb2
-rw-r--r--railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb2
-rw-r--r--railties/lib/rails/generators/test_unit/scaffold/templates/system_test.rb2
-rw-r--r--railties/lib/rails/generators/test_unit/system/templates/application_system_test_case.rb2
-rw-r--r--railties/lib/rails/generators/test_unit/system/templates/system_test.rb2
-rw-r--r--railties/test/application/rake_test.rb41
-rw-r--r--railties/test/commands/credentials_test.rb19
64 files changed, 350 insertions, 311 deletions
diff --git a/Gemfile b/Gemfile
index fda547fab2..c60241d447 100644
--- a/Gemfile
+++ b/Gemfile
@@ -15,7 +15,7 @@ gem "rake", ">= 11.1"
# be loaded after loading the test library.
gem "mocha", "~> 0.14", require: false
-gem "capybara", "~> 2.13"
+gem "capybara", "~> 2.15"
gem "rack-cache", "~> 1.2"
gem "jquery-rails"
diff --git a/Gemfile.lock b/Gemfile.lock
index 787631ada5..fb18fdc14e 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -490,7 +490,7 @@ DEPENDENCIES
blade-sauce_labs_plugin
bootsnap (>= 1.1.0)
byebug
- capybara (~> 2.13)
+ capybara (~> 2.15)
coffee-rails
dalli (>= 2.2.1)
delayed_job
diff --git a/actioncable/README.md b/actioncable/README.md
index a060e8938e..70b39ead57 100644
--- a/actioncable/README.md
+++ b/actioncable/README.md
@@ -454,9 +454,9 @@ The Ruby side of things is built on top of [websocket-driver](https://github.com
## Deployment
Action Cable is powered by a combination of WebSockets and threads. All of the
-connection management is handled internally by utilizing Ruby’s native thread
+connection management is handled internally by utilizing Ruby's native thread
support, which means you can use all your regular Rails models with no problems
-as long as you haven’t committed any thread-safety sins.
+as long as you haven't committed any thread-safety sins.
The Action Cable server does _not_ need to be a multi-threaded application server.
This is because Action Cable uses the [Rack socket hijacking API](http://www.rubydoc.info/github/rack/rack/file/SPEC#Hijacking)
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 932968fa35..a53d8efee1 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,3 +1,10 @@
+* Use Capybara registered `:puma` server config.
+
+ The Capybara registered `:puma` server ensures the puma server is run in process so
+ connection sharing and open request detection work correctly by default.
+
+ *Thomas Walpole*
+
* Cookies `:expires` option supports `ActiveSupport::Duration` object.
cookies[:user_name] = { value: "assain", expires: 1.hour }
diff --git a/actionpack/lib/action_dispatch/system_testing/server.rb b/actionpack/lib/action_dispatch/system_testing/server.rb
index 76bada8df1..32aa6a4dc4 100644
--- a/actionpack/lib/action_dispatch/system_testing/server.rb
+++ b/actionpack/lib/action_dispatch/system_testing/server.rb
@@ -12,29 +12,17 @@ module ActionDispatch
self.silence_puma = false
def run
- register
setup
end
private
- def register
- Capybara.register_server :rails_puma do |app, port, host|
- Rack::Handler::Puma.run(
- app,
- Port: port,
- Threads: "0:1",
- Silent: self.class.silence_puma
- )
- end
- end
-
def setup
set_server
set_port
end
def set_server
- Capybara.server = :rails_puma
+ Capybara.server = :puma, { Silent: self.class.silence_puma }
end
def set_port
diff --git a/actionpack/test/dispatch/system_testing/server_test.rb b/actionpack/test/dispatch/system_testing/server_test.rb
index ed65d93e49..1866225fc1 100644
--- a/actionpack/test/dispatch/system_testing/server_test.rb
+++ b/actionpack/test/dispatch/system_testing/server_test.rb
@@ -9,10 +9,6 @@ class ServerTest < ActiveSupport::TestCase
ActionDispatch::SystemTesting::Server.new.run
end
- test "initializing the server port" do
- assert_includes Capybara.servers, :rails_puma
- end
-
test "port is always included" do
assert Capybara.always_include_port, "expected Capybara.always_include_port to be true"
end
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index a61c0336db..ef26f4a20c 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1400,7 +1400,7 @@ module ActiveRecord
# has_many :tags, as: :taggable
# has_many :reports, -> { readonly }
# has_many :subscribers, through: :subscriptions, source: :user
- def has_many(name, scope = nil, options = {}, &extension)
+ def has_many(name, scope = nil, **options, &extension)
reflection = Builder::HasMany.build(self, name, scope, options, &extension)
Reflection.add_reflection self, name, reflection
end
@@ -1534,7 +1534,7 @@ module ActiveRecord
# has_one :club, through: :membership
# has_one :primary_address, -> { where(primary: true) }, through: :addressables, source: :addressable
# has_one :credit_card, required: true
- def has_one(name, scope = nil, options = {})
+ def has_one(name, scope = nil, **options)
reflection = Builder::HasOne.build(self, name, scope, options)
Reflection.add_reflection self, name, reflection
end
@@ -1678,7 +1678,7 @@ module ActiveRecord
# belongs_to :company, touch: :employees_last_updated_at
# belongs_to :user, optional: true
# belongs_to :account, default: -> { company.account }
- def belongs_to(name, scope = nil, options = {})
+ def belongs_to(name, scope = nil, **options)
reflection = Builder::BelongsTo.build(self, name, scope, options)
Reflection.add_reflection self, name, reflection
end
diff --git a/activerecord/lib/active_record/associations/builder/association.rb b/activerecord/lib/active_record/associations/builder/association.rb
index 496b16b58f..ca3032d967 100644
--- a/activerecord/lib/active_record/associations/builder/association.rb
+++ b/activerecord/lib/active_record/associations/builder/association.rb
@@ -38,11 +38,6 @@ module ActiveRecord::Associations::Builder # :nodoc:
def self.create_reflection(model, name, scope, options, extension = nil)
raise ArgumentError, "association names must be a Symbol" unless name.kind_of?(Symbol)
- if scope.is_a?(Hash)
- options = scope
- scope = nil
- end
-
validate_options(options)
scope = build_scope(scope, extension)
diff --git a/activerecord/lib/active_record/associations/preloader.rb b/activerecord/lib/active_record/associations/preloader.rb
index 62caf02a2c..e1754d4a19 100644
--- a/activerecord/lib/active_record/associations/preloader.rb
+++ b/activerecord/lib/active_record/associations/preloader.rb
@@ -91,13 +91,13 @@ module ActiveRecord
# { author: :avatar }
# [ :books, { author: :avatar } ]
def preload(records, associations, preload_scope = nil)
- records = Array.wrap(records).compact.uniq
- associations = Array.wrap(associations)
+ records = records.compact
if records.empty?
[]
else
- associations.flat_map { |association|
+ records.uniq!
+ Array.wrap(associations).flat_map { |association|
preloaders_on association, records, preload_scope
}
end
diff --git a/activerecord/lib/active_record/associations/preloader/association.rb b/activerecord/lib/active_record/associations/preloader/association.rb
index 9bb6a613e1..fe696e0d6e 100644
--- a/activerecord/lib/active_record/associations/preloader/association.rb
+++ b/activerecord/lib/active_record/associations/preloader/association.rb
@@ -17,26 +17,20 @@ module ActiveRecord
end
def run(preloader)
- preload(preloader)
- end
-
- def preload(preloader)
- raise NotImplementedError
- end
-
- # The name of the key on the associated records
- def association_key_name
- raise NotImplementedError
- end
-
- # The name of the key on the model which declares the association
- def owner_key_name
- raise NotImplementedError
+ associated_records_by_owner(preloader).each do |owner, records|
+ associate_records_to_owner(owner, records)
+ end
end
private
- def options
- reflection.options
+ # The name of the key on the associated records
+ def association_key_name
+ reflection.join_primary_key(klass)
+ end
+
+ # The name of the key on the model which declares the association
+ def owner_key_name
+ reflection.join_foreign_key
end
def associated_records_by_owner(preloader)
@@ -51,6 +45,10 @@ module ActiveRecord
end
end
+ def associate_records_to_owner(owner, records)
+ raise NotImplementedError
+ end
+
def owner_keys
unless defined?(@owner_keys)
@owner_keys = owners.map do |owner|
diff --git a/activerecord/lib/active_record/associations/preloader/belongs_to.rb b/activerecord/lib/active_record/associations/preloader/belongs_to.rb
index ae9695f26a..a8e3340b23 100644
--- a/activerecord/lib/active_record/associations/preloader/belongs_to.rb
+++ b/activerecord/lib/active_record/associations/preloader/belongs_to.rb
@@ -4,13 +4,6 @@ module ActiveRecord
module Associations
class Preloader
class BelongsTo < SingularAssociation #:nodoc:
- def association_key_name
- options[:primary_key] || klass && klass.primary_key
- end
-
- def owner_key_name
- reflection.foreign_key
- end
end
end
end
diff --git a/activerecord/lib/active_record/associations/preloader/collection_association.rb b/activerecord/lib/active_record/associations/preloader/collection_association.rb
index fb920a642c..fc2029f54a 100644
--- a/activerecord/lib/active_record/associations/preloader/collection_association.rb
+++ b/activerecord/lib/active_record/associations/preloader/collection_association.rb
@@ -5,13 +5,10 @@ module ActiveRecord
class Preloader
class CollectionAssociation < Association #:nodoc:
private
-
- def preload(preloader)
- associated_records_by_owner(preloader).each do |owner, records|
- association = owner.association(reflection.name)
- association.loaded!
- association.target.concat(records)
- end
+ def associate_records_to_owner(owner, records)
+ association = owner.association(reflection.name)
+ association.loaded!
+ association.target.concat(records)
end
end
end
diff --git a/activerecord/lib/active_record/associations/preloader/has_many.rb b/activerecord/lib/active_record/associations/preloader/has_many.rb
index 29a1ce099d..72f55bc43f 100644
--- a/activerecord/lib/active_record/associations/preloader/has_many.rb
+++ b/activerecord/lib/active_record/associations/preloader/has_many.rb
@@ -4,13 +4,6 @@ module ActiveRecord
module Associations
class Preloader
class HasMany < CollectionAssociation #:nodoc:
- def association_key_name
- reflection.foreign_key
- end
-
- def owner_key_name
- reflection.active_record_primary_key
- end
end
end
end
diff --git a/activerecord/lib/active_record/associations/preloader/has_one.rb b/activerecord/lib/active_record/associations/preloader/has_one.rb
index d87abf630f..e339b65fb5 100644
--- a/activerecord/lib/active_record/associations/preloader/has_one.rb
+++ b/activerecord/lib/active_record/associations/preloader/has_one.rb
@@ -4,13 +4,6 @@ module ActiveRecord
module Associations
class Preloader
class HasOne < SingularAssociation #:nodoc:
- def association_key_name
- reflection.foreign_key
- end
-
- def owner_key_name
- reflection.active_record_primary_key
- end
end
end
end
diff --git a/activerecord/lib/active_record/associations/preloader/singular_association.rb b/activerecord/lib/active_record/associations/preloader/singular_association.rb
index 266b5f6b1c..30a92411e3 100644
--- a/activerecord/lib/active_record/associations/preloader/singular_association.rb
+++ b/activerecord/lib/active_record/associations/preloader/singular_association.rb
@@ -5,14 +5,9 @@ module ActiveRecord
class Preloader
class SingularAssociation < Association #:nodoc:
private
-
- def preload(preloader)
- associated_records_by_owner(preloader).each do |owner, associated_records|
- record = associated_records.first
-
- association = owner.association(reflection.name)
- association.target = record
- end
+ def associate_records_to_owner(owner, records)
+ association = owner.association(reflection.name)
+ association.target = records.first
end
end
end
diff --git a/activerecord/lib/active_record/associations/preloader/through_association.rb b/activerecord/lib/active_record/associations/preloader/through_association.rb
index 8aac00d910..fa32cc5553 100644
--- a/activerecord/lib/active_record/associations/preloader/through_association.rb
+++ b/activerecord/lib/active_record/associations/preloader/through_association.rb
@@ -28,6 +28,8 @@ module ActiveRecord
middle_records = through_records.flat_map(&:last)
+ reflection_scope = reflection_scope() if reflection.scope
+
preloaders = preloader.preload(middle_records,
source_reflection.name,
reflection_scope)
@@ -49,7 +51,7 @@ module ActiveRecord
}.compact
# Respect the order on `reflection_scope` if it exists, else use the natural order.
- if reflection_scope.values[:order].present?
+ if reflection_scope && !reflection_scope.order_values.empty?
@id_map ||= id_to_index_map @preloaded_records
rhs_records.sort_by { |rhs| @id_map[rhs] }
else
@@ -67,10 +69,7 @@ module ActiveRecord
id_map
end
- def reset_association(owners, association_name, through_scope)
- should_reset = (through_scope != through_reflection.klass.unscoped) ||
- (options[:source_type] && through_reflection.collection?)
-
+ def reset_association(owners, association_name, should_reset)
# Don't cache the association - we would only be caching a subset
if should_reset
owners.each { |owner|
@@ -81,6 +80,7 @@ module ActiveRecord
def through_scope
scope = through_reflection.klass.unscoped
+ options = reflection.options
if options[:source_type]
scope.where! reflection.foreign_type => options[:source_type]
@@ -113,7 +113,7 @@ module ActiveRecord
end
end
- scope
+ scope unless scope.empty_scope?
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
index f57c7a5d4d..c9607df28c 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -522,6 +522,8 @@ module ActiveRecord
# Specifies the precision for the <tt>:decimal</tt> and <tt>:numeric</tt> columns.
# * <tt>:scale</tt> -
# Specifies the scale for the <tt>:decimal</tt> and <tt>:numeric</tt> columns.
+ # * <tt>:comment</tt> -
+ # Specifies the comment for the column. This option is ignored by some backends.
#
# Note: The precision is the total number of significant digits,
# and the scale is the number of digits that can be stored following
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/column.rb b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb
index 1b67cee24b..ff95fa4a0e 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/column.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb
@@ -10,8 +10,15 @@ module ActiveRecord
def serial?
return unless default_function
- %r{\Anextval\('"?#{table_name}_#{name}_seq"?'::regclass\)\z} === default_function
+ if %r{\Anextval\('"?(?<sequence_name>.+_(?<suffix>seq\d*))"?'::regclass\)\z} =~ default_function
+ sequence_name_from_parts(table_name, name, suffix) == sequence_name
+ end
end
+
+ private
+ def sequence_name_from_parts(table_name, column_name, suffix)
+ "#{table_name}_#{column_name}_#{suffix}"
+ end
end
end
end
diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb
index 52ca4671c2..8845e26ab7 100644
--- a/activerecord/lib/active_record/migration.rb
+++ b/activerecord/lib/active_record/migration.rb
@@ -354,9 +354,9 @@ module ActiveRecord
# to match the structure of your database.
#
# To roll the database back to a previous migration version, use
- # <tt>rails db:migrate VERSION=X</tt> where <tt>X</tt> is the version to which
+ # <tt>rails db:rollback VERSION=X</tt> where <tt>X</tt> is the version to which
# you wish to downgrade. Alternatively, you can also use the STEP option if you
- # wish to rollback last few migrations. <tt>rails db:migrate STEP=2</tt> will rollback
+ # wish to rollback last few migrations. <tt>rails db:rollback STEP=2</tt> will rollback
# the latest two migrations.
#
# If any of the migrations throw an <tt>ActiveRecord::IrreversibleMigration</tt> exception,
diff --git a/activerecord/lib/active_record/migration/compatibility.rb b/activerecord/lib/active_record/migration/compatibility.rb
index 784292f3f9..87c1c58aff 100644
--- a/activerecord/lib/active_record/migration/compatibility.rb
+++ b/activerecord/lib/active_record/migration/compatibility.rb
@@ -71,6 +71,21 @@ module ActiveRecord
end
end
+ def create_join_table(table_1, table_2, column_options: {}, **options)
+ column_options.reverse_merge!(type: :integer)
+
+ if block_given?
+ super(table_1, table_2, column_options: column_options, **options) do |t|
+ class << t
+ prepend TableDefinition
+ end
+ yield t
+ end
+ else
+ super
+ end
+ end
+
def add_reference(table_name, ref_name, **options)
super(table_name, ref_name, type: :integer, **options)
end
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index fbbf9082cc..b48a137a73 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -71,6 +71,100 @@ module ActiveRecord
klass.allocate.init_with("attributes" => attributes, "new_record" => false, &block)
end
+ # Updates an object (or multiple objects) and saves it to the database, if validations pass.
+ # The resulting object is returned whether the object was saved successfully to the database or not.
+ #
+ # ==== Parameters
+ #
+ # * +id+ - This should be the id or an array of ids to be updated.
+ # * +attributes+ - This should be a hash of attributes or an array of hashes.
+ #
+ # ==== Examples
+ #
+ # # Updates one record
+ # Person.update(15, user_name: "Samuel", group: "expert")
+ #
+ # # Updates multiple records
+ # people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy" } }
+ # Person.update(people.keys, people.values)
+ #
+ # # Updates multiple records from the result of a relation
+ # people = Person.where(group: "expert")
+ # people.update(group: "masters")
+ #
+ # Note: Updating a large number of records will run an UPDATE
+ # query for each record, which may cause a performance issue.
+ # When running callbacks is not needed for each record update,
+ # it is preferred to use {update_all}[rdoc-ref:Relation#update_all]
+ # for updating all records in a single query.
+ def update(id = :all, attributes)
+ if id.is_a?(Array)
+ id.map.with_index { |one_id, idx| update(one_id, attributes[idx]) }.compact
+ elsif id == :all
+ all.each { |record| record.update(attributes) }
+ else
+ if ActiveRecord::Base === id
+ raise ArgumentError,
+ "You are passing an instance of ActiveRecord::Base to `update`. " \
+ "Please pass the id of the object by calling `.id`."
+ end
+ object = find(id)
+ object.update(attributes)
+ object
+ end
+ rescue RecordNotFound
+ end
+
+ # Destroy an object (or multiple objects) that has the given id. The object is instantiated first,
+ # therefore all callbacks and filters are fired off before the object is deleted. This method is
+ # less efficient than #delete but allows cleanup methods and other actions to be run.
+ #
+ # This essentially finds the object (or multiple objects) with the given id, creates a new object
+ # from the attributes, and then calls destroy on it.
+ #
+ # ==== Parameters
+ #
+ # * +id+ - This should be the id or an array of ids to be destroyed.
+ #
+ # ==== Examples
+ #
+ # # Destroy a single object
+ # Todo.destroy(1)
+ #
+ # # Destroy multiple objects
+ # todos = [1,2,3]
+ # Todo.destroy(todos)
+ def destroy(id)
+ if id.is_a?(Array)
+ id.map { |one_id| destroy(one_id) }.compact
+ else
+ find(id).destroy
+ end
+ rescue RecordNotFound
+ end
+
+ # Deletes the row with a primary key matching the +id+ argument, using a
+ # SQL +DELETE+ statement, and returns the number of rows deleted. Active
+ # Record objects are not instantiated, so the object's callbacks are not
+ # executed, including any <tt>:dependent</tt> association options.
+ #
+ # You can delete multiple rows at once by passing an Array of <tt>id</tt>s.
+ #
+ # Note: Although it is often much faster than the alternative, #destroy,
+ # skipping callbacks might bypass business logic in your application
+ # that ensures referential integrity or performs other essential jobs.
+ #
+ # ==== Examples
+ #
+ # # Delete a single row
+ # Todo.delete(1)
+ #
+ # # Delete multiple rows
+ # Todo.delete([2,3,4])
+ def delete(id_or_array)
+ where(primary_key => id_or_array).delete_all
+ end
+
private
# Called by +instantiate+ to decide which class to use for a new
# record instance.
diff --git a/activerecord/lib/active_record/querying.rb b/activerecord/lib/active_record/querying.rb
index f780538319..3996d5661f 100644
--- a/activerecord/lib/active_record/querying.rb
+++ b/activerecord/lib/active_record/querying.rb
@@ -7,7 +7,7 @@ module ActiveRecord
delegate :first_or_create, :first_or_create!, :first_or_initialize, to: :all
delegate :find_or_create_by, :find_or_create_by!, :find_or_initialize_by, to: :all
delegate :find_by, :find_by!, to: :all
- delegate :destroy, :destroy_all, :delete, :delete_all, :update, :update_all, to: :all
+ delegate :destroy_all, :delete_all, :update_all, to: :all
delegate :find_each, :find_in_batches, :in_batches, to: :all
delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins, :left_joins, :left_outer_joins, :or,
:where, :rewhere, :preload, :eager_load, :includes, :from, :lock, :readonly, :extending,
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index 889e24dd1a..82ab2415e1 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -292,13 +292,17 @@ module ActiveRecord
end
def get_join_keys(association_klass)
- JoinKeys.new(join_pk(association_klass), join_foreign_key)
+ JoinKeys.new(join_primary_key(association_klass), join_foreign_key)
end
def build_scope(table, predicate_builder = predicate_builder(table))
Relation.create(klass, table, predicate_builder)
end
+ def join_primary_key(_)
+ foreign_key
+ end
+
def join_foreign_key
active_record_primary_key
end
@@ -313,10 +317,6 @@ module ActiveRecord
PredicateBuilder.new(TableMetadata.new(klass, table))
end
- def join_pk(_)
- foreign_key
- end
-
def primary_key(klass)
klass.primary_key || raise(UnknownPrimaryKey.new(klass))
end
@@ -736,6 +736,10 @@ module ActiveRecord
end
end
+ def join_primary_key(klass)
+ polymorphic? ? association_primary_key(klass) : association_primary_key
+ end
+
def join_foreign_key
foreign_key
end
@@ -745,10 +749,6 @@ module ActiveRecord
def calculate_constructable(macro, options)
!polymorphic?
end
-
- def join_pk(klass)
- polymorphic? ? association_primary_key(klass) : association_primary_key
- end
end
class HasAndBelongsToManyReflection < AssociationReflection # :nodoc:
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 42a9d8492b..f6825e67d7 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -376,50 +376,6 @@ module ActiveRecord
@klass.connection.update stmt, "SQL"
end
- # Updates an object (or multiple objects) and saves it to the database, if validations pass.
- # The resulting object is returned whether the object was saved successfully to the database or not.
- #
- # ==== Parameters
- #
- # * +id+ - This should be the id or an array of ids to be updated.
- # * +attributes+ - This should be a hash of attributes or an array of hashes.
- #
- # ==== Examples
- #
- # # Updates one record
- # Person.update(15, user_name: 'Samuel', group: 'expert')
- #
- # # Updates multiple records
- # people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy" } }
- # Person.update(people.keys, people.values)
- #
- # # Updates multiple records from the result of a relation
- # people = Person.where(group: 'expert')
- # people.update(group: 'masters')
- #
- # Note: Updating a large number of records will run an
- # UPDATE query for each record, which may cause a performance
- # issue. When running callbacks is not needed for each record update,
- # it is preferred to use #update_all for updating all records
- # in a single query.
- def update(id = :all, attributes)
- if id.is_a?(Array)
- id.map.with_index { |one_id, idx| update(one_id, attributes[idx]) }
- elsif id == :all
- records.each { |record| record.update(attributes) }
- else
- if ActiveRecord::Base === id
- raise ArgumentError, <<-MSG.squish
- You are passing an instance of ActiveRecord::Base to `update`.
- Please pass the id of the object by calling `.id`.
- MSG
- end
- object = find(id)
- object.update(attributes)
- object
- end
- end
-
# Destroys the records by instantiating each
# record and calling its {#destroy}[rdoc-ref:Persistence#destroy] method.
# Each object's callbacks are executed (including <tt>:dependent</tt> association options).
@@ -440,33 +396,6 @@ module ActiveRecord
records.each(&:destroy).tap { reset }
end
- # Destroy an object (or multiple objects) that has the given id. The object is instantiated first,
- # therefore all callbacks and filters are fired off before the object is deleted. This method is
- # less efficient than #delete but allows cleanup methods and other actions to be run.
- #
- # This essentially finds the object (or multiple objects) with the given id, creates a new object
- # from the attributes, and then calls destroy on it.
- #
- # ==== Parameters
- #
- # * +id+ - Can be either an Integer or an Array of Integers.
- #
- # ==== Examples
- #
- # # Destroy a single object
- # Todo.destroy(1)
- #
- # # Destroy multiple objects
- # todos = [1,2,3]
- # Todo.destroy(todos)
- def destroy(id)
- if id.is_a?(Array)
- id.map { |one_id| destroy(one_id) }
- else
- find(id).destroy
- end
- end
-
# Deletes the records without instantiating the records
# first, and hence not calling the {#destroy}[rdoc-ref:Persistence#destroy]
# method nor invoking callbacks.
@@ -509,29 +438,6 @@ module ActiveRecord
affected
end
- # Deletes the row with a primary key matching the +id+ argument, using a
- # SQL +DELETE+ statement, and returns the number of rows deleted. Active
- # Record objects are not instantiated, so the object's callbacks are not
- # executed, including any <tt>:dependent</tt> association options.
- #
- # You can delete multiple rows at once by passing an Array of <tt>id</tt>s.
- #
- # Note: Although it is often much faster than the alternative,
- # #destroy, skipping callbacks might bypass business logic in
- # your application that ensures referential integrity or performs other
- # essential jobs.
- #
- # ==== Examples
- #
- # # Delete a single row
- # Todo.delete(1)
- #
- # # Delete multiple rows
- # Todo.delete([2,3,4])
- def delete(id_or_array)
- where(primary_key => id_or_array).delete_all
- end
-
# Causes the records to be loaded from the database if they have not
# been loaded already. You can use this if for some reason you need
# to explicitly load some records before actually using them. The
diff --git a/activerecord/test/cases/adapters/postgresql/serial_test.rb b/activerecord/test/cases/adapters/postgresql/serial_test.rb
index 3c020a88d0..df7875dbf2 100644
--- a/activerecord/test/cases/adapters/postgresql/serial_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/serial_test.rb
@@ -86,3 +86,39 @@ class PostgresqlBigSerialTest < ActiveRecord::PostgreSQLTestCase
assert_match %r{t\.bigint\s+"serials_id",\s+default: -> \{ "nextval\('postgresql_big_serials_id_seq'::regclass\)" \}$}, output
end
end
+
+module SequenceNameDetectionTestCases
+ class CollidedSequenceNameTest < ActiveRecord::PostgreSQLTestCase
+ include SchemaDumpingHelper
+
+ def setup
+ @connection = ActiveRecord::Base.connection
+ @connection.create_table :foo_bar, force: true do |t|
+ t.serial :baz_id
+ end
+ @connection.create_table :foo, force: true do |t|
+ t.serial :bar_id
+ t.bigserial :bar_baz_id
+ end
+ end
+
+ def teardown
+ @connection.drop_table :foo_bar, if_exists: true
+ @connection.drop_table :foo, if_exists: true
+ end
+
+ def test_serial_columns
+ columns = @connection.columns(:foo)
+ columns.each do |column|
+ assert_equal :integer, column.type
+ assert column.serial?
+ end
+ end
+
+ def test_schema_dump_with_collided_sequence_name
+ output = dump_table_schema "foo"
+ assert_match %r{t\.serial\s+"bar_id",\s+null: false$}, output
+ assert_match %r{t\.bigserial\s+"bar_baz_id",\s+null: false$}, output
+ end
+ end
+end
diff --git a/activerecord/test/cases/attributes_test.rb b/activerecord/test/cases/attributes_test.rb
index 29a25b4461..2caf2a63d4 100644
--- a/activerecord/test/cases/attributes_test.rb
+++ b/activerecord/test/cases/attributes_test.rb
@@ -108,12 +108,14 @@ module ActiveRecord
assert_equal 6, klass.attribute_types.length
assert_equal 6, klass.column_defaults.length
+ assert_equal 6, klass.attribute_names.length
assert_not klass.attribute_types.include?("wibble")
klass.attribute :wibble, Type::Value.new
assert_equal 7, klass.attribute_types.length
assert_equal 7, klass.column_defaults.length
+ assert_equal 7, klass.attribute_names.length
assert_includes klass.attribute_types, "wibble"
end
diff --git a/activerecord/test/cases/migration/compatibility_test.rb b/activerecord/test/cases/migration/compatibility_test.rb
index cb3b02c02a..e1311c0f21 100644
--- a/activerecord/test/cases/migration/compatibility_test.rb
+++ b/activerecord/test/cases/migration/compatibility_test.rb
@@ -199,6 +199,36 @@ class LegacyPrimaryKeyTest < ActiveRecord::TestCase
assert_match %r{create_table "legacy_primary_keys", id: :integer, default: nil}, schema
end
+ def test_legacy_join_table_foreign_keys_should_be_integer
+ @migration = Class.new(ActiveRecord::Migration[5.0]) {
+ def change
+ create_join_table :apples, :bananas do |t|
+ end
+ end
+ }.new
+
+ @migration.migrate(:up)
+
+ schema = dump_table_schema "apples_bananas"
+ assert_match %r{integer "apple_id", null: false}, schema
+ assert_match %r{integer "banana_id", null: false}, schema
+ end
+
+ def test_legacy_join_table_column_options_should_be_overwritten
+ @migration = Class.new(ActiveRecord::Migration[5.0]) {
+ def change
+ create_join_table :apples, :bananas, column_options: { type: :bigint } do |t|
+ end
+ end
+ }.new
+
+ @migration.migrate(:up)
+
+ schema = dump_table_schema "apples_bananas"
+ assert_match %r{bigint "apple_id", null: false}, schema
+ assert_match %r{bigint "banana_id", null: false}, schema
+ end
+
if current_adapter?(:Mysql2Adapter)
def test_legacy_bigint_primary_key_should_be_auto_incremented
@migration = Class.new(ActiveRecord::Migration[5.0]) {
diff --git a/activerecord/test/cases/persistence_test.rb b/activerecord/test/cases/persistence_test.rb
index 170fd02b6f..6cbe18cc8c 100644
--- a/activerecord/test/cases/persistence_test.rb
+++ b/activerecord/test/cases/persistence_test.rb
@@ -70,10 +70,10 @@ class PersistenceTest < ActiveRecord::TestCase
end
def test_update_many
- topic_data = { 1 => { "content" => "1 updated" }, 2 => { "content" => "2 updated" } }
+ topic_data = { 1 => { "content" => "1 updated" }, 2 => { "content" => "2 updated" }, nil => {} }
updated = Topic.update(topic_data.keys, topic_data.values)
- assert_equal 2, updated.size
+ assert_equal [1, 2], updated.map(&:id)
assert_equal "1 updated", Topic.find(1).content
assert_equal "2 updated", Topic.find(2).content
end
@@ -81,9 +81,8 @@ class PersistenceTest < ActiveRecord::TestCase
def test_class_level_update_is_affected_by_scoping
topic_data = { 1 => { "content" => "1 updated" }, 2 => { "content" => "2 updated" } }
- assert_raise(ActiveRecord::RecordNotFound) do
- Topic.where("1=0").scoping { Topic.update(topic_data.keys, topic_data.values) }
- end
+ assert_equal [], Topic.where("1=0").scoping { Topic.update(topic_data.keys, topic_data.values) }
+
assert_not_equal "1 updated", Topic.find(1).content
assert_not_equal "2 updated", Topic.find(2).content
end
@@ -175,7 +174,7 @@ class PersistenceTest < ActiveRecord::TestCase
clients = Client.all.merge!(order: "id").find([2, 3])
assert_difference("Client.count", -2) do
- destroyed = Client.destroy([2, 3]).sort_by(&:id)
+ destroyed = Client.destroy([2, 3, nil]).sort_by(&:id)
assert_equal clients, destroyed
assert destroyed.all?(&:frozen?), "destroyed clients should be frozen"
end
@@ -917,7 +916,9 @@ class PersistenceTest < ActiveRecord::TestCase
should_be_destroyed_reply = Reply.create("title" => "hello", "content" => "world")
Topic.find(1).replies << should_be_destroyed_reply
- Topic.destroy(1)
+ topic = Topic.destroy(1)
+ assert topic.destroyed?
+
assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1) }
assert_raise(ActiveRecord::RecordNotFound) { Reply.find(should_be_destroyed_reply.id) }
end
@@ -926,9 +927,8 @@ class PersistenceTest < ActiveRecord::TestCase
should_not_be_destroyed_reply = Reply.create("title" => "hello", "content" => "world")
Topic.find(1).replies << should_not_be_destroyed_reply
- assert_raise(ActiveRecord::RecordNotFound) do
- Topic.where("1=0").scoping { Topic.destroy(1) }
- end
+ assert_nil Topic.where("1=0").scoping { Topic.destroy(1) }
+
assert_nothing_raised { Topic.find(1) }
assert_nothing_raised { Reply.find(should_not_be_destroyed_reply.id) }
end
diff --git a/activestorage/README.md b/activestorage/README.md
index 17d98978bb..8814887950 100644
--- a/activestorage/README.md
+++ b/activestorage/README.md
@@ -24,7 +24,7 @@ class User < ApplicationRecord
end
# Attach an avatar to the user.
-user.avatar.attach(io: File.open("~/face.jpg"), filename: "avatar.jpg", content_type: "image/jpg")
+user.avatar.attach(io: File.open("/path/to/face.jpg"), filename: "face.jpg", content_type: "image/jpg")
# Does the user have an avatar?
user.avatar.attached? # => true
@@ -63,7 +63,7 @@ end
```
```erb
-<%= form_with model: @message do |form| %>
+<%= form_with model: @message, local: true do |form| %>
<%= form.text_field :title, placeholder: "Title" %><br>
<%= form.text_area :content %><br><br>
diff --git a/activestorage/app/models/active_storage/variation.rb b/activestorage/app/models/active_storage/variation.rb
index bf269e2a8f..cf04a879eb 100644
--- a/activestorage/app/models/active_storage/variation.rb
+++ b/activestorage/app/models/active_storage/variation.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-require "active_support/core_ext/object/inclusion"
-
# A set of transformations that can be applied to a blob to create a variant. This class is exposed via
# the ActiveStorage::Blob#variant method and should rarely be used directly.
#
diff --git a/activestorage/config/routes.rb b/activestorage/config/routes.rb
index 168788475c..c3194887be 100644
--- a/activestorage/config/routes.rb
+++ b/activestorage/config/routes.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
Rails.application.routes.draw do
- get "/rails/active_storage/blobs/:signed_id/*filename" => "active_storage/blobs#show", as: :rails_service_blob
+ get "/rails/active_storage/blobs/:signed_id/*filename" => "active_storage/blobs#show", as: :rails_service_blob, internal: true
direct :rails_blob do |blob|
route_for(:rails_service_blob, blob.signed_id, blob.filename)
@@ -11,7 +11,7 @@ Rails.application.routes.draw do
resolve("ActiveStorage::Attachment") { |attachment| route_for(:rails_blob, attachment.blob) }
- get "/rails/active_storage/variants/:signed_blob_id/:variation_key/*filename" => "active_storage/variants#show", as: :rails_blob_variation
+ get "/rails/active_storage/variants/:signed_blob_id/:variation_key/*filename" => "active_storage/variants#show", as: :rails_blob_variation, internal: true
direct :rails_variant do |variant|
signed_blob_id = variant.blob.signed_id
@@ -24,7 +24,7 @@ Rails.application.routes.draw do
resolve("ActiveStorage::Variant") { |variant| route_for(:rails_variant, variant) }
- get "/rails/active_storage/disk/:encoded_key/*filename" => "active_storage/disk#show", as: :rails_disk_service
- put "/rails/active_storage/disk/:encoded_token" => "active_storage/disk#update", as: :update_rails_disk_service
- post "/rails/active_storage/direct_uploads" => "active_storage/direct_uploads#create", as: :rails_direct_uploads
+ get "/rails/active_storage/disk/:encoded_key/*filename" => "active_storage/disk#show", as: :rails_disk_service, internal: true
+ put "/rails/active_storage/disk/:encoded_token" => "active_storage/disk#update", as: :update_rails_disk_service, internal: true
+ post "/rails/active_storage/direct_uploads" => "active_storage/direct_uploads#create", as: :rails_direct_uploads, internal: true
end
diff --git a/activestorage/lib/active_storage/attached/many.rb b/activestorage/lib/active_storage/attached/many.rb
index 59b7d7d559..1e0657c33c 100644
--- a/activestorage/lib/active_storage/attached/many.rb
+++ b/activestorage/lib/active_storage/attached/many.rb
@@ -17,7 +17,7 @@ module ActiveStorage
#
# document.images.attach(params[:images]) # Array of ActionDispatch::Http::UploadedFile objects
# document.images.attach(params[:signed_blob_id]) # Signed reference to blob from direct upload
- # document.images.attach(io: File.open("~/racecar.jpg"), filename: "racecar.jpg", content_type: "image/jpg")
+ # document.images.attach(io: File.open("/path/to/racecar.jpg"), filename: "racecar.jpg", content_type: "image/jpg")
# document.images.attach([ first_blob, second_blob ])
def attach(*attachables)
attachables.flatten.collect do |attachable|
diff --git a/activestorage/lib/active_storage/attached/one.rb b/activestorage/lib/active_storage/attached/one.rb
index ac90f32d95..c66be08f58 100644
--- a/activestorage/lib/active_storage/attached/one.rb
+++ b/activestorage/lib/active_storage/attached/one.rb
@@ -18,7 +18,7 @@ module ActiveStorage
#
# person.avatar.attach(params[:avatar]) # ActionDispatch::Http::UploadedFile object
# person.avatar.attach(params[:signed_blob_id]) # Signed reference to blob from direct upload
- # person.avatar.attach(io: File.open("~/face.jpg"), filename: "face.jpg", content_type: "image/jpg")
+ # person.avatar.attach(io: File.open("/path/to/face.jpg"), filename: "face.jpg", content_type: "image/jpg")
# person.avatar.attach(avatar_blob) # ActiveStorage::Blob object
def attach(attachable)
if attached? && dependent == :purge_later
diff --git a/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb b/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb
index 3b62fe6819..b7ad76bb62 100644
--- a/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb
+++ b/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb
@@ -37,18 +37,6 @@ module ActiveSupport
private
- def digits_and_rounded_number(precision)
- if zero?
- [1, 0]
- else
- digits = digit_count(number)
- multiplier = 10**(digits - precision)
- rounded_number = calculate_rounded_number(multiplier)
- digits = digit_count(rounded_number) # After rounding, the number of digits may have changed
- [digits, rounded_number]
- end
- end
-
def calculate_rounded_number(multiplier)
(number / BigDecimal.new(multiplier.to_f.to_s)).round * multiplier
end
diff --git a/activesupport/lib/active_support/ordered_options.rb b/activesupport/lib/active_support/ordered_options.rb
index fa7825b3ba..c2a37fbdd7 100644
--- a/activesupport/lib/active_support/ordered_options.rb
+++ b/activesupport/lib/active_support/ordered_options.rb
@@ -24,7 +24,7 @@ module ActiveSupport
# To raise an exception when the value is blank, append a
# bang to the key name, like:
#
- # h.dog! # => raises KeyError: key not found: :dog
+ # h.dog! # => raises KeyError: :dog is blank
#
class OrderedOptions < Hash
alias_method :_get, :[] # preserve the original #[] method
@@ -46,7 +46,7 @@ module ActiveSupport
bangs = name_string.chomp!("!")
if bangs
- fetch(name_string.to_sym).presence || raise(KeyError.new("#{name_string} is blank."))
+ fetch(name_string.to_sym).presence || raise(KeyError.new(":#{name_string} is blank"))
else
self[name_string]
end
diff --git a/guides/source/5_1_release_notes.md b/guides/source/5_1_release_notes.md
index fa92b9e5f8..80c9da6446 100644
--- a/guides/source/5_1_release_notes.md
+++ b/guides/source/5_1_release_notes.md
@@ -602,7 +602,7 @@ Please refer to the [Changelog][active-support] for detailed changes.
([Pull Request](https://github.com/rails/rails/pull/28157))
* Deprecated passing string to `:if` and `:unless` conditional options on `set_callback` and `skip_callback`.
- ([Commit](https://github.com/rails/rails/commit/0952552)
+ ([Commit](https://github.com/rails/rails/commit/0952552))
### Notable changes
diff --git a/guides/source/action_controller_overview.md b/guides/source/action_controller_overview.md
index 2c3f74c3e1..5fb8e300de 100644
--- a/guides/source/action_controller_overview.md
+++ b/guides/source/action_controller_overview.md
@@ -400,9 +400,9 @@ Rails.application.config.session_store :cookie_store, key: '_your_app_session',
Rails sets up (for the CookieStore) a secret key used for signing the session data in `config/credentials.yml.enc`. This can be changed with `bin/rails credentials:edit`.
```ruby
-# amazon:
-# access_key_id: 123
-# secret_access_key: 345
+# aws:
+# access_key_id: 123
+# secret_access_key: 345
# Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies.
secret_key_base: 492f...
diff --git a/guides/source/active_job_basics.md b/guides/source/active_job_basics.md
index 7a3ff12b63..914ef2c327 100644
--- a/guides/source/active_job_basics.md
+++ b/guides/source/active_job_basics.md
@@ -389,6 +389,25 @@ class GuestsCleanupJob < ApplicationJob
end
```
+### Retrying or Discarding failed jobs
+
+It's also possible to retry or discard a job if an exception is raised during execution.
+For example:
+
+```ruby
+class RemoteServiceJob < ApplicationJob
+ retry_on CustomAppException # defaults to 3s wait, 5 attempts
+
+ discard_on ActiveJob::DeserializationError
+
+ def perform(*args)
+ # Might raise CustomAppException or ActiveJob::DeserializationError
+ end
+end
+```
+
+To get more details see the API Documentation for [ActiveJob::Exceptions](http://api.rubyonrails.org/classes/ActiveJob/Exceptions/ClassMethods.html).
+
### Deserialization
GlobalID allows serializing full Active Record objects passed to `#perform`.
diff --git a/guides/source/autoloading_and_reloading_constants.md b/guides/source/autoloading_and_reloading_constants.md
index c62194faf4..ede0324a51 100644
--- a/guides/source/autoloading_and_reloading_constants.md
+++ b/guides/source/autoloading_and_reloading_constants.md
@@ -954,7 +954,7 @@ to work on some subclass, things get interesting.
While working with `Polygon` you do not need to be aware of all its descendants,
because anything in the table is by definition a polygon, but when working with
subclasses Active Record needs to be able to enumerate the types it is looking
-for. Let’s see an example.
+for. Let's see an example.
`Rectangle.all` only loads rectangles by adding a type constraint to the query:
@@ -963,7 +963,7 @@ SELECT "polygons".* FROM "polygons"
WHERE "polygons"."type" IN ("Rectangle")
```
-Let’s introduce now a subclass of `Rectangle`:
+Let's introduce now a subclass of `Rectangle`:
```ruby
# app/models/square.rb
@@ -978,7 +978,7 @@ SELECT "polygons".* FROM "polygons"
WHERE "polygons"."type" IN ("Rectangle", "Square")
```
-But there’s a caveat here: How does Active Record know that the class `Square`
+But there's a caveat here: How does Active Record know that the class `Square`
exists at all?
Even if the file `app/models/square.rb` exists and defines the `Square` class,
@@ -1049,7 +1049,7 @@ end
The purpose of this setup would be that the application uses the class that
corresponds to the environment via `AUTH_SERVICE`. In development mode
-`MockedAuthService` gets autoloaded when the initializer runs. Let’s suppose
+`MockedAuthService` gets autoloaded when the initializer runs. Let's suppose
we do some requests, change its implementation, and hit the application again.
To our surprise the changes are not reflected. Why?
diff --git a/guides/source/caching_with_rails.md b/guides/source/caching_with_rails.md
index 910a531068..96650b5be9 100644
--- a/guides/source/caching_with_rails.md
+++ b/guides/source/caching_with_rails.md
@@ -181,7 +181,7 @@ cache.
### Shared Partial Caching
-It is possible to share partials and associated caching between files with different mime types. For example shared partial caching allows template writers to share a partial between HTML and Javascript files. When templates are collected in the template resolver file paths they only include the template language extension and not the mime type. Because of this templates can be used for multiple mime types. Both HTML and JavaScript requests will respond to the following code:
+It is possible to share partials and associated caching between files with different mime types. For example shared partial caching allows template writers to share a partial between HTML and JavaScript files. When templates are collected in the template resolver file paths they only include the template language extension and not the mime type. Because of this templates can be used for multiple mime types. Both HTML and JavaScript requests will respond to the following code:
```ruby
render(partial: 'hotels/hotel', collection: @hotels, cached: true)
@@ -195,7 +195,7 @@ Another option is to include the full filename of the partial to render.
render(partial: 'hotels/hotel.html.erb', collection: @hotels, cached: true)
```
-Will load a file named `hotels/hotel.html.erb` in any file mime type, for example you could include this partial in a Javascript file.
+Will load a file named `hotels/hotel.html.erb` in any file mime type, for example you could include this partial in a JavaScript file.
### Managing dependencies
diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md
index 7c7b3a4c01..70a945ad9e 100644
--- a/guides/source/getting_started.md
+++ b/guides/source/getting_started.md
@@ -594,7 +594,7 @@ familiar error:
You now need to create the `create` action within the `ArticlesController` for
this to work.
-NOTE: by default `form_with` submits forms using Ajax thereby skipping full page
+NOTE: By default `form_with` submits forms using Ajax thereby skipping full page
redirects. To make this guide easier to get into we've disabled that with
`local: true` for now.
diff --git a/guides/source/i18n.md b/guides/source/i18n.md
index cb24822f86..0153f52249 100644
--- a/guides/source/i18n.md
+++ b/guides/source/i18n.md
@@ -1187,7 +1187,7 @@ If you find your own locale (language) missing from our [example translations da
Resources
---------
-* [Google group: rails-i18n](https://groups.google.com/forum/#!forum/rails-i18n) - The project's mailing list.
+* [Google group: rails-i18n](https://groups.google.com/group/rails-i18n) - The project's mailing list.
* [GitHub: rails-i18n](https://github.com/svenfuchs/rails-i18n) - Code repository and issue tracker for the rails-i18n project. Most importantly you can find lots of [example translations](https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale) for Rails that should work for your application in most cases.
* [GitHub: i18n](https://github.com/svenfuchs/i18n) - Code repository and issue tracker for the i18n gem.
diff --git a/guides/source/plugins.md b/guides/source/plugins.md
index 0f0cde7634..b3a7f544f5 100644
--- a/guides/source/plugins.md
+++ b/guides/source/plugins.md
@@ -237,7 +237,7 @@ Finished in 0.004812s, 831.2949 runs/s, 415.6475 assertions/s.
This tells us that we don't have the necessary models (Hickwall and Wickwall) that we are trying to test.
We can easily generate these models in our "dummy" Rails application by running the following commands from the
-test/dummy directory:
+`test/dummy` directory:
```bash
$ cd test/dummy
diff --git a/guides/source/security.md b/guides/source/security.md
index a74de22ac0..0b2d8de0fb 100644
--- a/guides/source/security.md
+++ b/guides/source/security.md
@@ -1029,7 +1029,7 @@ Rails generates a `config/credentials.yml.enc` to store third-party credentials
within the repo. This is only viable because Rails encrypts the file with a master
key that's generated into a version control ignored `config/master.key` — Rails
will also look for that key in `ENV["RAILS_MASTER_KEY"]`. Rails also requires the
-the key to boot in production, so the credentials can be read.
+key to boot in production, so the credentials can be read.
To edit stored credentials use `bin/rails credentials:edit`.
@@ -1038,18 +1038,18 @@ By default, this file contains the application's
access keys for external APIs.
The credentials added to this file are accessible via `Rails.application.credentials`.
-For example, with the following decrypted `config/credentails.yml.enc`:
+For example, with the following decrypted `config/credentials.yml.enc`:
secret_key_base: 3b7cd727ee24e8444053437c36cc66c3
some_api_key: SOMEKEY
-`Rails.application.credentails.some_api_key` returns `SOMEKEY` in any environment.
+`Rails.application.credentials.some_api_key` returns `SOMEKEY` in any environment.
If you want an exception to be raised when some key is blank, use the bang
version:
```ruby
-Rails.application.credentails.some_api_key! # => raises KeyError: key not found: :some_api_key
+Rails.application.credentials.some_api_key! # => raises KeyError: :some_api_key is blank
```
Additional Resources
diff --git a/guides/source/working_with_javascript_in_rails.md b/guides/source/working_with_javascript_in_rails.md
index 27cef2bd27..098366ec1b 100644
--- a/guides/source/working_with_javascript_in_rails.md
+++ b/guides/source/working_with_javascript_in_rails.md
@@ -382,7 +382,7 @@ Rails 5.1 introduced rails-ujs and dropped jQuery as a dependency.
As a result the Unobtrusive JavaScript (UJS) driver has been rewritten to operate without jQuery.
These introductions cause small changes to `custom events` fired during the request:
-NOTE: Signature of calls to UJS’s event handlers has changed.
+NOTE: Signature of calls to UJS's event handlers has changed.
Unlike the version with jQuery, all custom events return only one parameter: `event`.
In this parameter, there is an additional attribute `detail` which contains an array of extra parameters.
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index 5057059898..ff440b7939 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,3 +1,7 @@
+* Add `mini_magick` to default `Gemfile` as comment.
+
+ *Yoshiyuki Hirano*
+
* Derive `secret_key_base` from the app name in development and test environments.
Spares away needless secret configs.
diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile
index 7b7bebc957..bfbba789b0 100644
--- a/railties/lib/rails/generators/rails/app/templates/Gemfile
+++ b/railties/lib/rails/generators/rails/app/templates/Gemfile
@@ -21,6 +21,9 @@ ruby <%= "'#{RUBY_VERSION}'" -%>
# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'
+# Use ActiveStorage variant
+# gem 'mini_magick', '~> 4.8'
+
# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development
@@ -38,7 +41,7 @@ group :development, :test do
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
<%- if depends_on_system_test? -%>
# Adds support for Capybara system testing and selenium driver
- gem 'capybara', '~> 2.13'
+ gem 'capybara', '~> 2.15'
gem 'selenium-webdriver'
<%- end -%>
end
diff --git a/railties/lib/rails/generators/rails/app/templates/config/storage.yml b/railties/lib/rails/generators/rails/app/templates/config/storage.yml
index 089ed4567a..9bada4b66d 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/storage.yml
+++ b/railties/lib/rails/generators/rails/app/templates/config/storage.yml
@@ -6,11 +6,11 @@ local:
service: Disk
root: <%%= Rails.root.join("storage") %>
-# Use rails secrets:edit to set the AWS secrets (as shared:aws:access_key_id|secret_access_key)
+# Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
# amazon:
# service: S3
-# access_key_id: <%%= Rails.application.secrets.dig(:aws, :access_key_id) %>
-# secret_access_key: <%%= Rails.application.secrets.dig(:aws, :secret_access_key) %>
+# access_key_id: <%%= Rails.application.credentials.dig(:aws, :access_key_id) %>
+# secret_access_key: <%%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
# region: us-east-1
# bucket: your_own_bucket
@@ -21,12 +21,12 @@ local:
# keyfile: <%%= Rails.root.join("path/to/gcs.keyfile") %>
# bucket: your_own_bucket
-# Use rails secrets:edit to set the Azure Storage secret (as shared:azure_storage:storage_access_key)
+# Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key)
# microsoft:
# service: AzureStorage
# path: your_azure_storage_path
# storage_account_name: your_account_name
-# storage_access_key: <%%= Rails.application.secrets.dig(:azure_storage, :storage_access_key) %>
+# storage_access_key: <%%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %>
# container: your_container_name
# mirror:
diff --git a/railties/lib/rails/generators/rails/credentials/credentials_generator.rb b/railties/lib/rails/generators/rails/credentials/credentials_generator.rb
index ddcccd5ce5..21ca566818 100644
--- a/railties/lib/rails/generators/rails/credentials/credentials_generator.rb
+++ b/railties/lib/rails/generators/rails/credentials/credentials_generator.rb
@@ -37,7 +37,7 @@ module Rails
private
def credentials_template
- "# amazon:\n# access_key_id: 123\n# secret_access_key: 345\n\n" +
+ "# aws:\n# access_key_id: 123\n# secret_access_key: 345\n\n" +
"# Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies.\n" +
"secret_key_base: #{SecureRandom.hex(64)}"
end
diff --git a/railties/lib/rails/generators/rails/resource/USAGE b/railties/lib/rails/generators/rails/resource/USAGE
index e359cd574f..66d0ee546a 100644
--- a/railties/lib/rails/generators/rails/resource/USAGE
+++ b/railties/lib/rails/generators/rails/resource/USAGE
@@ -1,6 +1,6 @@
Description:
Stubs out a new resource including an empty model and controller suitable
- for a restful, resource-oriented application. Pass the singular model name,
+ for a RESTful, resource-oriented application. Pass the singular model name,
either CamelCased or under_scored, as the first argument, and an optional
list of attribute pairs.
diff --git a/railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb b/railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb
index 4efa977a89..ff41fef9e9 100644
--- a/railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb
+++ b/railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb
@@ -1,5 +1,3 @@
-# frozen_string_literal: true
-
require 'test_helper'
<% module_namespacing do -%>
diff --git a/railties/lib/rails/generators/test_unit/generator/templates/generator_test.rb b/railties/lib/rails/generators/test_unit/generator/templates/generator_test.rb
index e6fb6c5ff4..a7f1fc4fba 100644
--- a/railties/lib/rails/generators/test_unit/generator/templates/generator_test.rb
+++ b/railties/lib/rails/generators/test_unit/generator/templates/generator_test.rb
@@ -1,5 +1,3 @@
-# frozen_string_literal: true
-
require 'test_helper'
require '<%= generator_path %>'
diff --git a/railties/lib/rails/generators/test_unit/integration/templates/integration_test.rb b/railties/lib/rails/generators/test_unit/integration/templates/integration_test.rb
index 65708b6c3b..118e0f1271 100644
--- a/railties/lib/rails/generators/test_unit/integration/templates/integration_test.rb
+++ b/railties/lib/rails/generators/test_unit/integration/templates/integration_test.rb
@@ -1,5 +1,3 @@
-# frozen_string_literal: true
-
require 'test_helper'
<% module_namespacing do -%>
diff --git a/railties/lib/rails/generators/test_unit/mailer/templates/functional_test.rb b/railties/lib/rails/generators/test_unit/mailer/templates/functional_test.rb
index 1ec3a2f360..a2f2d30de5 100644
--- a/railties/lib/rails/generators/test_unit/mailer/templates/functional_test.rb
+++ b/railties/lib/rails/generators/test_unit/mailer/templates/functional_test.rb
@@ -1,5 +1,3 @@
-# frozen_string_literal: true
-
require 'test_helper'
<% module_namespacing do -%>
diff --git a/railties/lib/rails/generators/test_unit/mailer/templates/preview.rb b/railties/lib/rails/generators/test_unit/mailer/templates/preview.rb
index 9876210b6c..b063cbc47b 100644
--- a/railties/lib/rails/generators/test_unit/mailer/templates/preview.rb
+++ b/railties/lib/rails/generators/test_unit/mailer/templates/preview.rb
@@ -1,5 +1,3 @@
-# frozen_string_literal: true
-
<% module_namespacing do -%>
# Preview all emails at http://localhost:3000/rails/mailers/<%= file_path %>_mailer
class <%= class_name %>MailerPreview < ActionMailer::Preview
diff --git a/railties/lib/rails/generators/test_unit/model/templates/unit_test.rb b/railties/lib/rails/generators/test_unit/model/templates/unit_test.rb
index 5f1ffeb33b..c9bc7d5b90 100644
--- a/railties/lib/rails/generators/test_unit/model/templates/unit_test.rb
+++ b/railties/lib/rails/generators/test_unit/model/templates/unit_test.rb
@@ -1,5 +1,3 @@
-# frozen_string_literal: true
-
require 'test_helper'
<% module_namespacing do -%>
diff --git a/railties/lib/rails/generators/test_unit/plugin/templates/test_helper.rb b/railties/lib/rails/generators/test_unit/plugin/templates/test_helper.rb
index 2147b09568..30a861f09d 100644
--- a/railties/lib/rails/generators/test_unit/plugin/templates/test_helper.rb
+++ b/railties/lib/rails/generators/test_unit/plugin/templates/test_helper.rb
@@ -1,4 +1,2 @@
-# frozen_string_literal: true
-
require 'active_support/testing/autorun'
require 'active_support'
diff --git a/railties/lib/rails/generators/test_unit/scaffold/templates/api_functional_test.rb b/railties/lib/rails/generators/test_unit/scaffold/templates/api_functional_test.rb
index 2ef93b8aea..f21861d8e6 100644
--- a/railties/lib/rails/generators/test_unit/scaffold/templates/api_functional_test.rb
+++ b/railties/lib/rails/generators/test_unit/scaffold/templates/api_functional_test.rb
@@ -1,5 +1,3 @@
-# frozen_string_literal: true
-
require 'test_helper'
<% module_namespacing do -%>
diff --git a/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb
index bcf9392bd1..195d60be20 100644
--- a/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb
+++ b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb
@@ -1,5 +1,3 @@
-# frozen_string_literal: true
-
require 'test_helper'
<% module_namespacing do -%>
diff --git a/railties/lib/rails/generators/test_unit/scaffold/templates/system_test.rb b/railties/lib/rails/generators/test_unit/scaffold/templates/system_test.rb
index ba8bdc192e..f83f5a5c62 100644
--- a/railties/lib/rails/generators/test_unit/scaffold/templates/system_test.rb
+++ b/railties/lib/rails/generators/test_unit/scaffold/templates/system_test.rb
@@ -1,5 +1,3 @@
-# frozen_string_literal: true
-
require "application_system_test_case"
<% module_namespacing do -%>
diff --git a/railties/lib/rails/generators/test_unit/system/templates/application_system_test_case.rb b/railties/lib/rails/generators/test_unit/system/templates/application_system_test_case.rb
index c05709aff8..d19212abd5 100644
--- a/railties/lib/rails/generators/test_unit/system/templates/application_system_test_case.rb
+++ b/railties/lib/rails/generators/test_unit/system/templates/application_system_test_case.rb
@@ -1,5 +1,3 @@
-# frozen_string_literal: true
-
require "test_helper"
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
diff --git a/railties/lib/rails/generators/test_unit/system/templates/system_test.rb b/railties/lib/rails/generators/test_unit/system/templates/system_test.rb
index cfac061cd1..b5ce2ba5c8 100644
--- a/railties/lib/rails/generators/test_unit/system/templates/system_test.rb
+++ b/railties/lib/rails/generators/test_unit/system/templates/system_test.rb
@@ -1,5 +1,3 @@
-# frozen_string_literal: true
-
require "application_system_test_case"
class <%= class_name.pluralize %>Test < ApplicationSystemTestCase
diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb
index f9b14f98cb..76bc0ce1d7 100644
--- a/railties/test/application/rake_test.rb
+++ b/railties/test/application/rake_test.rb
@@ -133,13 +133,8 @@ module ApplicationTests
output = rails("routes")
assert_equal <<-MESSAGE.strip_heredoc, output
- Prefix Verb URI Pattern Controller#Action
- cart GET /cart(.:format) cart#show
- rails_service_blob GET /rails/active_storage/blobs/:signed_id/*filename(.:format) active_storage/blobs#show
- rails_blob_variation GET /rails/active_storage/variants/:signed_blob_id/:variation_key/*filename(.:format) active_storage/variants#show
- rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show
- update_rails_disk_service PUT /rails/active_storage/disk/:encoded_token(.:format) active_storage/disk#update
- rails_direct_uploads POST /rails/active_storage/direct_uploads(.:format) active_storage/direct_uploads#create
+ Prefix Verb URI Pattern Controller#Action
+ cart GET /cart(.:format) cart#show
MESSAGE
end
@@ -174,18 +169,14 @@ module ApplicationTests
output = rails("routes", "-g", "show", allow_failure: true)
assert_equal <<-MESSAGE.strip_heredoc, output
- Prefix Verb URI Pattern Controller#Action
- cart GET /cart(.:format) cart#show
- rails_service_blob GET /rails/active_storage/blobs/:signed_id/*filename(.:format) active_storage/blobs#show
- rails_blob_variation GET /rails/active_storage/variants/:signed_blob_id/:variation_key/*filename(.:format) active_storage/variants#show
- rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show
+ Prefix Verb URI Pattern Controller#Action
+ cart GET /cart(.:format) cart#show
MESSAGE
output = rails("routes", "-g", "POST")
assert_equal <<-MESSAGE.strip_heredoc, output
- Prefix Verb URI Pattern Controller#Action
- POST /cart(.:format) cart#create
- rails_direct_uploads POST /rails/active_storage/direct_uploads(.:format) active_storage/direct_uploads#create
+ Prefix Verb URI Pattern Controller#Action
+ POST /cart(.:format) cart#create
MESSAGE
output = rails("routes", "-g", "basketballs")
@@ -242,12 +233,11 @@ module ApplicationTests
RUBY
assert_equal <<-MESSAGE.strip_heredoc, rails("routes")
- Prefix Verb URI Pattern Controller#Action
- rails_service_blob GET /rails/active_storage/blobs/:signed_id/*filename(.:format) active_storage/blobs#show
- rails_blob_variation GET /rails/active_storage/variants/:signed_blob_id/:variation_key/*filename(.:format) active_storage/variants#show
- rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show
- update_rails_disk_service PUT /rails/active_storage/disk/:encoded_token(.:format) active_storage/disk#update
- rails_direct_uploads POST /rails/active_storage/direct_uploads(.:format) active_storage/direct_uploads#create
+ You don't have any routes defined!
+
+ Please add some routes in config/routes.rb.
+
+ For more information about routes, see the Rails guide: http://guides.rubyonrails.org/routing.html.
MESSAGE
end
@@ -261,13 +251,8 @@ module ApplicationTests
output = Dir.chdir(app_path) { `bin/rake --rakefile Rakefile routes` }
assert_equal <<-MESSAGE.strip_heredoc, output
- Prefix Verb URI Pattern Controller#Action
- cart GET /cart(.:format) cart#show
- rails_service_blob GET /rails/active_storage/blobs/:signed_id/*filename(.:format) active_storage/blobs#show
- rails_blob_variation GET /rails/active_storage/variants/:signed_blob_id/:variation_key/*filename(.:format) active_storage/variants#show
- rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show
- update_rails_disk_service PUT /rails/active_storage/disk/:encoded_token(.:format) active_storage/disk#update
- rails_direct_uploads POST /rails/active_storage/direct_uploads(.:format) active_storage/direct_uploads#create
+ Prefix Verb URI Pattern Controller#Action
+ cart GET /cart(.:format) cart#show
MESSAGE
end
diff --git a/railties/test/commands/credentials_test.rb b/railties/test/commands/credentials_test.rb
index fe52c306d2..743fb5f788 100644
--- a/railties/test/commands/credentials_test.rb
+++ b/railties/test/commands/credentials_test.rb
@@ -12,6 +12,21 @@ class Rails::Command::CredentialsCommandTest < ActiveSupport::TestCase
teardown { teardown_app }
+ test "edit without editor gives hint" do
+ assert_match "No $EDITOR to open credentials in", run_edit_command(editor: "")
+ end
+
+ test "edit credentials" do
+ # Run twice to ensure credentials can be reread after first edit pass.
+ 2.times do
+ assert_match(/access_key_id: 123/, run_edit_command)
+ end
+ end
+
+ test "show credentials" do
+ assert_match(/access_key_id: 123/, run_show_command)
+ end
+
test "edit command does not add master key to gitignore when already exist" do
run_edit_command
@@ -27,4 +42,8 @@ class Rails::Command::CredentialsCommandTest < ActiveSupport::TestCase
rails "credentials:edit"
end
end
+
+ def run_show_command
+ rails "credentials:show"
+ end
end