aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile.lock12
-rw-r--r--activerecord/CHANGELOG.md4
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/quoting.rb26
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/quoting.rb24
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb27
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb24
-rw-r--r--activerecord/lib/active_record/railties/databases.rake26
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb1
-rw-r--r--activerecord/lib/active_record/sanitization.rb3
-rw-r--r--activerecord/test/cases/associations/eager_test.rb8
-rw-r--r--activerecord/test/cases/calculations_test.rb6
-rw-r--r--activerecord/test/cases/query_cache_test.rb6
-rw-r--r--activerecord/test/cases/relations_test.rb6
-rw-r--r--activerecord/test/cases/unsafe_raw_sql_test.rb57
-rw-r--r--guides/source/action_text_overview.md2
-rw-r--r--guides/source/initialization.md4
-rw-r--r--railties/test/application/rake/multi_dbs_test.rb26
17 files changed, 191 insertions, 71 deletions
diff --git a/Gemfile.lock b/Gemfile.lock
index 39ea426ed9..85d38303f4 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -337,15 +337,14 @@ GEM
mysql2 (0.5.2)
mysql2 (0.5.2-x64-mingw32)
mysql2 (0.5.2-x86-mingw32)
- net_http_ssl_fix (0.0.10)
nio4r (2.3.1)
nio4r (2.3.1-java)
- nokogiri (1.9.1)
+ nokogiri (1.10.3)
mini_portile2 (~> 2.4.0)
- nokogiri (1.9.1-java)
- nokogiri (1.9.1-x64-mingw32)
+ nokogiri (1.10.3-java)
+ nokogiri (1.10.3-x64-mingw32)
mini_portile2 (~> 2.4.0)
- nokogiri (1.9.1-x86-mingw32)
+ nokogiri (1.10.3-x86-mingw32)
mini_portile2 (~> 2.4.0)
os (1.0.0)
parallel (1.17.0)
@@ -504,8 +503,7 @@ GEM
json (>= 1.8)
nokogiri (~> 1.6)
wdm (0.1.1)
- webdrivers (3.7.0)
- net_http_ssl_fix
+ webdrivers (4.0.0)
nokogiri (~> 1.6)
rubyzip (~> 1.0)
selenium-webdriver (~> 3.0)
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 09fdc66788..a4def5b270 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,7 @@
+* Add support for multiple databases to `rails db:abort_if_pending_migrations`.
+
+ *Mark Lee*
+
* Fix sqlite3 collation parsing when using decimal columns.
*Martin R. Schuster*
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
index 99e1a11f30..1b6ba8ce97 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
@@ -155,7 +155,18 @@ module ActiveRecord
#
# "#{table_name}.#{column_name}"
# "#{column_name}"
- COLUMN_NAME = /\A(?:\w+\.)?\w+\z/i
+ COLUMN_NAME = /
+ \A
+ (
+ (?:
+ # table_name.column_name | function(one or no argument)
+ ((?:\w+\.)?\w+) | \w+\((?:|\g<2>)\)
+ )
+ (?:(?:\s+AS)?\s+\w+)?
+ )
+ (?:\s*,\s*\g<1>)*
+ \z
+ /ix
# Regexp for column names with order (with or without a table name prefix,
# with or without various order modifiers). Matches the following:
@@ -170,10 +181,15 @@ module ActiveRecord
# "#{column_name} NULLS LAST"
COLUMN_NAME_WITH_ORDER = /
\A
- (?:\w+\.)?
- \w+
- (?:\s+ASC|\s+DESC)?
- (?:\s+NULLS\s+(?:FIRST|LAST))?
+ (
+ (?:
+ # table_name.column_name | function(one or no argument)
+ ((?:\w+\.)?\w+) | \w+\((?:|\g<2>)\)
+ )
+ (?:\s+ASC|\s+DESC)?
+ (?:\s+NULLS\s+(?:FIRST|LAST))?
+ )
+ (?:\s*,\s*\g<1>)*
\z
/ix
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb b/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb
index 84354c0187..dfed5471f4 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/quoting.rb
@@ -40,13 +40,29 @@ module ActiveRecord
COLUMN_NAME_WITH_ORDER
end
- COLUMN_NAME = /\A(?:(`?)\w+\k<1>\.)?(`?)\w+\k<2>\z/i
+ COLUMN_NAME = /
+ \A
+ (
+ (?:
+ # `table_name`.`column_name` | function(one or no argument)
+ ((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`)) | \w+\((?:|\g<2>)\)
+ )
+ (?:(?:\s+AS)?\s+(?:\w+|`\w+`))?
+ )
+ (?:\s*,\s*\g<1>)*
+ \z
+ /ix
COLUMN_NAME_WITH_ORDER = /
\A
- (?:(`?)\w+\k<1>\.)?
- (`?)\w+\k<2>
- (?:\s+ASC|\s+DESC)?
+ (
+ (?:
+ # `table_name`.`column_name` | function(one or no argument)
+ ((?:\w+\.|`\w+`\.)?(?:\w+|`\w+`)) | \w+\((?:|\g<2>)\)
+ )
+ (?:\s+ASC|\s+DESC)?
+ )
+ (?:\s*,\s*\g<1>)*
\z
/ix
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
index 0ebed21717..0c800dca83 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
@@ -86,15 +86,30 @@ module ActiveRecord
COLUMN_NAME_WITH_ORDER
end
- COLUMN_NAME = /\A(?:("?)\w+\k<1>\.)?("?)\w+\k<2>(?:::\w+)?\z/i
+ COLUMN_NAME = /
+ \A
+ (
+ (?:
+ # "table_name"."column_name"::type_name | function(one or no argument)::type_name
+ ((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")(?:::\w+)?) | \w+\((?:|\g<2>)\)(?:::\w+)?
+ )
+ (?:(?:\s+AS)?\s+(?:\w+|"\w+"))?
+ )
+ (?:\s*,\s*\g<1>)*
+ \z
+ /ix
COLUMN_NAME_WITH_ORDER = /
\A
- (?:("?)\w+\k<1>\.)?
- ("?)\w+\k<2>
- (?:::\w+)?
- (?:\s+ASC|\s+DESC)?
- (?:\s+NULLS\s+(?:FIRST|LAST))?
+ (
+ (?:
+ # "table_name"."column_name"::type_name | function(one or no argument)::type_name
+ ((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")(?:::\w+)?) | \w+\((?:|\g<2>)\)(?:::\w+)?
+ )
+ (?:\s+ASC|\s+DESC)?
+ (?:\s+NULLS\s+(?:FIRST|LAST))?
+ )
+ (?:\s*,\s*\g<1>)*
\z
/ix
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb b/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb
index 79d477cdb2..54808de714 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb
@@ -53,13 +53,29 @@ module ActiveRecord
COLUMN_NAME_WITH_ORDER
end
- COLUMN_NAME = /\A(?:("?)\w+\k<1>\.)?("?)\w+\k<2>\z/i
+ COLUMN_NAME = /
+ \A
+ (
+ (?:
+ # "table_name"."column_name" | function(one or no argument)
+ ((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")) | \w+\((?:|\g<2>)\)
+ )
+ (?:(?:\s+AS)?\s+(?:\w+|"\w+"))?
+ )
+ (?:\s*,\s*\g<1>)*
+ \z
+ /ix
COLUMN_NAME_WITH_ORDER = /
\A
- (?:("?)\w+\k<1>\.)?
- ("?)\w+\k<2>
- (?:\s+ASC|\s+DESC)?
+ (
+ (?:
+ # "table_name"."column_name" | function(one or no argument)
+ ((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")) | \w+\((?:|\g<2>)\)
+ )
+ (?:\s+ASC|\s+DESC)?
+ )
+ (?:\s*,\s*\g<1>)*
\z
/ix
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake
index befcbc8984..d17acc408c 100644
--- a/activerecord/lib/active_record/railties/databases.rake
+++ b/activerecord/lib/active_record/railties/databases.rake
@@ -250,7 +250,11 @@ db_namespace = namespace :db do
# desc "Raises an error if there are pending migrations"
task abort_if_pending_migrations: :load_config do
- pending_migrations = ActiveRecord::Base.connection.migration_context.open.pending_migrations
+ pending_migrations = ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).flat_map do |db_config|
+ ActiveRecord::Base.establish_connection(db_config.config)
+
+ ActiveRecord::Base.connection.migration_context.open.pending_migrations
+ end
if pending_migrations.any?
puts "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}"
@@ -261,6 +265,26 @@ db_namespace = namespace :db do
end
end
+ namespace :abort_if_pending_migrations do
+ ActiveRecord::Tasks::DatabaseTasks.for_each do |spec_name|
+ # desc "Raises an error if there are pending migrations for #{spec_name} database"
+ task spec_name => :load_config do
+ db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
+ ActiveRecord::Base.establish_connection(db_config.config)
+
+ pending_migrations = ActiveRecord::Base.connection.migration_context.open.pending_migrations
+
+ if pending_migrations.any?
+ puts "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}"
+ pending_migrations.each do |pending_migration|
+ puts " %4d %s" % [pending_migration.version, pending_migration.name]
+ end
+ abort %{Run `rails db:migrate:#{spec_name}` to update your database then try again.}
+ end
+ end
+ end
+ end
+
desc "Creates the database, loads the schema, and initializes with the seed data (use db:reset to also drop the database first)"
task setup: ["db:schema:load_if_ruby", "db:structure:load_if_sql", :seed]
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 588cb130f2..d1bcec9704 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -1247,6 +1247,7 @@ module ActiveRecord
end
def preprocess_order_args(order_args)
+ order_args.reject!(&:blank?)
order_args.map! do |arg|
klass.sanitize_sql_for_order(arg)
end
diff --git a/activerecord/lib/active_record/sanitization.rb b/activerecord/lib/active_record/sanitization.rb
index 5296499bad..b16cbb0f84 100644
--- a/activerecord/lib/active_record/sanitization.rb
+++ b/activerecord/lib/active_record/sanitization.rb
@@ -137,8 +137,7 @@ module ActiveRecord
def disallow_raw_sql!(args, permit: connection.column_name_matcher) # :nodoc:
unexpected = nil
args.each do |arg|
- next if arg.is_a?(Symbol) || Arel.arel_node?(arg) ||
- arg.to_s.split(/\s*,\s*/).all? { |part| permit.match?(part) }
+ next if arg.is_a?(Symbol) || Arel.arel_node?(arg) || permit.match?(arg.to_s)
(unexpected ||= []) << arg
end
diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb
index 38723b6c19..cb46f9e053 100644
--- a/activerecord/test/cases/associations/eager_test.rb
+++ b/activerecord/test/cases/associations/eager_test.rb
@@ -968,14 +968,14 @@ class EagerAssociationTest < ActiveRecord::TestCase
posts(:thinking, :sti_comments),
Post.all.merge!(
includes: [:author, :comments], where: { "authors.name" => "David" },
- order: Arel.sql("UPPER(posts.title)"), limit: 2, offset: 1
+ order: "UPPER(posts.title)", limit: 2, offset: 1
).to_a
)
assert_equal(
posts(:sti_post_and_comments, :sti_comments),
Post.all.merge!(
includes: [:author, :comments], where: { "authors.name" => "David" },
- order: Arel.sql("UPPER(posts.title) DESC"), limit: 2, offset: 1
+ order: "UPPER(posts.title) DESC", limit: 2, offset: 1
).to_a
)
end
@@ -985,14 +985,14 @@ class EagerAssociationTest < ActiveRecord::TestCase
posts(:thinking, :sti_comments),
Post.all.merge!(
includes: [:author, :comments], where: { "authors.name" => "David" },
- order: [Arel.sql("UPPER(posts.title)"), "posts.id"], limit: 2, offset: 1
+ order: ["UPPER(posts.title)", "posts.id"], limit: 2, offset: 1
).to_a
)
assert_equal(
posts(:sti_post_and_comments, :sti_comments),
Post.all.merge!(
includes: [:author, :comments], where: { "authors.name" => "David" },
- order: [Arel.sql("UPPER(posts.title) DESC"), "posts.id"], limit: 2, offset: 1
+ order: ["UPPER(posts.title) DESC", "posts.id"], limit: 2, offset: 1
).to_a
)
end
diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb
index e42af3686e..5dabff1431 100644
--- a/activerecord/test/cases/calculations_test.rb
+++ b/activerecord/test/cases/calculations_test.rb
@@ -589,11 +589,7 @@ class CalculationsTest < ActiveRecord::TestCase
end
def test_should_sum_expression
- if current_adapter?(:SQLite3Adapter, :Mysql2Adapter, :PostgreSQLAdapter, :OracleAdapter)
- assert_equal 636, Account.sum("2 * credit_limit")
- else
- assert_equal 636, Account.sum("2 * credit_limit").to_i
- end
+ assert_equal 636, Account.sum("2 * credit_limit")
end
def test_sum_expression_returns_zero_when_no_records_to_sum
diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb
index eb32b690aa..8adff9129d 100644
--- a/activerecord/test/cases/query_cache_test.rb
+++ b/activerecord/test/cases/query_cache_test.rb
@@ -335,11 +335,7 @@ class QueryCacheTest < ActiveRecord::TestCase
def test_cache_does_not_wrap_results_in_arrays
Task.cache do
- if current_adapter?(:SQLite3Adapter, :Mysql2Adapter, :PostgreSQLAdapter, :OracleAdapter)
- assert_equal 2, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
- else
- assert_instance_of String, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
- end
+ assert_equal 2, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
end
end
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index 732bca4bf5..a5c162af33 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -298,7 +298,7 @@ class RelationTest < ActiveRecord::TestCase
end
def test_reverse_order_with_function
- topics = Topic.order(Arel.sql("length(title)")).reverse_order
+ topics = Topic.order("length(title)").reverse_order
assert_equal topics(:second).title, topics.first.title
end
@@ -1696,7 +1696,7 @@ class RelationTest < ActiveRecord::TestCase
scope = Post.order("comments.body asc")
assert_equal ["comments"], scope.references_values
- scope = Post.order(Arel.sql("foo(comments.body)"))
+ scope = Post.order("foo(comments.body)")
assert_equal [], scope.references_values
end
@@ -1721,7 +1721,7 @@ class RelationTest < ActiveRecord::TestCase
scope = Post.reorder("comments.body asc")
assert_equal %w(comments), scope.references_values
- scope = Post.reorder(Arel.sql("foo(comments.body)"))
+ scope = Post.reorder("foo(comments.body)")
assert_equal [], scope.references_values
end
diff --git a/activerecord/test/cases/unsafe_raw_sql_test.rb b/activerecord/test/cases/unsafe_raw_sql_test.rb
index fc92bf73c9..87edb163f2 100644
--- a/activerecord/test/cases/unsafe_raw_sql_test.rb
+++ b/activerecord/test/cases/unsafe_raw_sql_test.rb
@@ -141,7 +141,7 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
test "order: disallows invalid column name" do
with_unsafe_raw_sql_disabled do
assert_raises(ActiveRecord::UnknownAttributeReference) do
- Post.order("len(title) asc").pluck(:id)
+ Post.order("REPLACE(title, 'misc', 'zzzz') asc").pluck(:id)
end
end
end
@@ -157,7 +157,7 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
test "order: disallows invalid column with direction" do
with_unsafe_raw_sql_disabled do
assert_raises(ActiveRecord::UnknownAttributeReference) do
- Post.order("len(title)" => :asc).pluck(:id)
+ Post.order("REPLACE(title, 'misc', 'zzzz')" => :asc).pluck(:id)
end
end
end
@@ -190,7 +190,7 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
test "order: disallows invalid Array arguments" do
with_unsafe_raw_sql_disabled do
assert_raises(ActiveRecord::UnknownAttributeReference) do
- Post.order(["author_id", "length(title)"]).pluck(:id)
+ Post.order(["author_id", "REPLACE(title, 'misc', 'zzzz')"]).pluck(:id)
end
end
end
@@ -198,8 +198,8 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
test "order: allows valid Array arguments" do
ids_expected = Post.order(Arel.sql("author_id, length(title)")).pluck(:id)
- ids_depr = with_unsafe_raw_sql_deprecated { Post.order(["author_id", Arel.sql("length(title)")]).pluck(:id) }
- ids_disabled = with_unsafe_raw_sql_disabled { Post.order(["author_id", Arel.sql("length(title)")]).pluck(:id) }
+ ids_depr = with_unsafe_raw_sql_deprecated { Post.order(["author_id", "length(title)"]).pluck(:id) }
+ ids_disabled = with_unsafe_raw_sql_disabled { Post.order(["author_id", "length(title)"]).pluck(:id) }
assert_equal ids_expected, ids_depr
assert_equal ids_expected, ids_disabled
@@ -208,7 +208,7 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
test "order: logs deprecation warning for unrecognized column" do
with_unsafe_raw_sql_deprecated do
assert_deprecated(/Dangerous query method/) do
- Post.order("length(title)")
+ Post.order("REPLACE(title, 'misc', 'zzzz')")
end
end
end
@@ -223,6 +223,16 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
assert_equal titles_expected, titles_disabled
end
+ test "pluck: allows string column name with function and alias" do
+ titles_expected = Post.pluck(Arel.sql("UPPER(title)"))
+
+ titles_depr = with_unsafe_raw_sql_deprecated { Post.pluck("UPPER(title) AS title") }
+ titles_disabled = with_unsafe_raw_sql_disabled { Post.pluck("UPPER(title) AS title") }
+
+ assert_equal titles_expected, titles_depr
+ assert_equal titles_expected, titles_disabled
+ end
+
test "pluck: allows symbol column name" do
titles_expected = Post.pluck(Arel.sql("title"))
@@ -287,7 +297,7 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
test "pluck: disallows invalid column name" do
with_unsafe_raw_sql_disabled do
assert_raises(ActiveRecord::UnknownAttributeReference) do
- Post.pluck("length(title)")
+ Post.pluck("REPLACE(title, 'misc', 'zzzz')")
end
end
end
@@ -295,7 +305,7 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
test "pluck: disallows invalid column name amongst valid names" do
with_unsafe_raw_sql_disabled do
assert_raises(ActiveRecord::UnknownAttributeReference) do
- Post.pluck(:title, "length(title)")
+ Post.pluck(:title, "REPLACE(title, 'misc', 'zzzz')")
end
end
end
@@ -303,7 +313,7 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
test "pluck: disallows invalid column names with includes" do
with_unsafe_raw_sql_disabled do
assert_raises(ActiveRecord::UnknownAttributeReference) do
- Post.includes(:comments).pluck(:title, "length(title)")
+ Post.includes(:comments).pluck(:title, "REPLACE(title, 'misc', 'zzzz')")
end
end
end
@@ -318,24 +328,25 @@ class UnsafeRawSqlTest < ActiveRecord::TestCase
test "pluck: logs deprecation warning" do
with_unsafe_raw_sql_deprecated do
assert_deprecated(/Dangerous query method/) do
- Post.includes(:comments).pluck(:title, "length(title)")
+ Post.includes(:comments).pluck(:title, "REPLACE(title, 'misc', 'zzzz')")
end
end
end
- def with_unsafe_raw_sql_disabled(&blk)
- with_config(:disabled, &blk)
- end
+ private
+ def with_unsafe_raw_sql_disabled(&block)
+ with_config(:disabled, &block)
+ end
- def with_unsafe_raw_sql_deprecated(&blk)
- with_config(:deprecated, &blk)
- end
+ def with_unsafe_raw_sql_deprecated(&block)
+ with_config(:deprecated, &block)
+ end
- def with_config(new_value, &blk)
- old_value = ActiveRecord::Base.allow_unsafe_raw_sql
- ActiveRecord::Base.allow_unsafe_raw_sql = new_value
- blk.call
- ensure
- ActiveRecord::Base.allow_unsafe_raw_sql = old_value
- end
+ def with_config(new_value, &block)
+ old_value = ActiveRecord::Base.allow_unsafe_raw_sql
+ ActiveRecord::Base.allow_unsafe_raw_sql = new_value
+ yield
+ ensure
+ ActiveRecord::Base.allow_unsafe_raw_sql = old_value
+ end
end
diff --git a/guides/source/action_text_overview.md b/guides/source/action_text_overview.md
index 07919775e2..a735ec2b0e 100644
--- a/guides/source/action_text_overview.md
+++ b/guides/source/action_text_overview.md
@@ -46,6 +46,8 @@ happens after every keystroke, and avoids the need to use execCommand at all.
## Installation
Run `rails action_text:install` to add the Yarn package and copy over the necessary migration.
+Also, you need to set up Active Storage for embedded images and other attachments.
+Please refer to the [Active Storage Overview](active_storage_overview.html) guide.
## Examples
diff --git a/guides/source/initialization.md b/guides/source/initialization.md
index c41eae18cf..817c6b17bc 100644
--- a/guides/source/initialization.md
+++ b/guides/source/initialization.md
@@ -160,8 +160,8 @@ namespace and executes the command if found.
If Rails doesn't recognize the command, it hands the reins over to Rake
to run a task of the same name.
-As shown, `Rails::Command` displays the help output automatically if the `args`
-are empty.
+As shown, `Rails::Command` displays the help output automatically if the `namespace`
+is empty.
```ruby
module Rails::Command
diff --git a/railties/test/application/rake/multi_dbs_test.rb b/railties/test/application/rake/multi_dbs_test.rb
index 8c41b252da..2606e64424 100644
--- a/railties/test/application/rake/multi_dbs_test.rb
+++ b/railties/test/application/rake/multi_dbs_test.rb
@@ -299,6 +299,32 @@ module ApplicationTests
db_migrate_and_schema_cache_dump_and_schema_cache_clear
end
+ test "db:abort_if_pending_migrations works on all databases" do
+ require "#{app_path}/config/environment"
+
+ app_file "db/animals_migrate/02_two_migration.rb", <<-MIGRATION
+ class TwoMigration < ActiveRecord::Migration::Current
+ end
+ MIGRATION
+
+ output = rails("db:abort_if_pending_migrations", allow_failure: true)
+ assert_match(/You have 1 pending migration/, output)
+ end
+
+ test "db:abort_if_pending_migrations:namespace works" do
+ require "#{app_path}/config/environment"
+
+ app_file "db/animals_migrate/02_two_migration.rb", <<-MIGRATION
+ class TwoMigration < ActiveRecord::Migration::Current
+ end
+ MIGRATION
+
+ output = rails("db:abort_if_pending_migrations:primary")
+ assert_no_match(/You have \d+ pending migration/, output)
+ output = rails("db:abort_if_pending_migrations:animals", allow_failure: true)
+ assert_match(/You have 1 pending migration/, output)
+ end
+
test "db:prepare works on all databases" do
require "#{app_path}/config/environment"
db_prepare