aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/CHANGELOG.md4
-rw-r--r--actionpack/lib/action_controller/metal/request_forgery_protection.rb1
-rw-r--r--actionpack/lib/action_dispatch/routing/endpoint.rb10
-rw-r--r--actionpack/lib/action_dispatch/routing/inspector.rb4
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb18
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb7
-rw-r--r--actionpack/lib/action_dispatch/system_testing/driver.rb2
-rw-r--r--actionpack/test/dispatch/routing_assertions_test.rb71
-rw-r--r--activejob/test/support/integration/dummy_app_template.rb2
-rw-r--r--activejob/test/support/integration/helper.rb1
-rw-r--r--activemodel/CHANGELOG.md4
-rw-r--r--activemodel/lib/active_model/validations/confirmation.rb2
-rw-r--r--activemodel/test/cases/validations/conditional_validation_test.rb49
-rw-r--r--activemodel/test/cases/validations/confirmation_validation_test.rb13
-rw-r--r--activemodel/test/cases/validations/numericality_validation_test.rb2
-rw-r--r--activemodel/test/cases/validations/validates_test.rb12
-rw-r--r--activemodel/test/models/person.rb4
-rw-r--r--activemodel/test/models/topic.rb2
-rw-r--r--activerecord/CHANGELOG.md8
-rw-r--r--activerecord/lib/active_record/associations/preloader/association.rb22
-rw-r--r--activerecord/lib/active_record/associations/preloader/has_many_through.rb10
-rw-r--r--activerecord/lib/active_record/associations/preloader/through_association.rb95
-rw-r--r--activerecord/lib/active_record/collection_cache_key.rb3
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/transaction.rb2
-rw-r--r--activerecord/lib/active_record/migration.rb2
-rw-r--r--activerecord/lib/active_record/railties/databases.rake19
-rw-r--r--activerecord/lib/active_record/relation.rb10
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb4
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb2
-rw-r--r--activerecord/lib/active_record/scoping/named.rb8
-rw-r--r--activerecord/lib/active_record/tasks/database_tasks.rb15
-rw-r--r--activerecord/test/cases/associations/nested_through_associations_test.rb22
-rw-r--r--activerecord/test/cases/collection_cache_key_test.rb10
-rw-r--r--activerecord/test/cases/migrator_test.rb20
-rw-r--r--activerecord/test/cases/persistence_test.rb49
-rw-r--r--activerecord/test/cases/scoping/relation_scoping_test.rb14
-rw-r--r--activerecord/test/cases/tasks/database_tasks_test.rb149
-rw-r--r--activerecord/test/models/comment.rb4
-rw-r--r--activerecord/test/schema/schema.rb1
-rw-r--r--activestorage/lib/active_storage/service/azure_storage_service.rb8
-rw-r--r--activestorage/lib/active_storage/service/s3_service.rb6
-rw-r--r--activestorage/test/service/shared_service_tests.rb10
-rw-r--r--activesupport/CHANGELOG.md92
-rw-r--r--activesupport/lib/active_support/core_ext/date_and_time/calculations.rb40
-rw-r--r--activesupport/lib/active_support/inflector/methods.rb2
-rw-r--r--activesupport/lib/active_support/inflector/transliterate.rb12
-rw-r--r--activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb8
-rw-r--r--activesupport/lib/active_support/testing/assertions.rb7
-rw-r--r--activesupport/test/core_ext/date_and_time_behavior.rb50
-rw-r--r--activesupport/test/core_ext/date_ext_test.rb8
-rw-r--r--activesupport/test/core_ext/date_time_ext_test.rb8
-rw-r--r--activesupport/test/core_ext/time_ext_test.rb8
-rw-r--r--activesupport/test/inflector_test.rb13
-rw-r--r--guides/source/active_support_core_extensions.md200
-rw-r--r--railties/CHANGELOG.md6
-rw-r--r--railties/lib/rails/all.rb2
-rw-r--r--railties/lib/rails/app_updater.rb11
-rw-r--r--railties/lib/rails/generators/actions.rb8
-rw-r--r--railties/lib/rails/generators/app_base.rb129
-rw-r--r--railties/lib/rails/generators/named_base.rb19
-rw-r--r--railties/lib/rails/generators/rails/app/app_generator.rb9
-rw-r--r--railties/lib/rails/generators/rails/app/templates/Gemfile3
-rw-r--r--railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/application.rb2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt3
-rw-r--r--railties/lib/rails/generators/rails/app/templates/gitignore2
-rw-r--r--railties/lib/rails/generators/rails/plugin/plugin_generator.rb2
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/gitignore3
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/rails/application.rb2
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js3
-rw-r--r--railties/test/application/bin_setup_test.rb4
-rw-r--r--railties/test/application/integration_test_case_test.rb7
-rw-r--r--railties/test/application/middleware/exceptions_test.rb2
-rw-r--r--railties/test/application/rackup_test.rb1
-rw-r--r--railties/test/application/rake/dbs_test.rb4
-rw-r--r--railties/test/application/rake/migrations_test.rb156
-rw-r--r--railties/test/application/test_runner_test.rb5
-rw-r--r--railties/test/application/test_test.rb5
-rw-r--r--railties/test/generators/actions_test.rb16
-rw-r--r--railties/test/generators/app_generator_test.rb74
-rw-r--r--railties/test/generators/named_base_test.rb22
-rw-r--r--railties/test/generators/plugin_generator_test.rb5
-rw-r--r--railties/test/generators/plugin_test_runner_test.rb2
-rw-r--r--railties/test/generators/scaffold_controller_generator_test.rb2
-rw-r--r--railties/test/generators/scaffold_generator_test.rb9
-rw-r--r--railties/test/generators/shared_generator_tests.rb120
-rw-r--r--railties/test/generators/test_runner_in_engine_test.rb2
-rw-r--r--railties/test/isolation/abstract_unit.rb1
-rw-r--r--railties/test/railties/engine_test.rb47
91 files changed, 1437 insertions, 406 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 32239d202c..e01f88e902 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,3 +1,7 @@
+* Make `assert_recognizes` to traverse mounted engines
+
+ *Yuichiro Kaneko*
+
* Remove deprecated `ActionController::ParamsParser::ParseError`.
*Rafael Mendonça França*
diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
index d6cd5fd9e0..bd133f24a1 100644
--- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -248,6 +248,7 @@ module ActionController #:nodoc:
"If you know what you're doing, go ahead and disable forgery " \
"protection on this action to permit cross-origin JavaScript embedding."
private_constant :CROSS_ORIGIN_JAVASCRIPT_WARNING
+ # :startdoc:
# If `verify_authenticity_token` was run (indicating that we have
# forgery protection enabled for this request) then also verify that
diff --git a/actionpack/lib/action_dispatch/routing/endpoint.rb b/actionpack/lib/action_dispatch/routing/endpoint.rb
index e911b6537b..24dced1efd 100644
--- a/actionpack/lib/action_dispatch/routing/endpoint.rb
+++ b/actionpack/lib/action_dispatch/routing/endpoint.rb
@@ -3,10 +3,12 @@
module ActionDispatch
module Routing
class Endpoint # :nodoc:
- def dispatcher?; false; end
- def redirect?; false; end
- def matches?(req); true; end
- def app; self; end
+ def dispatcher?; false; end
+ def redirect?; false; end
+ def engine?; rack_app.respond_to?(:routes); end
+ def matches?(req); true; end
+ def app; self; end
+ def rack_app; app; end
end
end
end
diff --git a/actionpack/lib/action_dispatch/routing/inspector.rb b/actionpack/lib/action_dispatch/routing/inspector.rb
index b2868b7427..a2205569b4 100644
--- a/actionpack/lib/action_dispatch/routing/inspector.rb
+++ b/actionpack/lib/action_dispatch/routing/inspector.rb
@@ -15,7 +15,7 @@ module ActionDispatch
end
def rack_app
- app.app
+ app.rack_app
end
def path
@@ -47,7 +47,7 @@ module ActionDispatch
end
def engine?
- rack_app.respond_to?(:routes)
+ app.engine?
end
end
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index dea8387c3d..ded42adee9 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -475,6 +475,16 @@ module ActionDispatch
#
# resources :users, param: :name
#
+ # The +users+ resource here will have the following routes generated for it:
+ #
+ # GET /users(.:format)
+ # POST /users(.:format)
+ # GET /users/new(.:format)
+ # GET /users/:name/edit(.:format)
+ # GET /users/:name(.:format)
+ # PATCH/PUT /users/:name(.:format)
+ # DELETE /users/:name(.:format)
+ #
# You can override <tt>ActiveRecord::Base#to_param</tt> of a related
# model to construct a URL:
#
@@ -484,8 +494,8 @@ module ActionDispatch
# end
# end
#
- # user = User.find_by(name: 'Phusion')
- # user_path(user) # => "/users/Phusion"
+ # user = User.find_by(name: 'Phusion')
+ # user_path(user) # => "/users/Phusion"
#
# [:path]
# The path prefix for the routes.
@@ -1265,7 +1275,7 @@ module ActionDispatch
# POST /profile
#
# === Options
- # Takes same options as +resources+.
+ # Takes same options as resources[rdoc-ref:#resources]
def resource(*resources, &block)
options = resources.extract_options!.dup
@@ -1330,7 +1340,7 @@ module ActionDispatch
# DELETE /photos/:photo_id/comments/:id
#
# === Options
- # Takes same options as <tt>Base#match</tt> as well as:
+ # Takes same options as match[rdoc-ref:Base#match] as well as:
#
# [:path_names]
# Allows you to change the segment component of the +edit+ and +new+ actions.
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 71cb458112..987e709f6f 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -842,6 +842,10 @@ module ActionDispatch
end
req = make_request(env)
+ recognize_path_with_request(req, path, extras)
+ end
+
+ def recognize_path_with_request(req, path, extras)
@router.recognize(req) do |route, params|
params.merge!(extras)
params.each do |key, value|
@@ -860,6 +864,9 @@ module ActionDispatch
end
return req.path_parameters
+ elsif app.matches?(req) && app.engine?
+ path_parameters = app.rack_app.routes.recognize_path_with_request(req, path, extras)
+ return path_parameters
end
end
diff --git a/actionpack/lib/action_dispatch/system_testing/driver.rb b/actionpack/lib/action_dispatch/system_testing/driver.rb
index 770fbde74e..2687772b4b 100644
--- a/actionpack/lib/action_dispatch/system_testing/driver.rb
+++ b/actionpack/lib/action_dispatch/system_testing/driver.rb
@@ -59,7 +59,7 @@ module ActionDispatch
def register_webkit(app)
Capybara::Webkit::Driver.new(app, Capybara::Webkit::Configuration.to_hash.merge(@options)).tap do |driver|
- driver.resize_window(*@screen_size)
+ driver.resize_window_to(driver.current_window_handle, *@screen_size)
end
end
diff --git a/actionpack/test/dispatch/routing_assertions_test.rb b/actionpack/test/dispatch/routing_assertions_test.rb
index e492a56653..a5198f2f13 100644
--- a/actionpack/test/dispatch/routing_assertions_test.rb
+++ b/actionpack/test/dispatch/routing_assertions_test.rb
@@ -1,14 +1,40 @@
# frozen_string_literal: true
require "abstract_unit"
+require "rails/engine"
require "controller/fake_controllers"
class SecureArticlesController < ArticlesController; end
class BlockArticlesController < ArticlesController; end
class QueryArticlesController < ArticlesController; end
+class SecureBooksController < BooksController; end
+class BlockBooksController < BooksController; end
+class QueryBooksController < BooksController; end
+
class RoutingAssertionsTest < ActionController::TestCase
def setup
+ engine = Class.new(Rails::Engine) do
+ def self.name
+ "blog_engine"
+ end
+ end
+ engine.routes.draw do
+ resources :books
+
+ scope "secure", constraints: { protocol: "https://" } do
+ resources :books, controller: "secure_books"
+ end
+
+ scope "block", constraints: lambda { |r| r.ssl? } do
+ resources :books, controller: "block_books"
+ end
+
+ scope "query", constraints: lambda { |r| r.params[:use_query] == "true" } do
+ resources :books, controller: "query_books"
+ end
+ end
+
@routes = ActionDispatch::Routing::RouteSet.new
@routes.draw do
resources :articles
@@ -24,6 +50,8 @@ class RoutingAssertionsTest < ActionController::TestCase
scope "query", constraints: lambda { |r| r.params[:use_query] == "true" } do
resources :articles, controller: "query_articles"
end
+
+ mount engine => "/shelf"
end
end
@@ -83,6 +111,49 @@ class RoutingAssertionsTest < ActionController::TestCase
assert_match err.message, "This is a really bad msg"
end
+ def test_assert_recognizes_with_engine
+ assert_recognizes({ controller: "books", action: "index" }, "/shelf/books")
+ assert_recognizes({ controller: "books", action: "show", id: "1" }, "/shelf/books/1")
+ end
+
+ def test_assert_recognizes_with_engine_and_extras
+ assert_recognizes({ controller: "books", action: "index", page: "1" }, "/shelf/books", page: "1")
+ end
+
+ def test_assert_recognizes_with_engine_and_method
+ assert_recognizes({ controller: "books", action: "create" }, { path: "/shelf/books", method: :post })
+ assert_recognizes({ controller: "books", action: "update", id: "1" }, { path: "/shelf/books/1", method: :put })
+ end
+
+ def test_assert_recognizes_with_engine_and_hash_constraint
+ assert_raise(Assertion) do
+ assert_recognizes({ controller: "secure_books", action: "index" }, "http://test.host/shelf/secure/books")
+ end
+ assert_recognizes({ controller: "secure_books", action: "index", protocol: "https://" }, "https://test.host/shelf/secure/books")
+ end
+
+ def test_assert_recognizes_with_engine_and_block_constraint
+ assert_raise(Assertion) do
+ assert_recognizes({ controller: "block_books", action: "index" }, "http://test.host/shelf/block/books")
+ end
+ assert_recognizes({ controller: "block_books", action: "index" }, "https://test.host/shelf/block/books")
+ end
+
+ def test_assert_recognizes_with_engine_and_query_constraint
+ assert_raise(Assertion) do
+ assert_recognizes({ controller: "query_books", action: "index", use_query: "false" }, "/shelf/query/books", use_query: "false")
+ end
+ assert_recognizes({ controller: "query_books", action: "index", use_query: "true" }, "/shelf/query/books", use_query: "true")
+ end
+
+ def test_assert_recognizes_raises_message_with_engine
+ err = assert_raise(Assertion) do
+ assert_recognizes({ controller: "secure_books", action: "index" }, "http://test.host/shelf/secure/books", {}, "This is a really bad msg")
+ end
+
+ assert_match err.message, "This is a really bad msg"
+ end
+
def test_assert_routing
assert_routing("/articles", controller: "articles", action: "index")
end
diff --git a/activejob/test/support/integration/dummy_app_template.rb b/activejob/test/support/integration/dummy_app_template.rb
index ac382bd1b7..7ea78c3350 100644
--- a/activejob/test/support/integration/dummy_app_template.rb
+++ b/activejob/test/support/integration/dummy_app_template.rb
@@ -4,8 +4,6 @@ if ENV["AJ_ADAPTER"] == "delayed_job"
generate "delayed_job:active_record", "--quiet"
end
-rails_command("db:migrate")
-
initializer "activejob.rb", <<-CODE
require "#{File.expand_path("jobs_manager.rb", __dir__)}"
JobsManager.current_manager.setup
diff --git a/activejob/test/support/integration/helper.rb b/activejob/test/support/integration/helper.rb
index a058da141f..a02d874e2e 100644
--- a/activejob/test/support/integration/helper.rb
+++ b/activejob/test/support/integration/helper.rb
@@ -18,6 +18,7 @@ Rails::Generators::AppGenerator.start args
require "#{dummy_app_path}/config/environment.rb"
ActiveRecord::Migrator.migrations_paths = [ Rails.root.join("db/migrate").to_s ]
+ActiveRecord::Tasks::DatabaseTasks.migrate
require "rails/test_help"
Rails.backtrace_cleaner.remove_silencers!
diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md
index 82e3a7f4dd..794744c646 100644
--- a/activemodel/CHANGELOG.md
+++ b/activemodel/CHANGELOG.md
@@ -1,3 +1,7 @@
+* Execute `ConfirmationValidator` validation when `_confirmation`'s value is `false`.
+
+ *bogdanvlviv*
+
* Allow passing a Proc or Symbol to length validator options.
*Matt Rohrer*
diff --git a/activemodel/lib/active_model/validations/confirmation.rb b/activemodel/lib/active_model/validations/confirmation.rb
index 0abec56b68..1b5d5b09ab 100644
--- a/activemodel/lib/active_model/validations/confirmation.rb
+++ b/activemodel/lib/active_model/validations/confirmation.rb
@@ -9,7 +9,7 @@ module ActiveModel
end
def validate_each(record, attribute, value)
- if (confirmed = record.send("#{attribute}_confirmation"))
+ unless (confirmed = record.send("#{attribute}_confirmation")).nil?
unless confirmation_value_equal?(record, attribute, value, confirmed)
human_attribute_name = record.class.human_attribute_name(attribute)
record.errors.add(:"#{attribute}_confirmation", :confirmation, options.except(:case_sensitive).merge!(attribute: human_attribute_name))
diff --git a/activemodel/test/cases/validations/conditional_validation_test.rb b/activemodel/test/cases/validations/conditional_validation_test.rb
index aa027c4128..caea8b65ef 100644
--- a/activemodel/test/cases/validations/conditional_validation_test.rb
+++ b/activemodel/test/cases/validations/conditional_validation_test.rb
@@ -18,6 +18,22 @@ class ConditionalValidationTest < ActiveModel::TestCase
assert_equal ["hoo 5"], t.errors["title"]
end
+ def test_if_validation_using_array_of_true_methods
+ Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", if: [:condition_is_true, :condition_is_true])
+ t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
+ assert t.invalid?
+ assert t.errors[:title].any?
+ assert_equal ["hoo 5"], t.errors["title"]
+ end
+
+ def test_unless_validation_using_array_of_false_methods
+ Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", unless: [:condition_is_false, :condition_is_false])
+ t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
+ assert t.invalid?
+ assert t.errors[:title].any?
+ assert_equal ["hoo 5"], t.errors["title"]
+ end
+
def test_unless_validation_using_method_true
# When the method returns true
Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", unless: :condition_is_true)
@@ -26,9 +42,23 @@ class ConditionalValidationTest < ActiveModel::TestCase
assert_empty t.errors[:title]
end
+ def test_if_validation_using_array_of_true_and_false_methods
+ Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", if: [:condition_is_true, :condition_is_false])
+ t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
+ assert t.valid?
+ assert_empty t.errors[:title]
+ end
+
+ def test_unless_validation_using_array_of_true_and_felse_methods
+ Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", unless: [:condition_is_true, :condition_is_false])
+ t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
+ assert t.valid?
+ assert_empty t.errors[:title]
+ end
+
def test_if_validation_using_method_false
# When the method returns false
- Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", if: :condition_is_true_but_its_not)
+ Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", if: :condition_is_false)
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
assert t.valid?
assert_empty t.errors[:title]
@@ -36,7 +66,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
def test_unless_validation_using_method_false
# When the method returns false
- Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", unless: :condition_is_true_but_its_not)
+ Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", unless: :condition_is_false)
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
assert t.invalid?
assert t.errors[:title].any?
@@ -80,4 +110,19 @@ class ConditionalValidationTest < ActiveModel::TestCase
assert t.errors[:title].any?
assert_equal ["hoo 5"], t.errors["title"]
end
+
+ def test_validation_using_conbining_if_true_and_unless_true_conditions
+ Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", if: :condition_is_true, unless: :condition_is_true)
+ t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
+ assert t.valid?
+ assert_empty t.errors[:title]
+ end
+
+ def test_validation_using_conbining_if_true_and_unless_false_conditions
+ Topic.validates_length_of(:title, maximum: 5, too_long: "hoo %{count}", if: :condition_is_true, unless: :condition_is_false)
+ t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
+ assert t.invalid?
+ assert t.errors[:title].any?
+ assert_equal ["hoo 5"], t.errors["title"]
+ end
end
diff --git a/activemodel/test/cases/validations/confirmation_validation_test.rb b/activemodel/test/cases/validations/confirmation_validation_test.rb
index e84415a868..8b2c65289b 100644
--- a/activemodel/test/cases/validations/confirmation_validation_test.rb
+++ b/activemodel/test/cases/validations/confirmation_validation_test.rb
@@ -37,6 +37,19 @@ class ConfirmationValidationTest < ActiveModel::TestCase
assert t.valid?
end
+ def test_validates_confirmation_of_with_boolean_attribute
+ Topic.validates_confirmation_of(:approved)
+
+ t = Topic.new(approved: true, approved_confirmation: nil)
+ assert t.valid?
+
+ t.approved_confirmation = false
+ assert t.invalid?
+
+ t.approved_confirmation = true
+ assert t.valid?
+ end
+
def test_validates_confirmation_of_for_ruby_class
Person.validates_confirmation_of :karma
diff --git a/activemodel/test/cases/validations/numericality_validation_test.rb b/activemodel/test/cases/validations/numericality_validation_test.rb
index 001815e28f..fbbaf8a30c 100644
--- a/activemodel/test/cases/validations/numericality_validation_test.rb
+++ b/activemodel/test/cases/validations/numericality_validation_test.rb
@@ -59,7 +59,7 @@ class NumericalityValidationTest < ActiveModel::TestCase
end
def test_validates_numericality_of_with_integer_only_and_symbol_as_value
- Topic.validates_numericality_of :approved, only_integer: :condition_is_true_but_its_not
+ Topic.validates_numericality_of :approved, only_integer: :condition_is_false
invalid!(NIL + BLANK + JUNK)
valid!(FLOATS + INTEGERS + BIGDECIMAL + INFINITY)
diff --git a/activemodel/test/cases/validations/validates_test.rb b/activemodel/test/cases/validations/validates_test.rb
index 77cb8ebdc1..7f32f5dc74 100644
--- a/activemodel/test/cases/validations/validates_test.rb
+++ b/activemodel/test/cases/validations/validates_test.rb
@@ -62,17 +62,23 @@ class ValidatesTest < ActiveModel::TestCase
end
def test_validates_with_if_as_local_conditions
- Person.validates :karma, presence: true, email: { unless: :condition_is_true }
+ Person.validates :karma, presence: true, email: { if: :condition_is_false }
person = Person.new
person.valid?
assert_equal ["can't be blank"], person.errors[:karma]
end
def test_validates_with_if_as_shared_conditions
- Person.validates :karma, presence: true, email: true, if: :condition_is_true
+ Person.validates :karma, presence: true, email: true, if: :condition_is_false
+ person = Person.new
+ assert person.valid?
+ end
+
+ def test_validates_with_unless_as_local_conditions
+ Person.validates :karma, presence: true, email: { unless: :condition_is_true }
person = Person.new
person.valid?
- assert_equal ["can't be blank", "is not an email"], person.errors[:karma].sort
+ assert_equal ["can't be blank"], person.errors[:karma]
end
def test_validates_with_unless_shared_conditions
diff --git a/activemodel/test/models/person.rb b/activemodel/test/models/person.rb
index b61fdf76b1..8dd8ceadad 100644
--- a/activemodel/test/models/person.rb
+++ b/activemodel/test/models/person.rb
@@ -9,6 +9,10 @@ class Person
def condition_is_true
true
end
+
+ def condition_is_false
+ false
+ end
end
class Person::Gender
diff --git a/activemodel/test/models/topic.rb b/activemodel/test/models/topic.rb
index 2f4e92c3b2..b0af00ee45 100644
--- a/activemodel/test/models/topic.rb
+++ b/activemodel/test/models/topic.rb
@@ -23,7 +23,7 @@ class Topic
true
end
- def condition_is_true_but_its_not
+ def condition_is_false
false
end
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 4aa7ecfc7e..e6a41ec281 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,11 @@
+* Fix `bin/rails db:migrate` with specified `VERSION`.
+ `bin/rails db:migrate` with empty VERSION behaves as without `VERSION`.
+ Check a format of `VERSION`: Allow a migration version number
+ or name of a migration file. Raise error if format of `VERSION` is invalid.
+ Raise error if target migration doesn't exist.
+
+ *bogdanvlviv*
+
* Fixed a bug where column orders for an index weren't written to
db/schema.rb when using the sqlite adapter.
diff --git a/activerecord/lib/active_record/associations/preloader/association.rb b/activerecord/lib/active_record/associations/preloader/association.rb
index 607d376a08..e77761692d 100644
--- a/activerecord/lib/active_record/associations/preloader/association.rb
+++ b/activerecord/lib/active_record/associations/preloader/association.rb
@@ -17,8 +17,14 @@ module ActiveRecord
end
def run(preloader)
- associated_records_by_owner(preloader).each do |owner, records|
- associate_records_to_owner(owner, records)
+ records = load_records do |record|
+ owner = owners_by_key[convert_key(record[association_key_name])]
+ association = owner.association(reflection.name)
+ association.set_inverse_instance(record)
+ end
+
+ owners.each do |owner|
+ associate_records_to_owner(owner, records[convert_key(owner[owner_key_name])] || [])
end
end
@@ -33,18 +39,6 @@ module ActiveRecord
reflection.join_foreign_key
end
- def associated_records_by_owner(preloader)
- records = load_records do |record|
- owner = owners_by_key[convert_key(record[association_key_name])]
- association = owner.association(reflection.name)
- association.set_inverse_instance(record)
- end
-
- owners.each_with_object({}) do |owner, result|
- result[owner] = records[convert_key(owner[owner_key_name])] || []
- end
- end
-
def associate_records_to_owner(owner, records)
raise NotImplementedError
end
diff --git a/activerecord/lib/active_record/associations/preloader/has_many_through.rb b/activerecord/lib/active_record/associations/preloader/has_many_through.rb
index 0639fdca44..3e17d07a33 100644
--- a/activerecord/lib/active_record/associations/preloader/has_many_through.rb
+++ b/activerecord/lib/active_record/associations/preloader/has_many_through.rb
@@ -5,16 +5,6 @@ module ActiveRecord
class Preloader
class HasManyThrough < CollectionAssociation #:nodoc:
include ThroughAssociation
-
- def associated_records_by_owner(preloader)
- records_by_owner = super
-
- if reflection_scope.distinct_value
- records_by_owner.each_value(&:uniq!)
- end
-
- records_by_owner
- end
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 fa32cc5553..b1813ba66b 100644
--- a/activerecord/lib/active_record/associations/preloader/through_association.rb
+++ b/activerecord/lib/active_record/associations/preloader/through_association.rb
@@ -12,69 +12,46 @@ module ActiveRecord
reflection.source_reflection
end
- def associated_records_by_owner(preloader)
- through_scope = through_scope()
-
- preloader.preload(owners,
- through_reflection.name,
- through_scope)
-
- through_records = owners.map do |owner|
- center = owner.association(through_reflection.name).target
- [owner, Array(center)]
- end
-
- reset_association(owners, through_reflection.name, through_scope)
-
- middle_records = through_records.flat_map(&:last)
-
- reflection_scope = reflection_scope() if reflection.scope
-
- preloaders = preloader.preload(middle_records,
- source_reflection.name,
- reflection_scope)
-
+ def run(preloader)
+ already_loaded = owners.first.association(through_reflection.name).loaded?
+ through_scope = through_scope()
+ reflection_scope = target_reflection_scope
+ through_preloaders = preloader.preload(owners, through_reflection.name, through_scope)
+ middle_records = through_preloaders.flat_map(&:preloaded_records)
+ preloaders = preloader.preload(middle_records, source_reflection.name, reflection_scope)
@preloaded_records = preloaders.flat_map(&:preloaded_records)
- middle_to_pl = preloaders.each_with_object({}) do |pl, h|
- pl.owners.each { |middle|
- h[middle] = pl
- }
- end
-
- through_records.each_with_object({}) do |(lhs, center), records_by_owner|
- pl_to_middle = center.group_by { |record| middle_to_pl[record] }
-
- records_by_owner[lhs] = pl_to_middle.flat_map do |pl, middles|
- rhs_records = middles.flat_map { |r|
- r.association(source_reflection.name).target
- }.compact
-
- # Respect the order on `reflection_scope` if it exists, else use the natural order.
- 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
- rhs_records
+ owners.each do |owner|
+ through_records = Array(owner.association(through_reflection.name).target)
+ if already_loaded
+ if source_type = reflection.options[:source_type]
+ through_records = through_records.select do |record|
+ record[reflection.foreign_type] == source_type
+ end
end
+ else
+ owner.association(through_reflection.name).reset if through_scope
+ end
+ result = through_records.flat_map do |record|
+ association = record.association(source_reflection.name)
+ target = association.target
+ association.reset if preload_scope
+ target
+ end
+ result.compact!
+ if reflection_scope
+ result.sort_by! { |rhs| preload_index[rhs] } if reflection_scope.order_values.any?
+ result.uniq! if reflection_scope.distinct_value
end
+ associate_records_to_owner(owner, result)
end
end
private
- def id_to_index_map(ids)
- id_map = {}
- ids.each_with_index { |id, index| id_map[id] = index }
- id_map
- end
-
- 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|
- owner.association(association_name).reset
- }
+ def preload_index
+ @preload_index ||= @preloaded_records.each_with_object({}).with_index do |(id, result), index|
+ result[id] = index
end
end
@@ -115,6 +92,16 @@ module ActiveRecord
scope unless scope.empty_scope?
end
+
+ def target_reflection_scope
+ if preload_scope
+ reflection_scope.merge(preload_scope)
+ elsif reflection.scope
+ reflection_scope
+ else
+ nil
+ end
+ end
end
end
end
diff --git a/activerecord/lib/active_record/collection_cache_key.rb b/activerecord/lib/active_record/collection_cache_key.rb
index f3e6516414..88b398ad45 100644
--- a/activerecord/lib/active_record/collection_cache_key.rb
+++ b/activerecord/lib/active_record/collection_cache_key.rb
@@ -12,6 +12,9 @@ module ActiveRecord
timestamp = collection.max_by(&timestamp_column)._read_attribute(timestamp_column)
end
else
+ if collection.eager_loading?
+ collection = collection.send(:apply_join_dependency)
+ end
column_type = type_for_attribute(timestamp_column.to_s)
column = connection.column_name_from_arel_node(collection.arel_attribute(timestamp_column))
select_values = "COUNT(*) AS #{connection.quote_column_name("size")}, MAX(%s) AS timestamp"
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb
index 147e16e9fa..d9ac8db6a8 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb
@@ -240,7 +240,7 @@ module ActiveRecord
rollback_transaction if transaction
else
begin
- commit_transaction
+ commit_transaction if transaction
rescue Exception
rollback_transaction(transaction) unless transaction.state.completed?
raise
diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb
index 1485687053..d12a979a7f 100644
--- a/activerecord/lib/active_record/migration.rb
+++ b/activerecord/lib/active_record/migration.rb
@@ -1224,7 +1224,7 @@ module ActiveRecord
# Return true if a valid version is not provided.
def invalid_target?
- !target && @target_version && @target_version > 0
+ @target_version && @target_version != 0 && !target
end
def execute_migration_in_transaction(migration, direction)
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake
index 723272b4b2..3bca2982e0 100644
--- a/activerecord/lib/active_record/railties/databases.rake
+++ b/activerecord/lib/active_record/railties/databases.rake
@@ -97,16 +97,27 @@ db_namespace = namespace :db do
task up: [:environment, :load_config] do
raise "VERSION is required" if !ENV["VERSION"] || ENV["VERSION"].empty?
- version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
- ActiveRecord::Migrator.run(:up, ActiveRecord::Tasks::DatabaseTasks.migrations_paths, version)
+ ActiveRecord::Tasks::DatabaseTasks.check_target_version
+
+ ActiveRecord::Migrator.run(
+ :up,
+ ActiveRecord::Tasks::DatabaseTasks.migrations_paths,
+ ActiveRecord::Tasks::DatabaseTasks.target_version
+ )
db_namespace["_dump"].invoke
end
# desc 'Runs the "down" for a given migration VERSION.'
task down: [:environment, :load_config] do
raise "VERSION is required - To go down one migration, use db:rollback" if !ENV["VERSION"] || ENV["VERSION"].empty?
- version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
- ActiveRecord::Migrator.run(:down, ActiveRecord::Tasks::DatabaseTasks.migrations_paths, version)
+
+ ActiveRecord::Tasks::DatabaseTasks.check_target_version
+
+ ActiveRecord::Migrator.run(
+ :down,
+ ActiveRecord::Tasks::DatabaseTasks.migrations_paths,
+ ActiveRecord::Tasks::DatabaseTasks.target_version
+ )
db_namespace["_dump"].invoke
end
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 997cfe4b5e..7615fb6ee9 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -359,6 +359,11 @@ module ActiveRecord
def update_all(updates)
raise ArgumentError, "Empty list of attributes to change" if updates.blank?
+ if eager_loading?
+ relation = apply_join_dependency
+ return relation.update_all(updates)
+ end
+
stmt = Arel::UpdateManager.new
stmt.set Arel.sql(@klass.send(:sanitize_sql_for_assignment, updates))
@@ -423,6 +428,11 @@ module ActiveRecord
raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
end
+ if eager_loading?
+ relation = apply_join_dependency
+ return relation.delete_all
+ end
+
stmt = Arel::DeleteManager.new
stmt.from(table)
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index 116bddce85..11256ab3d9 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -130,7 +130,7 @@ module ActiveRecord
# end
def calculate(operation, column_name)
if has_include?(column_name)
- relation = apply_join_dependency(construct_join_dependency)
+ relation = apply_join_dependency
relation.distinct! if operation.to_s.downcase == "count"
relation.calculate(operation, column_name)
@@ -180,7 +180,7 @@ module ActiveRecord
end
if has_include?(column_names.first)
- relation = apply_join_dependency(construct_join_dependency)
+ relation = apply_join_dependency
relation.pluck(*column_names)
else
relation = spawn
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 707245bab2..18566b5662 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -394,7 +394,7 @@ module ActiveRecord
)
end
- def apply_join_dependency(join_dependency)
+ def apply_join_dependency(join_dependency = construct_join_dependency)
relation = except(:includes, :eager_load, :preload).joins!(join_dependency)
if using_limitable_reflections?(join_dependency.reflections)
diff --git a/activerecord/lib/active_record/scoping/named.rb b/activerecord/lib/active_record/scoping/named.rb
index 6fa096c1fe..310af72c41 100644
--- a/activerecord/lib/active_record/scoping/named.rb
+++ b/activerecord/lib/active_record/scoping/named.rb
@@ -24,8 +24,14 @@ module ActiveRecord
# You can define a scope that applies to all finders using
# {default_scope}[rdoc-ref:Scoping::Default::ClassMethods#default_scope].
def all
+ current_scope = self.current_scope
+
if current_scope
- current_scope.clone
+ if self == current_scope.klass
+ current_scope.clone
+ else
+ relation.merge!(current_scope)
+ end
else
default_scoped
end
diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb
index ff388ff1f6..4657e51e6d 100644
--- a/activerecord/lib/active_record/tasks/database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/database_tasks.rb
@@ -164,13 +164,12 @@ module ActiveRecord
end
def migrate
- raise "Empty VERSION provided" if ENV["VERSION"] && ENV["VERSION"].empty?
+ check_target_version
verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] != "false" : true
- version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
scope = ENV["SCOPE"]
verbose_was, Migration.verbose = Migration.verbose, verbose
- Migrator.migrate(migrations_paths, version) do |migration|
+ Migrator.migrate(migrations_paths, target_version) do |migration|
scope.blank? || scope == migration.scope
end
ActiveRecord::Base.clear_cache!
@@ -178,6 +177,16 @@ module ActiveRecord
Migration.verbose = verbose_was
end
+ def check_target_version
+ if target_version && !(Migration::MigrationFilenameRegexp.match?(ENV["VERSION"]) || /\A\d+\z/.match?(ENV["VERSION"]))
+ raise "Invalid format of target version: `VERSION=#{ENV['VERSION']}`"
+ end
+ end
+
+ def target_version
+ ENV["VERSION"].to_i if ENV["VERSION"] && !ENV["VERSION"].empty?
+ end
+
def charset_current(environment = env)
charset ActiveRecord::Base.configurations[environment]
end
diff --git a/activerecord/test/cases/associations/nested_through_associations_test.rb b/activerecord/test/cases/associations/nested_through_associations_test.rb
index 4cf5a9ffc4..65d30d011b 100644
--- a/activerecord/test/cases/associations/nested_through_associations_test.rb
+++ b/activerecord/test/cases/associations/nested_through_associations_test.rb
@@ -579,6 +579,28 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase
assert !c.post_taggings.empty?
end
+ def test_polymorphic_has_many_through_when_through_association_has_not_loaded
+ cake_designer = CakeDesigner.create!(chef: Chef.new)
+ drink_designer = DrinkDesigner.create!(chef: Chef.new)
+ department = Department.create!(chefs: [cake_designer.chef, drink_designer.chef])
+ Hotel.create!(departments: [department])
+ hotel = Hotel.includes(:cake_designers, :drink_designers).take
+
+ assert_equal [cake_designer], hotel.cake_designers
+ assert_equal [drink_designer], hotel.drink_designers
+ end
+
+ def test_polymorphic_has_many_through_when_through_association_has_already_loaded
+ cake_designer = CakeDesigner.create!(chef: Chef.new)
+ drink_designer = DrinkDesigner.create!(chef: Chef.new)
+ department = Department.create!(chefs: [cake_designer.chef, drink_designer.chef])
+ Hotel.create!(departments: [department])
+ hotel = Hotel.includes(:chefs, :cake_designers, :drink_designers).take
+
+ assert_equal [cake_designer], hotel.cake_designers
+ assert_equal [drink_designer], hotel.drink_designers
+ end
+
def test_polymorphic_has_many_through_joined_different_table_twice
cake_designer = CakeDesigner.create!(chef: Chef.new)
drink_designer = DrinkDesigner.create!(chef: Chef.new)
diff --git a/activerecord/test/cases/collection_cache_key_test.rb b/activerecord/test/cases/collection_cache_key_test.rb
index c137693211..19d6464a22 100644
--- a/activerecord/test/cases/collection_cache_key_test.rb
+++ b/activerecord/test/cases/collection_cache_key_test.rb
@@ -73,6 +73,16 @@ module ActiveRecord
assert_equal last_developer_timestamp.to_s(ActiveRecord::Base.cache_timestamp_format), $3
end
+ test "cache_key for relation with includes" do
+ comments = Comment.includes(:post).where("posts.type": "Post")
+ assert_match(/\Acomments\/query-(\h+)-(\d+)-(\d+)\z/, comments.cache_key)
+ end
+
+ test "cache_key for loaded relation with includes" do
+ comments = Comment.includes(:post).where("posts.type": "Post").load
+ assert_match(/\Acomments\/query-(\h+)-(\d+)-(\d+)\z/, comments.cache_key)
+ end
+
test "it triggers at most one query" do
developers = Developer.where(name: "David")
diff --git a/activerecord/test/cases/migrator_test.rb b/activerecord/test/cases/migrator_test.rb
index ee10be119c..1047ba1367 100644
--- a/activerecord/test/cases/migrator_test.rb
+++ b/activerecord/test/cases/migrator_test.rb
@@ -66,6 +66,26 @@ class MigratorTest < ActiveRecord::TestCase
list = [ActiveRecord::Migration.new("Foo", 1), ActiveRecord::Migration.new("Bar", 2)]
ActiveRecord::Migrator.new(:up, list, 3).run
end
+
+ assert_raises(ActiveRecord::UnknownMigrationVersionError) do
+ list = [ActiveRecord::Migration.new("Foo", 1), ActiveRecord::Migration.new("Bar", 2)]
+ ActiveRecord::Migrator.new(:up, list, -1).run
+ end
+
+ assert_raises(ActiveRecord::UnknownMigrationVersionError) do
+ list = [ActiveRecord::Migration.new("Foo", 1), ActiveRecord::Migration.new("Bar", 2)]
+ ActiveRecord::Migrator.new(:up, list, 0).run
+ end
+
+ assert_raises(ActiveRecord::UnknownMigrationVersionError) do
+ list = [ActiveRecord::Migration.new("Foo", 1), ActiveRecord::Migration.new("Bar", 2)]
+ ActiveRecord::Migrator.new(:up, list, 3).migrate
+ end
+
+ assert_raises(ActiveRecord::UnknownMigrationVersionError) do
+ list = [ActiveRecord::Migration.new("Foo", 1), ActiveRecord::Migration.new("Bar", 2)]
+ ActiveRecord::Migrator.new(:up, list, -1).migrate
+ end
end
def test_finds_migrations
diff --git a/activerecord/test/cases/persistence_test.rb b/activerecord/test/cases/persistence_test.rb
index 6cbe18cc8c..f088c064f5 100644
--- a/activerecord/test/cases/persistence_test.rb
+++ b/activerecord/test/cases/persistence_test.rb
@@ -94,27 +94,31 @@ class PersistenceTest < ActiveRecord::TestCase
end
def test_delete_all_with_joins_and_where_part_is_hash
- where_args = { toys: { name: "Bone" } }
- count = Pet.joins(:toys).where(where_args).count
+ pets = Pet.joins(:toys).where(toys: { name: "Bone" })
- assert_equal count, 1
- assert_equal count, Pet.joins(:toys).where(where_args).delete_all
+ assert_equal true, pets.exists?
+ assert_equal pets.count, pets.delete_all
+ end
+
+ def test_delete_all_with_joins_and_where_part_is_not_hash
+ pets = Pet.joins(:toys).where("toys.name = ?", "Bone")
+
+ assert_equal true, pets.exists?
+ assert_equal pets.count, pets.delete_all
end
def test_delete_all_with_left_joins
- where_args = { toys: { name: "Bone" } }
- count = Pet.left_joins(:toys).where(where_args).count
+ pets = Pet.left_joins(:toys).where(toys: { name: "Bone" })
- assert_equal count, 1
- assert_equal count, Pet.left_joins(:toys).where(where_args).delete_all
+ assert_equal true, pets.exists?
+ assert_equal pets.count, pets.delete_all
end
- def test_delete_all_with_joins_and_where_part_is_not_hash
- where_args = ["toys.name = ?", "Bone"]
- count = Pet.joins(:toys).where(where_args).count
+ def test_delete_all_with_includes
+ pets = Pet.includes(:toys).where(toys: { name: "Bone" })
- assert_equal count, 1
- assert_equal count, Pet.joins(:toys).where(where_args).delete_all
+ assert_equal true, pets.exists?
+ assert_equal pets.count, pets.delete_all
end
def test_increment_attribute
@@ -496,17 +500,24 @@ class PersistenceTest < ActiveRecord::TestCase
end
def test_update_all_with_joins
- where_args = { toys: { name: "Bone" } }
- count = Pet.left_joins(:toys).where(where_args).count
+ pets = Pet.joins(:toys).where(toys: { name: "Bone" })
- assert_equal count, Pet.joins(:toys).where(where_args).update_all(name: "Bob")
+ assert_equal true, pets.exists?
+ assert_equal pets.count, pets.update_all(name: "Bob")
end
def test_update_all_with_left_joins
- where_args = { toys: { name: "Bone" } }
- count = Pet.left_joins(:toys).where(where_args).count
+ pets = Pet.left_joins(:toys).where(toys: { name: "Bone" })
+
+ assert_equal true, pets.exists?
+ assert_equal pets.count, pets.update_all(name: "Bob")
+ end
+
+ def test_update_all_with_includes
+ pets = Pet.includes(:toys).where(toys: { name: "Bone" })
- assert_equal count, Pet.left_joins(:toys).where(where_args).update_all(name: "Bob")
+ assert_equal true, pets.exists?
+ assert_equal pets.count, pets.update_all(name: "Bob")
end
def test_update_all_with_non_standard_table_name
diff --git a/activerecord/test/cases/scoping/relation_scoping_test.rb b/activerecord/test/cases/scoping/relation_scoping_test.rb
index f3b84d88c2..116f8e83aa 100644
--- a/activerecord/test/cases/scoping/relation_scoping_test.rb
+++ b/activerecord/test/cases/scoping/relation_scoping_test.rb
@@ -240,6 +240,20 @@ class RelationScopingTest < ActiveRecord::TestCase
assert_nil SpecialComment.current_scope
end
+ def test_scoping_respects_current_class
+ Comment.unscoped do
+ assert_equal "a comment...", Comment.all.what_are_you
+ assert_equal "a special comment...", SpecialComment.all.what_are_you
+ end
+ end
+
+ def test_scoping_respects_sti_constraint
+ Comment.unscoped do
+ assert_equal comments(:greetings), Comment.find(1)
+ assert_raises(ActiveRecord::RecordNotFound) { SpecialComment.find(1) }
+ end
+ end
+
def test_circular_joins_with_scoping_does_not_crash
posts = Post.joins(comments: :post).scoping do
Post.first(10)
diff --git a/activerecord/test/cases/tasks/database_tasks_test.rb b/activerecord/test/cases/tasks/database_tasks_test.rb
index 1495d2ab89..5a094ead42 100644
--- a/activerecord/test/cases/tasks/database_tasks_test.rb
+++ b/activerecord/test/cases/tasks/database_tasks_test.rb
@@ -357,8 +357,15 @@ module ActiveRecord
ActiveRecord::Migration.expects(:verbose=).with(ActiveRecord::Migration.verbose)
ActiveRecord::Tasks::DatabaseTasks.migrate
+ ENV["VERBOSE"] = ""
+ ENV["VERSION"] = ""
+ ActiveRecord::Migrator.expects(:migrate).with("custom/path", nil)
+ ActiveRecord::Migration.expects(:verbose=).with(true)
+ ActiveRecord::Migration.expects(:verbose=).with(ActiveRecord::Migration.verbose)
+ ActiveRecord::Tasks::DatabaseTasks.migrate
+
ENV["VERBOSE"] = "yes"
- ENV["VERSION"] = "unknown"
+ ENV["VERSION"] = "0"
ActiveRecord::Migrator.expects(:migrate).with("custom/path", 0)
ActiveRecord::Migration.expects(:verbose=).with(true)
ActiveRecord::Migration.expects(:verbose=).with(ActiveRecord::Migration.verbose)
@@ -367,15 +374,47 @@ module ActiveRecord
ENV["VERBOSE"], ENV["VERSION"] = verbose, version
end
- def test_migrate_raise_error_on_empty_version
+ def test_migrate_raise_error_on_invalid_version_format
version = ENV["VERSION"]
- ENV["VERSION"] = ""
+
+ ENV["VERSION"] = "unknown"
+ e = assert_raise(RuntimeError) { ActiveRecord::Tasks::DatabaseTasks.migrate }
+ assert_match(/Invalid format of target version/, e.message)
+
+ ENV["VERSION"] = "0.1.11"
+ e = assert_raise(RuntimeError) { ActiveRecord::Tasks::DatabaseTasks.migrate }
+ assert_match(/Invalid format of target version/, e.message)
+
+ ENV["VERSION"] = "1.1.11"
+ e = assert_raise(RuntimeError) { ActiveRecord::Tasks::DatabaseTasks.migrate }
+ assert_match(/Invalid format of target version/, e.message)
+
+ ENV["VERSION"] = "0 "
+ e = assert_raise(RuntimeError) { ActiveRecord::Tasks::DatabaseTasks.migrate }
+ assert_match(/Invalid format of target version/, e.message)
+
+ ENV["VERSION"] = "1."
+ e = assert_raise(RuntimeError) { ActiveRecord::Tasks::DatabaseTasks.migrate }
+ assert_match(/Invalid format of target version/, e.message)
+
+ ENV["VERSION"] = "1_"
e = assert_raise(RuntimeError) { ActiveRecord::Tasks::DatabaseTasks.migrate }
- assert_equal "Empty VERSION provided", e.message
+ assert_match(/Invalid format of target version/, e.message)
+
+ ENV["VERSION"] = "1_name"
+ e = assert_raise(RuntimeError) { ActiveRecord::Tasks::DatabaseTasks.migrate }
+ assert_match(/Invalid format of target version/, e.message)
ensure
ENV["VERSION"] = version
end
+ def test_migrate_raise_error_on_failed_check_target_version
+ ActiveRecord::Tasks::DatabaseTasks.stubs(:check_target_version).raises("foo")
+
+ e = assert_raise(RuntimeError) { ActiveRecord::Tasks::DatabaseTasks.migrate }
+ assert_equal "foo", e.message
+ end
+
def test_migrate_clears_schema_cache_afterward
ActiveRecord::Base.expects(:clear_cache!)
ActiveRecord::Tasks::DatabaseTasks.migrate
@@ -444,6 +483,108 @@ module ActiveRecord
end
end
+ class DatabaseTaskTargetVersionTest < ActiveRecord::TestCase
+ def test_target_version_returns_nil_if_version_does_not_exist
+ version = ENV.delete("VERSION")
+ assert_nil ActiveRecord::Tasks::DatabaseTasks.target_version
+ ensure
+ ENV["VERSION"] = version
+ end
+
+ def test_target_version_returns_nil_if_version_is_empty
+ version = ENV["VERSION"]
+
+ ENV["VERSION"] = ""
+ assert_nil ActiveRecord::Tasks::DatabaseTasks.target_version
+ ensure
+ ENV["VERSION"] = version
+ end
+
+ def test_target_version_returns_converted_to_integer_env_version_if_version_exists
+ version = ENV["VERSION"]
+
+ ENV["VERSION"] = "0"
+ assert_equal ENV["VERSION"].to_i, ActiveRecord::Tasks::DatabaseTasks.target_version
+
+ ENV["VERSION"] = "42"
+ assert_equal ENV["VERSION"].to_i, ActiveRecord::Tasks::DatabaseTasks.target_version
+
+ ENV["VERSION"] = "042"
+ assert_equal ENV["VERSION"].to_i, ActiveRecord::Tasks::DatabaseTasks.target_version
+ ensure
+ ENV["VERSION"] = version
+ end
+ end
+
+ class DatabaseTaskCheckTargetVersionTest < ActiveRecord::TestCase
+ def test_check_target_version_does_not_raise_error_on_empty_version
+ version = ENV["VERSION"]
+ ENV["VERSION"] = ""
+ assert_nothing_raised { ActiveRecord::Tasks::DatabaseTasks.check_target_version }
+ ensure
+ ENV["VERSION"] = version
+ end
+
+ def test_check_target_version_does_not_raise_error_if_version_is_not_setted
+ version = ENV.delete("VERSION")
+ assert_nothing_raised { ActiveRecord::Tasks::DatabaseTasks.check_target_version }
+ ensure
+ ENV["VERSION"] = version
+ end
+
+ def test_check_target_version_raises_error_on_invalid_version_format
+ version = ENV["VERSION"]
+
+ ENV["VERSION"] = "unknown"
+ e = assert_raise(RuntimeError) { ActiveRecord::Tasks::DatabaseTasks.check_target_version }
+ assert_match(/Invalid format of target version/, e.message)
+
+ ENV["VERSION"] = "0.1.11"
+ e = assert_raise(RuntimeError) { ActiveRecord::Tasks::DatabaseTasks.check_target_version }
+ assert_match(/Invalid format of target version/, e.message)
+
+ ENV["VERSION"] = "1.1.11"
+ e = assert_raise(RuntimeError) { ActiveRecord::Tasks::DatabaseTasks.check_target_version }
+ assert_match(/Invalid format of target version/, e.message)
+
+ ENV["VERSION"] = "0 "
+ e = assert_raise(RuntimeError) { ActiveRecord::Tasks::DatabaseTasks.check_target_version }
+ assert_match(/Invalid format of target version/, e.message)
+
+ ENV["VERSION"] = "1."
+ e = assert_raise(RuntimeError) { ActiveRecord::Tasks::DatabaseTasks.check_target_version }
+ assert_match(/Invalid format of target version/, e.message)
+
+ ENV["VERSION"] = "1_"
+ e = assert_raise(RuntimeError) { ActiveRecord::Tasks::DatabaseTasks.check_target_version }
+ assert_match(/Invalid format of target version/, e.message)
+
+ ENV["VERSION"] = "1_name"
+ e = assert_raise(RuntimeError) { ActiveRecord::Tasks::DatabaseTasks.check_target_version }
+ assert_match(/Invalid format of target version/, e.message)
+ ensure
+ ENV["VERSION"] = version
+ end
+
+ def test_check_target_version_does_not_raise_error_on_valid_version_format
+ version = ENV["VERSION"]
+
+ ENV["VERSION"] = "0"
+ assert_nothing_raised { ActiveRecord::Tasks::DatabaseTasks.check_target_version }
+
+ ENV["VERSION"] = "1"
+ assert_nothing_raised { ActiveRecord::Tasks::DatabaseTasks.check_target_version }
+
+ ENV["VERSION"] = "001"
+ assert_nothing_raised { ActiveRecord::Tasks::DatabaseTasks.check_target_version }
+
+ ENV["VERSION"] = "001_name.rb"
+ assert_nothing_raised { ActiveRecord::Tasks::DatabaseTasks.check_target_version }
+ ensure
+ ENV["VERSION"] = version
+ end
+ end
+
class DatabaseTasksStructureDumpTest < ActiveRecord::TestCase
include DatabaseTasksSetupper
diff --git a/activerecord/test/models/comment.rb b/activerecord/test/models/comment.rb
index 740aa593ac..5ab433f2d9 100644
--- a/activerecord/test/models/comment.rb
+++ b/activerecord/test/models/comment.rb
@@ -60,6 +60,10 @@ end
class SpecialComment < Comment
default_scope { where(deleted_at: nil) }
+
+ def self.what_are_you
+ "a special comment..."
+ end
end
class SubSpecialComment < SpecialComment
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 8f872c38ba..a4505a4892 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -191,6 +191,7 @@ ActiveRecord::Schema.define do
t.string :resource_id
t.string :resource_type
t.integer :developer_id
+ t.datetime :updated_at
t.datetime :deleted_at
t.integer :comments
end
diff --git a/activestorage/lib/active_storage/service/azure_storage_service.rb b/activestorage/lib/active_storage/service/azure_storage_service.rb
index 27dd192ce6..f3877ad9c9 100644
--- a/activestorage/lib/active_storage/service/azure_storage_service.rb
+++ b/activestorage/lib/active_storage/service/azure_storage_service.rb
@@ -28,7 +28,7 @@ module ActiveStorage
end
end
- def download(key)
+ def download(key, &block)
if block_given?
instrument :streaming_download, key do
stream(key, &block)
@@ -108,15 +108,15 @@ module ActiveStorage
end
# Reads the object for the given key in chunks, yielding each to the block.
- def stream(key, options = {}, &block)
+ def stream(key)
blob = blob_for(key)
chunk_size = 5.megabytes
offset = 0
while offset < blob.properties[:content_length]
- _, io = blobs.get_blob(container, key, start_range: offset, end_range: offset + chunk_size - 1)
- yield io
+ _, chunk = blobs.get_blob(container, key, start_range: offset, end_range: offset + chunk_size - 1)
+ yield chunk.force_encoding(Encoding::BINARY)
offset += chunk_size
end
end
diff --git a/activestorage/lib/active_storage/service/s3_service.rb b/activestorage/lib/active_storage/service/s3_service.rb
index 3e93cdd072..958b172efb 100644
--- a/activestorage/lib/active_storage/service/s3_service.rb
+++ b/activestorage/lib/active_storage/service/s3_service.rb
@@ -26,7 +26,7 @@ module ActiveStorage
end
end
- def download(key)
+ def download(key, &block)
if block_given?
instrument :streaming_download, key do
stream(key, &block)
@@ -85,14 +85,14 @@ module ActiveStorage
end
# Reads the object for the given key in chunks, yielding each to the block.
- def stream(key, options = {}, &block)
+ def stream(key, &block)
object = object_for(key)
chunk_size = 5.megabytes
offset = 0
while offset < object.content_length
- yield object.read(options.merge(range: "bytes=#{offset}-#{offset + chunk_size - 1}"))
+ yield object.get(range: "bytes=#{offset}-#{offset + chunk_size - 1}").body.read.force_encoding(Encoding::BINARY)
offset += chunk_size
end
end
diff --git a/activestorage/test/service/shared_service_tests.rb b/activestorage/test/service/shared_service_tests.rb
index a9e1cb6ce9..ade91ab89a 100644
--- a/activestorage/test/service/shared_service_tests.rb
+++ b/activestorage/test/service/shared_service_tests.rb
@@ -50,6 +50,16 @@ module ActiveStorage::Service::SharedServiceTests
assert_equal FIXTURE_DATA, @service.download(FIXTURE_KEY)
end
+ test "downloading in chunks" do
+ chunks = []
+
+ @service.download(FIXTURE_KEY) do |chunk|
+ chunks << chunk
+ end
+
+ assert_equal [ FIXTURE_DATA ], chunks
+ end
+
test "existing" do
assert @service.exist?(FIXTURE_KEY)
assert_not @service.exist?(FIXTURE_KEY + "nonsense")
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 8e8e9b9440..9c27c68919 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,3 +1,95 @@
+* Fix acronym support in `humanize`
+
+ Acronym inflections are stored with lowercase keys in the hash but
+ the match wasn't being lowercased before being looked up in the hash.
+ This shouldn't have any performance impact because before it would
+ fail to find the acronym and perform the `downcase` operation anyway.
+
+ Fixes #31052.
+
+ *Andrew White*
+
+* Add same method signature for `Time#prev_year` and `Time#next_year`
+ in accordance with `Date#prev_year`, `Date#next_year`.
+
+ Allows pass argument for `Time#prev_year` and `Time#next_year`.
+
+ Before:
+ ```
+ Time.new(2017, 9, 16, 17, 0).prev_year # => 2016-09-16 17:00:00 +0300
+ Time.new(2017, 9, 16, 17, 0).prev_year(1)
+ # => ArgumentError: wrong number of arguments (given 1, expected 0)
+
+ Time.new(2017, 9, 16, 17, 0).next_year # => 2018-09-16 17:00:00 +0300
+ Time.new(2017, 9, 16, 17, 0).next_year(1)
+ # => ArgumentError: wrong number of arguments (given 1, expected 0)
+ ```
+
+ After:
+ ```
+ Time.new(2017, 9, 16, 17, 0).prev_year # => 2016-09-16 17:00:00 +0300
+ Time.new(2017, 9, 16, 17, 0).prev_year(1) # => 2016-09-16 17:00:00 +0300
+
+ Time.new(2017, 9, 16, 17, 0).next_year # => 2018-09-16 17:00:00 +0300
+ Time.new(2017, 9, 16, 17, 0).next_year(1) # => 2018-09-16 17:00:00 +0300
+ ```
+
+ *bogdanvlviv*
+
+* Add same method signature for `Time#prev_month` and `Time#next_month`
+ in accordance with `Date#prev_month`, `Date#next_month`.
+
+ Allows pass argument for `Time#prev_month` and `Time#next_month`.
+
+ Before:
+ ```
+ Time.new(2017, 9, 16, 17, 0).prev_month # => 2017-08-16 17:00:00 +0300
+ Time.new(2017, 9, 16, 17, 0).prev_month(1)
+ # => ArgumentError: wrong number of arguments (given 1, expected 0)
+
+ Time.new(2017, 9, 16, 17, 0).next_month # => 2017-10-16 17:00:00 +0300
+ Time.new(2017, 9, 16, 17, 0).next_month(1)
+ # => ArgumentError: wrong number of arguments (given 1, expected 0)
+ ```
+
+ After:
+ ```
+ Time.new(2017, 9, 16, 17, 0).prev_month # => 2017-08-16 17:00:00 +0300
+ Time.new(2017, 9, 16, 17, 0).prev_month(1) # => 2017-08-16 17:00:00 +0300
+
+ Time.new(2017, 9, 16, 17, 0).next_month # => 2017-10-16 17:00:00 +0300
+ Time.new(2017, 9, 16, 17, 0).next_month(1) # => 2017-10-16 17:00:00 +0300
+ ```
+
+ *bogdanvlviv*
+
+* Add same method signature for `Time#prev_day` and `Time#next_day`
+ in accordance with `Date#prev_day`, `Date#next_day`.
+
+ Allows pass argument for `Time#prev_day` and `Time#next_day`.
+
+ Before:
+ ```
+ Time.new(2017, 9, 16, 17, 0).prev_day # => 2017-09-15 17:00:00 +0300
+ Time.new(2017, 9, 16, 17, 0).prev_day(1)
+ # => ArgumentError: wrong number of arguments (given 1, expected 0)
+
+ Time.new(2017, 9, 16, 17, 0).next_day # => 2017-09-17 17:00:00 +0300
+ Time.new(2017, 9, 16, 17, 0).next_day(1)
+ # => ArgumentError: wrong number of arguments (given 1, expected 0)
+ ```
+
+ After:
+ ```
+ Time.new(2017, 9, 16, 17, 0).prev_day # => 2017-09-15 17:00:00 +0300
+ Time.new(2017, 9, 16, 17, 0).prev_day(1) # => 2017-09-15 17:00:00 +0300
+
+ Time.new(2017, 9, 16, 17, 0).next_day # => 2017-09-17 17:00:00 +0300
+ Time.new(2017, 9, 16, 17, 0).next_day(1) # => 2017-09-17 17:00:00 +0300
+ ```
+
+ *bogdanvlviv*
+
* `IO#to_json` now returns the `to_s` representation, rather than
attempting to convert to an array. This fixes a bug where `IO#to_json`
would raise an `IOError` when called on an unreadable object.
diff --git a/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb b/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb
index 265c6949e1..061b79e098 100644
--- a/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb
@@ -20,9 +20,9 @@ module DateAndTime
advance(days: -1)
end
- # Returns a new date/time representing the previous day.
- def prev_day
- advance(days: -1)
+ # Returns a new date/time the specified number of days ago.
+ def prev_day(days = 1)
+ advance(days: -days)
end
# Returns a new date/time representing tomorrow.
@@ -30,9 +30,9 @@ module DateAndTime
advance(days: 1)
end
- # Returns a new date/time representing the next day.
- def next_day
- advance(days: 1)
+ # Returns a new date/time the specified number of days in the future.
+ def next_day(days = 1)
+ advance(days: days)
end
# Returns true if the date/time is today.
@@ -188,9 +188,9 @@ module DateAndTime
end
end
- # Short-hand for months_since(1).
- def next_month
- months_since(1)
+ # Returns a new date/time the specified number of months in the future.
+ def next_month(months = 1)
+ advance(months: months)
end
# Short-hand for months_since(3)
@@ -198,9 +198,9 @@ module DateAndTime
months_since(3)
end
- # Short-hand for years_since(1).
- def next_year
- years_since(1)
+ # Returns a new date/time the specified number of years in the future.
+ def next_year(years = 1)
+ advance(years: years)
end
# Returns a new date/time representing the given day in the previous week.
@@ -223,11 +223,15 @@ module DateAndTime
end
alias_method :last_weekday, :prev_weekday
+ # Returns a new date/time the specified number of months ago.
+ def prev_month(months = 1)
+ advance(months: -months)
+ end
+
# Short-hand for months_ago(1).
- def prev_month
+ def last_month
months_ago(1)
end
- alias_method :last_month, :prev_month
# Short-hand for months_ago(3).
def prev_quarter
@@ -235,11 +239,15 @@ module DateAndTime
end
alias_method :last_quarter, :prev_quarter
+ # Returns a new date/time the specified number of years ago.
+ def prev_year(years = 1)
+ advance(years: -years)
+ end
+
# Short-hand for years_ago(1).
- def prev_year
+ def last_year
years_ago(1)
end
- alias_method :last_year, :prev_year
# Returns the number of days to the start of the week on the given day.
# Week is assumed to start on +start_day+, default is
diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb
index 72de42b1c3..3357b5eb32 100644
--- a/activesupport/lib/active_support/inflector/methods.rb
+++ b/activesupport/lib/active_support/inflector/methods.rb
@@ -138,7 +138,7 @@ module ActiveSupport
result.tr!("_".freeze, " ".freeze)
result.gsub!(/([a-z\d]*)/i) do |match|
- "#{inflections.acronyms[match] || match.downcase}"
+ "#{inflections.acronyms[match.downcase] || match.downcase}"
end
if capitalize
diff --git a/activesupport/lib/active_support/inflector/transliterate.rb b/activesupport/lib/active_support/inflector/transliterate.rb
index 9801f1d118..9fb3a2e0af 100644
--- a/activesupport/lib/active_support/inflector/transliterate.rb
+++ b/activesupport/lib/active_support/inflector/transliterate.rb
@@ -71,17 +71,23 @@ module ActiveSupport
# a 'pretty' URL.
#
# parameterize("Donald E. Knuth") # => "donald-e-knuth"
- # parameterize("^trés|Jolie-- ") # => "tres-jolie"
+ # parameterize("^très|Jolie-- ") # => "tres-jolie"
#
# To use a custom separator, override the `separator` argument.
#
# parameterize("Donald E. Knuth", separator: '_') # => "donald_e_knuth"
- # parameterize("^trés|Jolie-- ", separator: '_') # => "tres_jolie"
+ # parameterize("^très|Jolie__ ", separator: '_') # => "tres_jolie"
#
# To preserve the case of the characters in a string, use the `preserve_case` argument.
#
# parameterize("Donald E. Knuth", preserve_case: true) # => "Donald-E-Knuth"
- # parameterize("^trés|Jolie-- ", preserve_case: true) # => "tres-Jolie"
+ # parameterize("^très|Jolie-- ", preserve_case: true) # => "tres-Jolie"
+ #
+ # It preserves dashes and underscores unless they are used as separators:
+ #
+ # parameterize("^très|Jolie__ ") # => "tres-jolie__"
+ # parameterize("^très|Jolie-- ", separator: "_") # => "tres_jolie--"
+ # parameterize("^très_Jolie-- ", separator: ".") # => "tres_jolie--"
#
def parameterize(string, separator: "-", preserve_case: false)
# Replace accented chars with their ASCII equivalents.
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 b7ad76bb62..eb528a0583 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,14 +37,6 @@ module ActiveSupport
private
- def calculate_rounded_number(multiplier)
- (number / BigDecimal.new(multiplier.to_f.to_s)).round * multiplier
- end
-
- def digit_count(number)
- number.zero? ? 1 : (Math.log10(absolute_number(number)) + 1).floor
- end
-
def strip_insignificant_zeros
options[:strip_insignificant_zeros]
end
diff --git a/activesupport/lib/active_support/testing/assertions.rb b/activesupport/lib/active_support/testing/assertions.rb
index e2bc51ff7a..46eed73d24 100644
--- a/activesupport/lib/active_support/testing/assertions.rb
+++ b/activesupport/lib/active_support/testing/assertions.rb
@@ -190,7 +190,12 @@ module ActiveSupport
error = "#{expression.inspect} did change to #{after}"
error = "#{message}.\n#{error}" if message
- assert_equal before, after, error
+
+ if before.nil?
+ assert_nil after, error
+ else
+ assert_equal before, after, error
+ end
retval
end
diff --git a/activesupport/test/core_ext/date_and_time_behavior.rb b/activesupport/test/core_ext/date_and_time_behavior.rb
index 256353c309..42da6f6cd0 100644
--- a/activesupport/test/core_ext/date_and_time_behavior.rb
+++ b/activesupport/test/core_ext/date_and_time_behavior.rb
@@ -9,6 +9,11 @@ module DateAndTimeBehavior
end
def test_prev_day
+ assert_equal date_time_init(2005, 2, 24, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_day(-2)
+ assert_equal date_time_init(2005, 2, 23, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_day(-1)
+ assert_equal date_time_init(2005, 2, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_day(0)
+ assert_equal date_time_init(2005, 2, 21, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_day(1)
+ assert_equal date_time_init(2005, 2, 20, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_day(2)
assert_equal date_time_init(2005, 2, 21, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_day
assert_equal date_time_init(2005, 2, 28, 10, 10, 10), date_time_init(2005, 3, 2, 10, 10, 10).prev_day.prev_day
end
@@ -19,6 +24,11 @@ module DateAndTimeBehavior
end
def test_next_day
+ assert_equal date_time_init(2005, 2, 20, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_day(-2)
+ assert_equal date_time_init(2005, 2, 21, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_day(-1)
+ assert_equal date_time_init(2005, 2, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_day(0)
+ assert_equal date_time_init(2005, 2, 23, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_day(1)
+ assert_equal date_time_init(2005, 2, 24, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_day(2)
assert_equal date_time_init(2005, 2, 23, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_day
assert_equal date_time_init(2005, 3, 2, 10, 10, 10), date_time_init(2005, 2, 28, 10, 10, 10).next_day.next_day
end
@@ -151,6 +161,16 @@ module DateAndTimeBehavior
assert_equal date_time_init(2015, 1, 5, 15, 15, 10), date_time_init(2015, 1, 3, 15, 15, 10).next_weekday
end
+ def test_next_month
+ assert_equal date_time_init(2004, 12, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month(-2)
+ assert_equal date_time_init(2005, 1, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month(-1)
+ assert_equal date_time_init(2005, 2, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month(0)
+ assert_equal date_time_init(2005, 3, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month(1)
+ assert_equal date_time_init(2005, 4, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month(2)
+ assert_equal date_time_init(2005, 3, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month
+ assert_equal date_time_init(2005, 4, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month.next_month
+ end
+
def test_next_month_on_31st
assert_equal date_time_init(2005, 9, 30, 15, 15, 10), date_time_init(2005, 8, 31, 15, 15, 10).next_month
end
@@ -160,7 +180,13 @@ module DateAndTimeBehavior
end
def test_next_year
+ assert_equal date_time_init(2003, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year(-2)
+ assert_equal date_time_init(2004, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year(-1)
+ assert_equal date_time_init(2005, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year(0)
+ assert_equal date_time_init(2006, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year(1)
+ assert_equal date_time_init(2007, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year(2)
assert_equal date_time_init(2006, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year
+ assert_equal date_time_init(2007, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year.next_year
end
def test_prev_week
@@ -203,6 +229,16 @@ module DateAndTimeBehavior
assert_equal date_time_init(2015, 1, 2, 15, 15, 10), date_time_init(2015, 1, 4, 15, 15, 10).prev_weekday
end
+ def test_prev_month
+ assert_equal date_time_init(2005, 4, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month(-2)
+ assert_equal date_time_init(2005, 3, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month(-1)
+ assert_equal date_time_init(2005, 2, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month(0)
+ assert_equal date_time_init(2005, 1, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month(1)
+ assert_equal date_time_init(2004, 12, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month(2)
+ assert_equal date_time_init(2005, 1, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month
+ assert_equal date_time_init(2004, 12, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month.prev_month
+ end
+
def test_prev_month_on_31st
assert_equal date_time_init(2004, 2, 29, 10, 10, 10), date_time_init(2004, 3, 31, 10, 10, 10).prev_month
end
@@ -212,7 +248,21 @@ module DateAndTimeBehavior
end
def test_prev_year
+ assert_equal date_time_init(2007, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year(-2)
+ assert_equal date_time_init(2006, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year(-1)
+ assert_equal date_time_init(2005, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year(0)
+ assert_equal date_time_init(2004, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year(1)
+ assert_equal date_time_init(2003, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year(2)
assert_equal date_time_init(2004, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year
+ assert_equal date_time_init(2003, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year.prev_year
+ end
+
+ def test_last_month_on_31st
+ assert_equal date_time_init(2004, 2, 29, 0, 0, 0), date_time_init(2004, 3, 31, 0, 0, 0).last_month
+ end
+
+ def test_last_year
+ assert_equal date_time_init(2004, 6, 5, 10, 0, 0), date_time_init(2005, 6, 5, 10, 0, 0).last_year
end
def test_days_to_week_start
diff --git a/activesupport/test/core_ext/date_ext_test.rb b/activesupport/test/core_ext/date_ext_test.rb
index b8672eac4b..0c6f3f595a 100644
--- a/activesupport/test/core_ext/date_ext_test.rb
+++ b/activesupport/test/core_ext/date_ext_test.rb
@@ -120,10 +120,6 @@ class DateExtCalculationsTest < ActiveSupport::TestCase
assert_equal Date.new(1582, 10, 4), Date.new(1583, 10, 14).prev_year
end
- def test_last_year
- assert_equal Date.new(2004, 6, 5), Date.new(2005, 6, 5).last_year
- end
-
def test_last_year_in_leap_years
assert_equal Date.new(1999, 2, 28), Date.new(2000, 2, 29).last_year
end
@@ -185,10 +181,6 @@ class DateExtCalculationsTest < ActiveSupport::TestCase
assert_equal Date.new(1582, 10, 18), Date.new(1582, 10, 4).next_week
end
- def test_last_month_on_31st
- assert_equal Date.new(2004, 2, 29), Date.new(2004, 3, 31).last_month
- end
-
def test_last_quarter_on_31st
assert_equal Date.new(2004, 2, 29), Date.new(2004, 5, 31).last_quarter
end
diff --git a/activesupport/test/core_ext/date_time_ext_test.rb b/activesupport/test/core_ext/date_time_ext_test.rb
index a3c2018a31..d942cddb2a 100644
--- a/activesupport/test/core_ext/date_time_ext_test.rb
+++ b/activesupport/test/core_ext/date_time_ext_test.rb
@@ -162,10 +162,6 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase
assert_equal DateTime.civil(2005, 4, 30, 23, 59, Rational(59999999999, 1000000000)), DateTime.civil(2005, 4, 20, 10, 10, 10).end_of_month
end
- def test_last_year
- assert_equal DateTime.civil(2004, 6, 5, 10), DateTime.civil(2005, 6, 5, 10, 0, 0).last_year
- end
-
def test_ago
assert_equal DateTime.civil(2005, 2, 22, 10, 10, 9), DateTime.civil(2005, 2, 22, 10, 10, 10).ago(1)
assert_equal DateTime.civil(2005, 2, 22, 9, 10, 10), DateTime.civil(2005, 2, 22, 10, 10, 10).ago(3600)
@@ -248,10 +244,6 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase
assert_equal DateTime.civil(2016, 2, 29), DateTime.civil(2016, 3, 7).last_week
end
- def test_last_month_on_31st
- assert_equal DateTime.civil(2004, 2, 29), DateTime.civil(2004, 3, 31).last_month
- end
-
def test_last_quarter_on_31st
assert_equal DateTime.civil(2004, 2, 29), DateTime.civil(2004, 5, 31).last_quarter
end
diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb
index dc2f4c5ac7..8cb17df01b 100644
--- a/activesupport/test/core_ext/time_ext_test.rb
+++ b/activesupport/test/core_ext/time_ext_test.rb
@@ -178,10 +178,6 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
assert_equal Time.local(2005, 2, 4, 19, 30, 59, Rational(999999999, 1000)), Time.local(2005, 2, 4, 19, 30, 10).end_of_minute
end
- def test_last_year
- assert_equal Time.local(2004, 6, 5, 10), Time.local(2005, 6, 5, 10, 0, 0).last_year
- end
-
def test_ago
assert_equal Time.local(2005, 2, 22, 10, 10, 9), Time.local(2005, 2, 22, 10, 10, 10).ago(1)
assert_equal Time.local(2005, 2, 22, 9, 10, 10), Time.local(2005, 2, 22, 10, 10, 10).ago(3600)
@@ -664,10 +660,6 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
end
end
- def test_last_month_on_31st
- assert_equal Time.local(2004, 2, 29), Time.local(2004, 3, 31).last_month
- end
-
def test_xmlschema_is_available
assert_nothing_raised { Time.now.xmlschema }
end
diff --git a/activesupport/test/inflector_test.rb b/activesupport/test/inflector_test.rb
index eeec0ab1a5..6cc1039d8e 100644
--- a/activesupport/test/inflector_test.rb
+++ b/activesupport/test/inflector_test.rb
@@ -356,6 +356,19 @@ class InflectorTest < ActiveSupport::TestCase
assert_equal("Col rpted bugs", ActiveSupport::Inflector.humanize("COL_rpted_bugs"))
end
+ def test_humanize_with_acronyms
+ ActiveSupport::Inflector.inflections do |inflect|
+ inflect.acronym "LAX"
+ inflect.acronym "SFO"
+ end
+ assert_equal("LAX roundtrip to SFO", ActiveSupport::Inflector.humanize("LAX ROUNDTRIP TO SFO"))
+ assert_equal("LAX roundtrip to SFO", ActiveSupport::Inflector.humanize("LAX ROUNDTRIP TO SFO", capitalize: false))
+ assert_equal("LAX roundtrip to SFO", ActiveSupport::Inflector.humanize("lax roundtrip to sfo"))
+ assert_equal("LAX roundtrip to SFO", ActiveSupport::Inflector.humanize("lax roundtrip to sfo", capitalize: false))
+ assert_equal("LAX roundtrip to SFO", ActiveSupport::Inflector.humanize("Lax Roundtrip To Sfo"))
+ assert_equal("LAX roundtrip to SFO", ActiveSupport::Inflector.humanize("Lax Roundtrip To Sfo", capitalize: false))
+ end
+
def test_constantize
run_constantize_tests_on do |string|
ActiveSupport::Inflector.constantize(string)
diff --git a/guides/source/active_support_core_extensions.md b/guides/source/active_support_core_extensions.md
index 54d3dec1c2..66d2fbd939 100644
--- a/guides/source/active_support_core_extensions.md
+++ b/guides/source/active_support_core_extensions.md
@@ -2970,6 +2970,32 @@ Extensions to `Date`
NOTE: All the following methods are defined in `active_support/core_ext/date/calculations.rb`.
+```ruby
+yesterday
+tomorrow
+beginning_of_week (at_beginning_of_week)
+end_of_week (at_end_of_week)
+monday
+sunday
+weeks_ago
+prev_week (last_week)
+next_week
+months_ago
+months_since
+beginning_of_month (at_beginning_of_month)
+end_of_month (at_end_of_month)
+last_month
+beginning_of_quarter (at_beginning_of_quarter)
+end_of_quarter (at_end_of_quarter)
+beginning_of_year (at_beginning_of_year)
+end_of_year (at_end_of_year)
+years_ago
+years_since
+last_year
+on_weekday?
+on_weekend?
+```
+
INFO: The following calculation methods have edge cases in October 1582, since days 5..14 just do not exist. This guide does not document their behavior around those days for brevity, but it is enough to say that they do what you would expect. That is, `Date.new(1582, 10, 4).tomorrow` returns `Date.new(1582, 10, 15)` and so on. Please check `test/core_ext/date_ext_test.rb` in the Active Support test suite for expected behavior.
#### `Date.current`
@@ -2980,68 +3006,6 @@ When making Date comparisons using methods which honor the user time zone, make
#### Named dates
-##### `prev_year`, `next_year`
-
-In Ruby 1.9 `prev_year` and `next_year` return a date with the same day/month in the last or next year:
-
-```ruby
-d = Date.new(2010, 5, 8) # => Sat, 08 May 2010
-d.prev_year # => Fri, 08 May 2009
-d.next_year # => Sun, 08 May 2011
-```
-
-If date is the 29th of February of a leap year, you obtain the 28th:
-
-```ruby
-d = Date.new(2000, 2, 29) # => Tue, 29 Feb 2000
-d.prev_year # => Sun, 28 Feb 1999
-d.next_year # => Wed, 28 Feb 2001
-```
-
-`prev_year` is aliased to `last_year`.
-
-##### `prev_month`, `next_month`
-
-In Ruby 1.9 `prev_month` and `next_month` return the date with the same day in the last or next month:
-
-```ruby
-d = Date.new(2010, 5, 8) # => Sat, 08 May 2010
-d.prev_month # => Thu, 08 Apr 2010
-d.next_month # => Tue, 08 Jun 2010
-```
-
-If such a day does not exist, the last day of the corresponding month is returned:
-
-```ruby
-Date.new(2000, 5, 31).prev_month # => Sun, 30 Apr 2000
-Date.new(2000, 3, 31).prev_month # => Tue, 29 Feb 2000
-Date.new(2000, 5, 31).next_month # => Fri, 30 Jun 2000
-Date.new(2000, 1, 31).next_month # => Tue, 29 Feb 2000
-```
-
-`prev_month` is aliased to `last_month`.
-
-##### `prev_quarter`, `next_quarter`
-
-Same as `prev_month` and `next_month`. It returns the date with the same day in the previous or next quarter:
-
-```ruby
-t = Time.local(2010, 5, 8) # => Sat, 08 May 2010
-t.prev_quarter # => Mon, 08 Feb 2010
-t.next_quarter # => Sun, 08 Aug 2010
-```
-
-If such a day does not exist, the last day of the corresponding month is returned:
-
-```ruby
-Time.local(2000, 7, 31).prev_quarter # => Sun, 30 Apr 2000
-Time.local(2000, 5, 31).prev_quarter # => Tue, 29 Feb 2000
-Time.local(2000, 10, 31).prev_quarter # => Mon, 30 Oct 2000
-Time.local(2000, 11, 31).next_quarter # => Wed, 28 Feb 2001
-```
-
-`prev_quarter` is aliased to `last_quarter`.
-
##### `beginning_of_week`, `end_of_week`
The methods `beginning_of_week` and `end_of_week` return the dates for the
@@ -3159,6 +3123,8 @@ Date.new(2012, 2, 29).years_ago(3) # => Sat, 28 Feb 2009
Date.new(2012, 2, 29).years_since(3) # => Sat, 28 Feb 2015
```
+`last_year` is short-hand for `#years_ago(1)`.
+
##### `months_ago`, `months_since`
The methods `months_ago` and `months_since` work analogously for months:
@@ -3175,6 +3141,8 @@ Date.new(2010, 4, 30).months_ago(2) # => Sun, 28 Feb 2010
Date.new(2009, 12, 31).months_since(2) # => Sun, 28 Feb 2010
```
+`last_month` is short-hand for `#months_ago(1)`.
+
##### `weeks_ago`
The method `weeks_ago` works analogously for weeks:
@@ -3337,35 +3305,7 @@ WARNING: `DateTime` is not aware of DST rules and so some of these methods have
NOTE: All the following methods are defined in `active_support/core_ext/date_time/calculations.rb`.
-The class `DateTime` is a subclass of `Date` so by loading `active_support/core_ext/date/calculations.rb` you inherit these methods and their aliases, except that they will always return datetimes:
-
-```ruby
-yesterday
-tomorrow
-beginning_of_week (at_beginning_of_week)
-end_of_week (at_end_of_week)
-monday
-sunday
-weeks_ago
-prev_week (last_week)
-next_week
-months_ago
-months_since
-beginning_of_month (at_beginning_of_month)
-end_of_month (at_end_of_month)
-prev_month (last_month)
-next_month
-beginning_of_quarter (at_beginning_of_quarter)
-end_of_quarter (at_end_of_quarter)
-beginning_of_year (at_beginning_of_year)
-end_of_year (at_end_of_year)
-years_ago
-years_since
-prev_year (last_year)
-next_year
-on_weekday?
-on_weekend?
-```
+The class `DateTime` is a subclass of `Date` so by loading `active_support/core_ext/date/calculations.rb` you inherit these methods and their aliases, except that they will always return datetimes.
The following methods are reimplemented so you do **not** need to load `active_support/core_ext/date/calculations.rb` for these ones:
@@ -3513,8 +3453,6 @@ Extensions to `Time`
NOTE: All the following methods are defined in `active_support/core_ext/time/calculations.rb`.
-Active Support adds to `Time` many of the methods available for `DateTime`:
-
```ruby
past?
today?
@@ -3526,6 +3464,8 @@ change
advance
ago
since (in)
+prev_day
+next_day
beginning_of_day (midnight, at_midnight, at_beginning_of_day)
end_of_day
beginning_of_hour (at_beginning_of_hour)
@@ -3541,15 +3481,17 @@ months_ago
months_since
beginning_of_month (at_beginning_of_month)
end_of_month (at_end_of_month)
-prev_month (last_month)
+prev_month
next_month
+last_month
beginning_of_quarter (at_beginning_of_quarter)
end_of_quarter (at_end_of_quarter)
beginning_of_year (at_beginning_of_year)
end_of_year (at_end_of_year)
years_ago
years_since
-prev_year (last_year)
+prev_year
+last_year
next_year
on_weekday?
on_weekend?
@@ -3607,6 +3549,74 @@ now.all_year
# => Fri, 01 Jan 2010 00:00:00 UTC +00:00..Fri, 31 Dec 2010 23:59:59 UTC +00:00
```
+#### `prev_day`, `next_day`
+
+In Ruby 1.9 `prev_day` and `next_day` return the date in the last or next day:
+
+```ruby
+d = Date.new(2010, 5, 8) # => Sat, 08 May 2010
+d.prev_day # => Fri, 07 May 2010
+d.next_day # => Sun, 09 May 2010
+```
+
+#### `prev_month`, `next_month`
+
+In Ruby 1.9 `prev_month` and `next_month` return the date with the same day in the last or next month:
+
+```ruby
+d = Date.new(2010, 5, 8) # => Sat, 08 May 2010
+d.prev_month # => Thu, 08 Apr 2010
+d.next_month # => Tue, 08 Jun 2010
+```
+
+If such a day does not exist, the last day of the corresponding month is returned:
+
+```ruby
+Date.new(2000, 5, 31).prev_month # => Sun, 30 Apr 2000
+Date.new(2000, 3, 31).prev_month # => Tue, 29 Feb 2000
+Date.new(2000, 5, 31).next_month # => Fri, 30 Jun 2000
+Date.new(2000, 1, 31).next_month # => Tue, 29 Feb 2000
+```
+
+#### `prev_year`, `next_year`
+
+In Ruby 1.9 `prev_year` and `next_year` return a date with the same day/month in the last or next year:
+
+```ruby
+d = Date.new(2010, 5, 8) # => Sat, 08 May 2010
+d.prev_year # => Fri, 08 May 2009
+d.next_year # => Sun, 08 May 2011
+```
+
+If date is the 29th of February of a leap year, you obtain the 28th:
+
+```ruby
+d = Date.new(2000, 2, 29) # => Tue, 29 Feb 2000
+d.prev_year # => Sun, 28 Feb 1999
+d.next_year # => Wed, 28 Feb 2001
+```
+
+#### `prev_quarter`, `next_quarter`
+
+`prev_quarter` and `next_quarter` return the date with the same day in the previous or next quarter:
+
+```ruby
+t = Time.local(2010, 5, 8) # => 2010-05-08 00:00:00 +0300
+t.prev_quarter # => 2010-02-08 00:00:00 +0200
+t.next_quarter # => 2010-08-08 00:00:00 +0300
+```
+
+If such a day does not exist, the last day of the corresponding month is returned:
+
+```ruby
+Time.local(2000, 7, 31).prev_quarter # => 2000-04-30 00:00:00 +0300
+Time.local(2000, 5, 31).prev_quarter # => 2000-02-29 00:00:00 +0200
+Time.local(2000, 10, 31).prev_quarter # => 2000-07-31 00:00:00 +0300
+Time.local(2000, 11, 31).next_quarter # => 2001-03-01 00:00:00 +0200
+```
+
+`prev_quarter` is aliased to `last_quarter`.
+
### Time Constructors
Active Support defines `Time.current` to be `Time.zone.now` if there's a user time zone defined, with fallback to `Time.now`:
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index 20603dedaf..e69a1231b1 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,3 +1,9 @@
+* `rails new` and `rails plugin new` get `Active Storage` by default.
+ Add ability to skip `Active Storage` with `--skip-active-storage`
+ and do so automatically when `--skip-active-record` is used.
+
+ *bogdanvlviv*
+
* Gemfile for new apps: upgrade redis-rb from ~> 3.0 to 4.0.
*Jeremy Daer*
diff --git a/railties/lib/rails/all.rb b/railties/lib/rails/all.rb
index e55b2e2433..f5dccd2381 100644
--- a/railties/lib/rails/all.rb
+++ b/railties/lib/rails/all.rb
@@ -4,12 +4,12 @@ require "rails"
%w(
active_record/railtie
+ active_storage/engine
action_controller/railtie
action_view/railtie
action_mailer/railtie
active_job/railtie
action_cable/engine
- active_storage/engine
rails/test_unit/railtie
sprockets/railtie
).each do |railtie|
diff --git a/railties/lib/rails/app_updater.rb b/railties/lib/rails/app_updater.rb
index c2436a69f9..a076d082d5 100644
--- a/railties/lib/rails/app_updater.rb
+++ b/railties/lib/rails/app_updater.rb
@@ -21,11 +21,12 @@ module Rails
private
def generator_options
options = { api: !!Rails.application.config.api_only, update: true }
- options[:skip_active_record] = !defined?(ActiveRecord::Railtie)
- options[:skip_action_mailer] = !defined?(ActionMailer::Railtie)
- options[:skip_action_cable] = !defined?(ActionCable::Engine)
- options[:skip_sprockets] = !defined?(Sprockets::Railtie)
- options[:skip_puma] = !defined?(Puma)
+ options[:skip_active_record] = !defined?(ActiveRecord::Railtie)
+ options[:skip_active_storage] = !defined?(ActiveStorage::Engine) || !defined?(ActiveRecord::Railtie)
+ options[:skip_action_mailer] = !defined?(ActionMailer::Railtie)
+ options[:skip_action_cable] = !defined?(ActionCable::Engine)
+ options[:skip_sprockets] = !defined?(Sprockets::Railtie)
+ options[:skip_puma] = !defined?(Puma)
options
end
end
diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb
index 9800e5750a..3362bf629a 100644
--- a/railties/lib/rails/generators/actions.rb
+++ b/railties/lib/rails/generators/actions.rb
@@ -221,6 +221,7 @@ module Rails
# rake("db:migrate")
# rake("db:migrate", env: "production")
# rake("gems:install", sudo: true)
+ # rake("gems:install", capture: true)
def rake(command, options = {})
execute_command :rake, command, options
end
@@ -230,6 +231,7 @@ module Rails
# rails_command("db:migrate")
# rails_command("db:migrate", env: "production")
# rails_command("gems:install", sudo: true)
+ # rails_command("gems:install", capture: true)
def rails_command(command, options = {})
execute_command :rails, command, options
end
@@ -292,7 +294,11 @@ module Rails
log executor, command
env = options[:env] || ENV["RAILS_ENV"] || "development"
sudo = options[:sudo] && !Gem.win_platform? ? "sudo " : ""
- in_root { run("#{sudo}#{extify(executor)} #{command} RAILS_ENV=#{env}", verbose: false) }
+ config = { verbose: false }
+
+ config.merge!(capture: options[:capture]) if options[:capture]
+
+ in_root { run("#{sudo}#{extify(executor)} #{command} RAILS_ENV=#{env}", config) }
end
# Add an extension to the given name based on the platform.
diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb
index bc00adabae..59ca4c849f 100644
--- a/railties/lib/rails/generators/app_base.rb
+++ b/railties/lib/rails/generators/app_base.rb
@@ -26,75 +26,78 @@ module Rails
end
def self.add_shared_options_for(name)
- class_option :template, type: :string, aliases: "-m",
- desc: "Path to some #{name} template (can be a filesystem path or URL)"
+ class_option :template, type: :string, aliases: "-m",
+ desc: "Path to some #{name} template (can be a filesystem path or URL)"
- class_option :database, type: :string, aliases: "-d", default: "sqlite3",
- desc: "Preconfigure for selected database (options: #{DATABASES.join('/')})"
+ class_option :database, type: :string, aliases: "-d", default: "sqlite3",
+ desc: "Preconfigure for selected database (options: #{DATABASES.join('/')})"
- class_option :skip_yarn, type: :boolean, default: false,
- desc: "Don't use Yarn for managing JavaScript dependencies"
+ class_option :skip_yarn, type: :boolean, default: false,
+ desc: "Don't use Yarn for managing JavaScript dependencies"
- class_option :skip_gemfile, type: :boolean, default: false,
- desc: "Don't create a Gemfile"
+ class_option :skip_gemfile, type: :boolean, default: false,
+ desc: "Don't create a Gemfile"
- class_option :skip_git, type: :boolean, aliases: "-G", default: false,
- desc: "Skip .gitignore file"
+ class_option :skip_git, type: :boolean, aliases: "-G", default: false,
+ desc: "Skip .gitignore file"
- class_option :skip_keeps, type: :boolean, default: false,
- desc: "Skip source control .keep files"
+ class_option :skip_keeps, type: :boolean, default: false,
+ desc: "Skip source control .keep files"
- class_option :skip_action_mailer, type: :boolean, aliases: "-M",
- default: false,
- desc: "Skip Action Mailer files"
+ class_option :skip_action_mailer, type: :boolean, aliases: "-M",
+ default: false,
+ desc: "Skip Action Mailer files"
- class_option :skip_active_record, type: :boolean, aliases: "-O", default: false,
- desc: "Skip Active Record files"
+ class_option :skip_active_record, type: :boolean, aliases: "-O", default: false,
+ desc: "Skip Active Record files"
- class_option :skip_puma, type: :boolean, aliases: "-P", default: false,
- desc: "Skip Puma related files"
+ class_option :skip_active_storage, type: :boolean, default: false,
+ desc: "Skip Active Storage files"
- class_option :skip_action_cable, type: :boolean, aliases: "-C", default: false,
- desc: "Skip Action Cable files"
+ class_option :skip_puma, type: :boolean, aliases: "-P", default: false,
+ desc: "Skip Puma related files"
- class_option :skip_sprockets, type: :boolean, aliases: "-S", default: false,
- desc: "Skip Sprockets files"
+ class_option :skip_action_cable, type: :boolean, aliases: "-C", default: false,
+ desc: "Skip Action Cable files"
- class_option :skip_spring, type: :boolean, default: false,
- desc: "Don't install Spring application preloader"
+ class_option :skip_sprockets, type: :boolean, aliases: "-S", default: false,
+ desc: "Skip Sprockets files"
- class_option :skip_listen, type: :boolean, default: false,
- desc: "Don't generate configuration that depends on the listen gem"
+ class_option :skip_spring, type: :boolean, default: false,
+ desc: "Don't install Spring application preloader"
- class_option :skip_coffee, type: :boolean, default: false,
- desc: "Don't use CoffeeScript"
+ class_option :skip_listen, type: :boolean, default: false,
+ desc: "Don't generate configuration that depends on the listen gem"
- class_option :skip_javascript, type: :boolean, aliases: "-J", default: false,
- desc: "Skip JavaScript files"
+ class_option :skip_coffee, type: :boolean, default: false,
+ desc: "Don't use CoffeeScript"
- class_option :skip_turbolinks, type: :boolean, default: false,
- desc: "Skip turbolinks gem"
+ class_option :skip_javascript, type: :boolean, aliases: "-J", default: false,
+ desc: "Skip JavaScript files"
- class_option :skip_test, type: :boolean, aliases: "-T", default: false,
- desc: "Skip test files"
+ class_option :skip_turbolinks, type: :boolean, default: false,
+ desc: "Skip turbolinks gem"
- class_option :skip_system_test, type: :boolean, default: false,
- desc: "Skip system test files"
+ class_option :skip_test, type: :boolean, aliases: "-T", default: false,
+ desc: "Skip test files"
- class_option :dev, type: :boolean, default: false,
- desc: "Setup the #{name} with Gemfile pointing to your Rails checkout"
+ class_option :skip_system_test, type: :boolean, default: false,
+ desc: "Skip system test files"
- class_option :edge, type: :boolean, default: false,
- desc: "Setup the #{name} with Gemfile pointing to Rails repository"
+ class_option :dev, type: :boolean, default: false,
+ desc: "Setup the #{name} with Gemfile pointing to your Rails checkout"
- class_option :rc, type: :string, default: nil,
- desc: "Path to file containing extra configuration options for rails command"
+ class_option :edge, type: :boolean, default: false,
+ desc: "Setup the #{name} with Gemfile pointing to Rails repository"
- class_option :no_rc, type: :boolean, default: false,
- desc: "Skip loading of extra configuration options from .railsrc file"
+ class_option :rc, type: :string, default: nil,
+ desc: "Path to file containing extra configuration options for rails command"
- class_option :help, type: :boolean, aliases: "-h", group: :rails,
- desc: "Show this help message and quit"
+ class_option :no_rc, type: :boolean, default: false,
+ desc: "Skip loading of extra configuration options from .railsrc file"
+
+ class_option :help, type: :boolean, aliases: "-h", group: :rails,
+ desc: "Show this help message and quit"
end
def initialize(*args)
@@ -193,11 +196,29 @@ module Rails
end
def include_all_railties? # :doc:
- options.values_at(:skip_active_record, :skip_action_mailer, :skip_test, :skip_sprockets, :skip_action_cable).none?
+ [
+ options.values_at(
+ :skip_active_record,
+ :skip_action_mailer,
+ :skip_test,
+ :skip_sprockets,
+ :skip_action_cable
+ ),
+ skip_active_storage?
+ ].flatten.none?
end
def comment_if(value) # :doc:
- options[value] ? "# " : ""
+ question = "#{value}?"
+
+ comment =
+ if respond_to?(question, true)
+ send(question)
+ else
+ options[value]
+ end
+
+ comment ? "# " : ""
end
def keeps? # :doc:
@@ -208,6 +229,10 @@ module Rails
!options[:skip_active_record] && options[:database] == "sqlite3"
end
+ def skip_active_storage? # :doc:
+ options[:skip_active_storage] || options[:skip_active_record]
+ end
+
class GemfileEntry < Struct.new(:name, :version, :comment, :options, :commented_out)
def initialize(name, version, comment, options = {}, commented_out = false)
super
@@ -434,6 +459,12 @@ module Rails
end
end
+ def run_active_storage
+ unless skip_active_storage?
+ rails_command "active_storage:install", capture: options[:quiet]
+ end
+ end
+
def empty_directory_with_keep_file(destination, config = {})
empty_directory(destination, config)
keep_file(destination)
diff --git a/railties/lib/rails/generators/named_base.rb b/railties/lib/rails/generators/named_base.rb
index 44f5ab45d3..60625283ac 100644
--- a/railties/lib/rails/generators/named_base.rb
+++ b/railties/lib/rails/generators/named_base.rb
@@ -1,6 +1,5 @@
# frozen_string_literal: true
-require "active_support/core_ext/module/introspection"
require "rails/generators/base"
require "rails/generators/generated_attribute"
@@ -158,26 +157,26 @@ module Rails
def model_resource_name(prefix: "") # :doc:
resource_name = "#{prefix}#{singular_table_name}"
- if controller_class_path.empty?
- resource_name
- else
+ if options[:model_name]
"[#{controller_class_path.map { |name| ":" + name }.join(", ")}, #{resource_name}]"
+ else
+ resource_name
end
end
def singular_route_name # :doc:
- if controller_class_path.empty?
- singular_table_name
- else
+ if options[:model_name]
"#{controller_class_path.join('_')}_#{singular_table_name}"
+ else
+ singular_table_name
end
end
def plural_route_name # :doc:
- if controller_class_path.empty?
- plural_table_name
- else
+ if options[:model_name]
"#{controller_class_path.join('_')}_#{plural_table_name}"
+ else
+ plural_table_name
end
end
diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb
index 46954f64b5..1c32fad3ea 100644
--- a/railties/lib/rails/generators/rails/app/app_generator.rb
+++ b/railties/lib/rails/generators/rails/app/app_generator.rb
@@ -114,7 +114,7 @@ module Rails
template "cable.yml" unless options[:skip_action_cable]
template "puma.rb" unless options[:skip_puma]
template "spring.rb" if spring_install?
- template "storage.yml"
+ template "storage.yml" unless skip_active_storage?
directory "environments"
directory "initializers"
@@ -139,7 +139,7 @@ module Rails
template "config/cable.yml"
end
- if !active_storage_config_exist
+ if !skip_active_storage? && !active_storage_config_exist
template "config/storage.yml"
end
@@ -355,6 +355,10 @@ module Rails
build(:system_test) if depends_on_system_test?
end
+ def create_storage_files
+ build(:storage) unless skip_active_storage?
+ end
+
def create_tmp_files
build(:tmp)
end
@@ -457,6 +461,7 @@ module Rails
public_task :apply_rails_template, :run_bundle
public_task :run_webpack, :generate_spring_binstubs
+ public_task :run_active_storage
def run_after_bundle_callbacks
@after_bundle_callbacks.each(&:call)
diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile
index 95e8be96b6..ee9db83ca2 100644
--- a/railties/lib/rails/generators/rails/app/templates/Gemfile
+++ b/railties/lib/rails/generators/rails/app/templates/Gemfile
@@ -20,9 +20,10 @@ ruby <%= "'#{RUBY_VERSION}'" -%>
# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'
-
+<% unless skip_active_storage? -%>
# Use ActiveStorage variant
# gem 'mini_magick', '~> 4.8'
+<% end -%>
# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development
diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt
index 62fd04f113..5183bcd256 100644
--- a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt
+++ b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt
@@ -12,7 +12,9 @@
//
<% unless options[:skip_javascript] -%>
//= require rails-ujs
+<% unless skip_active_storage? -%>
//= require activestorage
+<% end -%>
<% unless options[:skip_turbolinks] -%>
//= require turbolinks
<% end -%>
diff --git a/railties/lib/rails/generators/rails/app/templates/config/application.rb b/railties/lib/rails/generators/rails/app/templates/config/application.rb
index dde09edb94..9e03e86771 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/application.rb
+++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb
@@ -8,10 +8,10 @@ require "rails"
require "active_model/railtie"
require "active_job/railtie"
<%= comment_if :skip_active_record %>require "active_record/railtie"
+<%= comment_if :skip_active_storage %>require "active_storage/engine"
require "action_controller/railtie"
<%= comment_if :skip_action_mailer %>require "action_mailer/railtie"
require "action_view/railtie"
-require "active_storage/engine"
<%= comment_if :skip_action_cable %>require "action_cable/engine"
<%= comment_if :skip_sprockets %>require "sprockets/railtie"
<%= comment_if :skip_test %>require "rails/test_unit/railtie"
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
index 98689cc30d..2746aedd6f 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
@@ -27,8 +27,10 @@ Rails.application.configure do
config.cache_store = :null_store
end
+ <%- unless skip_active_storage? -%>
# Store uploaded files on the local file system (see config/storage.yml for options)
config.active_storage.service = :local
+ <%- end -%>
<%- unless options.skip_action_mailer? -%>
# Don't care if the mailer can't send.
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
index 2e0b555f6f..4c0f36db98 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
@@ -44,9 +44,11 @@ Rails.application.configure do
# config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
+ <%- unless skip_active_storage? -%>
# Store uploaded files on the local file system (see config/storage.yml for options)
config.active_storage.service = :local
+ <%- end -%>
<%- unless options[:skip_action_cable] -%>
# Mount Action Cable outside main process or domain
# config.action_cable.mount_path = nil
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt
index a53978bc6e..a19f490d91 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt
@@ -28,8 +28,11 @@ Rails.application.configure do
# Disable request forgery protection in test environment.
config.action_controller.allow_forgery_protection = false
+ <%- unless skip_active_storage? -%>
# Store uploaded files on the local file system in a temporary directory
config.active_storage.service = :test
+
+ <%- end -%>
<%- unless options.skip_action_mailer? -%>
config.action_mailer.perform_caching = false
diff --git a/railties/lib/rails/generators/rails/app/templates/gitignore b/railties/lib/rails/generators/rails/app/templates/gitignore
index 83a7b211aa..bd6b34346a 100644
--- a/railties/lib/rails/generators/rails/app/templates/gitignore
+++ b/railties/lib/rails/generators/rails/app/templates/gitignore
@@ -21,8 +21,10 @@
!/tmp/.keep
<% end -%>
+<% unless skip_active_storage? -%>
# Ignore uploaded files in development
/storage/*
+<% end -%>
<% unless options.skip_yarn? -%>
/node_modules
diff --git a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb
index d9ca4712d0..bc2dcf008e 100644
--- a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb
+++ b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb
@@ -87,7 +87,7 @@ task default: :test
end
PASSTHROUGH_OPTIONS = [
- :skip_active_record, :skip_action_mailer, :skip_javascript, :skip_action_cable, :skip_sprockets, :database,
+ :skip_active_record, :skip_active_storage, :skip_action_mailer, :skip_javascript, :skip_action_cable, :skip_sprockets, :database,
:javascript, :skip_yarn, :api, :quiet, :pretend, :skip
]
diff --git a/railties/lib/rails/generators/rails/plugin/templates/gitignore b/railties/lib/rails/generators/rails/plugin/templates/gitignore
index e15863d860..7a68da5c4b 100644
--- a/railties/lib/rails/generators/rails/plugin/templates/gitignore
+++ b/railties/lib/rails/generators/rails/plugin/templates/gitignore
@@ -11,5 +11,8 @@ pkg/
<%= dummy_path %>/node_modules/
<%= dummy_path %>/yarn-error.log
<% end -%>
+<% unless skip_active_storage? -%>
+<%= dummy_path %>/storage/
+<% end -%>
<%= dummy_path %>/tmp/
<% end -%>
diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb b/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb
index 47b56ae3df..06ffe2f1ed 100644
--- a/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb
+++ b/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb
@@ -8,10 +8,10 @@ require "rails"
require "active_model/railtie"
require "active_job/railtie"
<%= comment_if :skip_active_record %>require "active_record/railtie"
+<%= comment_if :skip_active_storage %>require "active_storage/engine"
require "action_controller/railtie"
<%= comment_if :skip_action_mailer %>require "action_mailer/railtie"
require "action_view/railtie"
-require "active_storage/engine"
<%= comment_if :skip_action_cable %>require "action_cable/engine"
<%= comment_if :skip_sprockets %>require "sprockets/railtie"
<%= comment_if :skip_test %>require "rails/test_unit/railtie"
diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js b/railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js
index e54c6461cc..f3d80c87f5 100644
--- a/railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js
+++ b/railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js
@@ -10,4 +10,7 @@
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
+<% unless skip_active_storage? -%>
+//= require activestorage
+<% end -%>
//= require_tree .
diff --git a/railties/test/application/bin_setup_test.rb b/railties/test/application/bin_setup_test.rb
index 54934dbe24..9fac0435e4 100644
--- a/railties/test/application/bin_setup_test.rb
+++ b/railties/test/application/bin_setup_test.rb
@@ -16,6 +16,8 @@ module ApplicationTests
def test_bin_setup
Dir.chdir(app_path) do
+ FileUtils.rm_rf("db/migrate")
+
app_file "db/schema.rb", <<-RUBY
ActiveRecord::Schema.define(version: 20140423102712) do
create_table(:articles) {}
@@ -37,6 +39,8 @@ module ApplicationTests
def test_bin_setup_output
Dir.chdir(app_path) do
+ FileUtils.rm_rf("db/migrate")
+
app_file "db/schema.rb", ""
output = `bin/setup 2>&1`
diff --git a/railties/test/application/integration_test_case_test.rb b/railties/test/application/integration_test_case_test.rb
index 9edc907fce..c08761092b 100644
--- a/railties/test/application/integration_test_case_test.rb
+++ b/railties/test/application/integration_test_case_test.rb
@@ -1,10 +1,11 @@
# frozen_string_literal: true
require "isolation/abstract_unit"
+require "env_helpers"
module ApplicationTests
class IntegrationTestCaseTest < ActiveSupport::TestCase
- include ActiveSupport::Testing::Isolation
+ include ActiveSupport::Testing::Isolation, EnvHelpers
setup do
build_app
@@ -39,13 +40,14 @@ module ApplicationTests
end
RUBY
+ with_rails_env("test") { rails("db:migrate") }
output = rails("test")
assert_match(/0 failures, 0 errors/, output)
end
end
class IntegrationTestDefaultApp < ActiveSupport::TestCase
- include ActiveSupport::Testing::Isolation
+ include ActiveSupport::Testing::Isolation, EnvHelpers
setup do
build_app
@@ -66,6 +68,7 @@ module ApplicationTests
end
RUBY
+ with_rails_env("test") { rails("db:migrate") }
output = rails("test")
assert_match(/0 failures, 0 errors/, output)
end
diff --git a/railties/test/application/middleware/exceptions_test.rb b/railties/test/application/middleware/exceptions_test.rb
index 75afeec905..2d659ade8d 100644
--- a/railties/test/application/middleware/exceptions_test.rb
+++ b/railties/test/application/middleware/exceptions_test.rb
@@ -102,7 +102,7 @@ module ApplicationTests
end
end
- test "routing to an nonexistent controller when action_dispatch.show_exceptions and consider_all_requests_local are set shows diagnostics" do
+ test "routing to a nonexistent controller when action_dispatch.show_exceptions and consider_all_requests_local are set shows diagnostics" do
app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
resources :articles
diff --git a/railties/test/application/rackup_test.rb b/railties/test/application/rackup_test.rb
index 383f18a7da..1dcc2826f0 100644
--- a/railties/test/application/rackup_test.rb
+++ b/railties/test/application/rackup_test.rb
@@ -26,6 +26,7 @@ module ApplicationTests
test "config.ru can be racked up" do
Dir.chdir app_path do
+ FileUtils.rm_rf("db/migrate")
@app = rackup
assert_welcome get("/")
end
diff --git a/railties/test/application/rake/dbs_test.rb b/railties/test/application/rake/dbs_test.rb
index fd22477539..009f2887c9 100644
--- a/railties/test/application/rake/dbs_test.rb
+++ b/railties/test/application/rake/dbs_test.rb
@@ -287,6 +287,8 @@ module ApplicationTests
ENV.delete "RAILS_ENV"
ENV.delete "RACK_ENV"
+ Dir.chdir(app_path) { FileUtils.rm_rf("db/migrate") }
+
app_file "db/schema.rb", <<-RUBY
ActiveRecord::Schema.define(version: "1") do
create_table :users do |t|
@@ -308,6 +310,8 @@ module ApplicationTests
end
test "db:setup sets ar_internal_metadata" do
+ Dir.chdir(app_path) { FileUtils.rm_rf("db/migrate") }
+
app_file "db/schema.rb", ""
rails "db:setup"
diff --git a/railties/test/application/rake/migrations_test.rb b/railties/test/application/rake/migrations_test.rb
index 33f2b7038c..788f9160d6 100644
--- a/railties/test/application/rake/migrations_test.rb
+++ b/railties/test/application/rake/migrations_test.rb
@@ -37,9 +37,64 @@ module ApplicationTests
assert_match(/AMigration: reverted/, output)
end
+ test "migrate with specified VERSION in different formats" do
+ app_file "db/migrate/01_one_migration.rb", <<-MIGRATION
+ class OneMigration < ActiveRecord::Migration::Current
+ end
+ MIGRATION
+
+ app_file "db/migrate/02_two_migration.rb", <<-MIGRATION
+ class TwoMigration < ActiveRecord::Migration::Current
+ end
+ MIGRATION
+
+ app_file "db/migrate/03_three_migration.rb", <<-MIGRATION
+ class ThreeMigration < ActiveRecord::Migration::Current
+ end
+ MIGRATION
+
+ rails "db:migrate"
+
+ output = rails("db:migrate:status")
+ assert_match(/up\s+001\s+One migration/, output)
+ assert_match(/up\s+002\s+Two migration/, output)
+ assert_match(/up\s+003\s+Three migration/, output)
+
+ rails "db:migrate", "VERSION=01_one_migration.rb"
+ output = rails("db:migrate:status")
+ assert_match(/up\s+001\s+One migration/, output)
+ assert_match(/down\s+002\s+Two migration/, output)
+ assert_match(/down\s+003\s+Three migration/, output)
+
+ rails "db:migrate", "VERSION=3"
+ output = rails("db:migrate:status")
+ assert_match(/up\s+001\s+One migration/, output)
+ assert_match(/up\s+002\s+Two migration/, output)
+ assert_match(/up\s+003\s+Three migration/, output)
+
+ rails "db:migrate", "VERSION=001"
+ output = rails("db:migrate:status")
+ assert_match(/up\s+001\s+One migration/, output)
+ assert_match(/down\s+002\s+Two migration/, output)
+ assert_match(/down\s+003\s+Three migration/, output)
+ end
+
test "migration with empty version" do
- output = rails("db:migrate", "VERSION=", allow_failure: true)
- assert_match(/Empty VERSION provided/, output)
+ app_file "db/migrate/01_one_migration.rb", <<-MIGRATION
+ class OneMigration < ActiveRecord::Migration::Current
+ end
+ MIGRATION
+
+ app_file "db/migrate/02_two_migration.rb", <<-MIGRATION
+ class TwoMigration < ActiveRecord::Migration::Current
+ end
+ MIGRATION
+
+ rails("db:migrate", "VERSION=")
+
+ output = rails("db:migrate:status")
+ assert_match(/up\s+001\s+One migration/, output)
+ assert_match(/up\s+002\s+Two migration/, output)
output = rails("db:migrate:redo", "VERSION=", allow_failure: true)
assert_match(/Empty VERSION provided/, output)
@@ -55,6 +110,34 @@ module ApplicationTests
output = rails("db:migrate:down", allow_failure: true)
assert_match(/VERSION is required - To go down one migration, use db:rollback/, output)
+
+ output = rails("db:migrate:status")
+ assert_match(/up\s+001\s+One migration/, output)
+ assert_match(/up\s+002\s+Two migration/, output)
+ end
+
+ test "migration with 0 version" do
+ app_file "db/migrate/01_one_migration.rb", <<-MIGRATION
+ class OneMigration < ActiveRecord::Migration::Current
+ end
+ MIGRATION
+
+ app_file "db/migrate/02_two_migration.rb", <<-MIGRATION
+ class TwoMigration < ActiveRecord::Migration::Current
+ end
+ MIGRATION
+
+ rails "db:migrate"
+
+ output = rails("db:migrate:status")
+ assert_match(/up\s+001\s+One migration/, output)
+ assert_match(/up\s+002\s+Two migration/, output)
+
+ rails "db:migrate", "VERSION=0"
+
+ output = rails("db:migrate:status")
+ assert_match(/down\s+001\s+One migration/, output)
+ assert_match(/down\s+002\s+Two migration/, output)
end
test "model and migration generator with change syntax" do
@@ -192,6 +275,75 @@ module ApplicationTests
end
end
+ test "raise error on any move when target migration does not exist" do
+ app_file "db/migrate/01_one_migration.rb", <<-MIGRATION
+ class OneMigration < ActiveRecord::Migration::Current
+ end
+ MIGRATION
+
+ app_file "db/migrate/02_two_migration.rb", <<-MIGRATION
+ class TwoMigration < ActiveRecord::Migration::Current
+ end
+ MIGRATION
+
+ rails "db:migrate"
+
+ output = rails("db:migrate:status")
+ assert_match(/up\s+001\s+One migration/, output)
+ assert_match(/up\s+002\s+Two migration/, output)
+
+ output = rails("db:migrate", "VERSION=3", allow_failure: true)
+ assert_match(/rails aborted!/, output)
+ assert_match(/ActiveRecord::UnknownMigrationVersionError:/, output)
+ assert_match(/No migration with version number 3/, output)
+
+ output = rails("db:migrate:status")
+ assert_match(/up\s+001\s+One migration/, output)
+ assert_match(/up\s+002\s+Two migration/, output)
+ end
+
+ test "raise error on any move when VERSION has invalid format" do
+ output = rails("db:migrate", "VERSION=unknown", allow_failure: true)
+ assert_match(/rails aborted!/, output)
+ assert_match(/Invalid format of target version/, output)
+
+ output = rails("db:migrate", "VERSION=0.1.11", allow_failure: true)
+ assert_match(/rails aborted!/, output)
+ assert_match(/Invalid format of target version/, output)
+
+ output = rails("db:migrate", "VERSION=1.1.11", allow_failure: true)
+ assert_match(/rails aborted!/, output)
+ assert_match(/Invalid format of target version/, output)
+
+ output = rails("db:migrate", "VERSION='0 '", allow_failure: true)
+ assert_match(/rails aborted!/, output)
+ assert_match(/Invalid format of target version/, output)
+
+ output = rails("db:migrate", "VERSION=1.", allow_failure: true)
+ assert_match(/rails aborted!/, output)
+ assert_match(/Invalid format of target version/, output)
+
+ output = rails("db:migrate", "VERSION=1_", allow_failure: true)
+ assert_match(/rails aborted!/, output)
+ assert_match(/Invalid format of target version/, output)
+
+ output = rails("db:migrate", "VERSION=1_name", allow_failure: true)
+ assert_match(/rails aborted!/, output)
+ assert_match(/Invalid format of target version/, output)
+
+ output = rails("db:migrate:redo", "VERSION=unknown", allow_failure: true)
+ assert_match(/rails aborted!/, output)
+ assert_match(/Invalid format of target version/, output)
+
+ output = rails("db:migrate:up", "VERSION=unknown", allow_failure: true)
+ assert_match(/rails aborted!/, output)
+ assert_match(/Invalid format of target version/, output)
+
+ output = rails("db:migrate:down", "VERSION=unknown", allow_failure: true)
+ assert_match(/rails aborted!/, output)
+ assert_match(/Invalid format of target version/, output)
+ end
+
test "migration status after rollback and redo without timestamps" do
add_to_config("config.active_record.timestamped_migrations = false")
diff --git a/railties/test/application/test_runner_test.rb b/railties/test/application/test_runner_test.rb
index e92a0466dd..30bd283b48 100644
--- a/railties/test/application/test_runner_test.rb
+++ b/railties/test/application/test_runner_test.rb
@@ -11,6 +11,7 @@ module ApplicationTests
def setup
build_app
create_schema
+ remove_migrations
end
def teardown
@@ -727,6 +728,10 @@ module ApplicationTests
app_file "db/schema.rb", ""
end
+ def remove_migrations
+ Dir.chdir(app_path) { FileUtils.rm_rf("db/migrate") }
+ end
+
def create_test_file(path = :unit, name = "test", pass: true)
app_file "test/#{path}/#{name}_test.rb", <<-RUBY
require 'test_helper'
diff --git a/railties/test/application/test_test.rb b/railties/test/application/test_test.rb
index 0a51e98656..50238ed682 100644
--- a/railties/test/application/test_test.rb
+++ b/railties/test/application/test_test.rb
@@ -8,6 +8,7 @@ module ApplicationTests
def setup
build_app
+ remove_migrations
end
def teardown
@@ -320,6 +321,10 @@ Expected: ["id", "name"]
end
private
+ def remove_migrations
+ Dir.chdir(app_path) { FileUtils.rm_rf("db/migrate") }
+ end
+
def assert_unsuccessful_run(name, message)
result = run_test_file(name)
assert_not_equal 0, $?.to_i
diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb
index 3ecfb4edd9..f421207025 100644
--- a/railties/test/generators/actions_test.rb
+++ b/railties/test/generators/actions_test.rb
@@ -308,6 +308,14 @@ class ActionsTest < Rails::Generators::TestCase
end
end
+ test "rake command with capture option should run rake command with capture" do
+ assert_called_with(generator, :run, ["rake log:clear RAILS_ENV=development", verbose: false, capture: true]) do
+ with_rails_env nil do
+ action :rake, "log:clear", capture: true
+ end
+ end
+ end
+
test "rails command should run rails_command with default env" do
assert_called_with(generator, :run, ["rails log:clear RAILS_ENV=development", verbose: false]) do
with_rails_env nil do
@@ -346,6 +354,14 @@ class ActionsTest < Rails::Generators::TestCase
end
end
+ test "rails command with capture option should run rails_command with capture" do
+ assert_called_with(generator, :run, ["rails log:clear RAILS_ENV=development", verbose: false, capture: true]) do
+ with_rails_env nil do
+ action :rails_command, "log:clear", capture: true
+ end
+ end
+ end
+
def test_capify_should_run_the_capify_command
content = capture(:stderr) do
assert_called_with(generator, :run, ["capify .", verbose: false]) do
diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
index 160ad1a928..c5a59edab2 100644
--- a/railties/test/generators/app_generator_test.rb
+++ b/railties/test/generators/app_generator_test.rb
@@ -68,6 +68,7 @@ DEFAULT_APP_FILES = %w(
config/spring.rb
config/storage.yml
db
+ db/migrate
db/seeds.rb
lib
lib/tasks
@@ -75,6 +76,7 @@ DEFAULT_APP_FILES = %w(
log
package.json
public
+ storage
test/application_system_test_case.rb
test/test_helper.rb
test/fixtures
@@ -89,6 +91,7 @@ DEFAULT_APP_FILES = %w(
tmp
tmp/cache
tmp/cache/assets
+ tmp/storage
)
class AppGeneratorTest < Rails::Generators::TestCase
@@ -296,6 +299,65 @@ class AppGeneratorTest < Rails::Generators::TestCase
end
end
+ def test_active_storage_mini_magick_gem
+ run_generator
+ assert_file "Gemfile", /^# gem 'mini_magick'/
+ end
+
+ def test_app_update_does_not_generate_active_storage_contents_when_skip_active_storage_is_given
+ app_root = File.join(destination_root, "myapp")
+ run_generator [app_root, "--skip-active-storage"]
+
+ FileUtils.cd(app_root) do
+ quietly { system("bin/rails app:update") }
+ end
+
+ assert_file "#{app_root}/config/environments/development.rb" do |content|
+ assert_no_match(/config\.active_storage/, content)
+ end
+
+ assert_file "#{app_root}/config/environments/production.rb" do |content|
+ assert_no_match(/config\.active_storage/, content)
+ end
+
+ assert_file "#{app_root}/config/environments/test.rb" do |content|
+ assert_no_match(/config\.active_storage/, content)
+ end
+
+ assert_no_file "#{app_root}/config/storage.yml"
+
+ assert_file "#{app_root}/Gemfile" do |content|
+ assert_no_match(/gem 'mini_magick'/, content)
+ end
+ end
+
+ def test_app_update_does_not_generate_active_storage_contents_when_skip_active_record_is_given
+ app_root = File.join(destination_root, "myapp")
+ run_generator [app_root, "--skip-active-record"]
+
+ FileUtils.cd(app_root) do
+ quietly { system("bin/rails app:update") }
+ end
+
+ assert_file "#{app_root}/config/environments/development.rb" do |content|
+ assert_no_match(/config\.active_storage/, content)
+ end
+
+ assert_file "#{app_root}/config/environments/production.rb" do |content|
+ assert_no_match(/config\.active_storage/, content)
+ end
+
+ assert_file "#{app_root}/config/environments/test.rb" do |content|
+ assert_no_match(/config\.active_storage/, content)
+ end
+
+ assert_no_file "#{app_root}/config/storage.yml"
+
+ assert_file "#{app_root}/Gemfile" do |content|
+ assert_no_match(/gem 'mini_magick'/, content)
+ end
+ end
+
def test_application_names_are_not_singularized
run_generator [File.join(destination_root, "hats")]
assert_file "hats/config/environment.rb", /Rails\.application\.initialize!/
@@ -347,7 +409,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
end
def test_config_jdbcmysql_database
- run_generator([destination_root, "-d", "jdbcmysql"])
+ run_generator([destination_root, "-d", "jdbcmysql", "--skip-active-storage"])
assert_file "config/database.yml", /mysql/
assert_gem "activerecord-jdbcmysql-adapter"
end
@@ -365,7 +427,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
end
def test_config_jdbc_database
- run_generator([destination_root, "-d", "jdbc"])
+ run_generator([destination_root, "-d", "jdbc", "--skip-active-storage"])
assert_file "config/database.yml", /jdbc/
assert_file "config/database.yml", /mssql/
assert_gem "activerecord-jdbc-adapter"
@@ -742,7 +804,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
template
end
- sequence = ["git init", "install", "exec spring binstub --all", "echo ran after_bundle"]
+ sequence = ["git init", "install", "exec spring binstub --all", "active_storage:install", "echo ran after_bundle"]
@sequence_step ||= 0
ensure_bundler_first = -> command, options = nil do
assert_equal sequence[@sequence_step], command, "commands should be called in sequence #{sequence}"
@@ -752,12 +814,14 @@ class AppGeneratorTest < Rails::Generators::TestCase
generator([destination_root], template: path).stub(:open, check_open, template) do
generator.stub(:bundle_command, ensure_bundler_first) do
generator.stub(:run, ensure_bundler_first) do
- quietly { generator.invoke_all }
+ generator.stub(:rails_command, ensure_bundler_first) do
+ quietly { generator.invoke_all }
+ end
end
end
end
- assert_equal 4, @sequence_step
+ assert_equal 5, @sequence_step
end
def test_system_tests_directory_generated
diff --git a/railties/test/generators/named_base_test.rb b/railties/test/generators/named_base_test.rb
index 967754c813..4e61b660d7 100644
--- a/railties/test/generators/named_base_test.rb
+++ b/railties/test/generators/named_base_test.rb
@@ -33,6 +33,17 @@ class NamedBaseTest < Rails::Generators::TestCase
assert_name g, "foos", :plural_name
assert_name g, "admin.foo", :i18n_scope
assert_name g, "admin_foos", :table_name
+ assert_name g, "admin/foos", :controller_name
+ assert_name g, %w(admin), :controller_class_path
+ assert_name g, "Admin::Foos", :controller_class_name
+ assert_name g, "admin/foos", :controller_file_path
+ assert_name g, "foos", :controller_file_name
+ assert_name g, "admin.foos", :controller_i18n_scope
+ assert_name g, "admin_foo", :singular_route_name
+ assert_name g, "admin_foos", :plural_route_name
+ assert_name g, "@admin_foo", :redirect_resource_name
+ assert_name g, "admin_foo", :model_resource_name
+ assert_name g, "admin_foos", :index_helper
end
def test_named_generator_attributes_as_ruby
@@ -47,6 +58,17 @@ class NamedBaseTest < Rails::Generators::TestCase
assert_name g, "foos", :plural_name
assert_name g, "admin.foo", :i18n_scope
assert_name g, "admin_foos", :table_name
+ assert_name g, "Admin::Foos", :controller_name
+ assert_name g, %w(admin), :controller_class_path
+ assert_name g, "Admin::Foos", :controller_class_name
+ assert_name g, "admin/foos", :controller_file_path
+ assert_name g, "foos", :controller_file_name
+ assert_name g, "admin.foos", :controller_i18n_scope
+ assert_name g, "admin_foo", :singular_route_name
+ assert_name g, "admin_foos", :plural_route_name
+ assert_name g, "@admin_foo", :redirect_resource_name
+ assert_name g, "admin_foo", :model_resource_name
+ assert_name g, "admin_foos", :index_helper
end
def test_named_generator_attributes_without_pluralized
diff --git a/railties/test/generators/plugin_generator_test.rb b/railties/test/generators/plugin_generator_test.rb
index 38130ceb68..06d223e26d 100644
--- a/railties/test/generators/plugin_generator_test.rb
+++ b/railties/test/generators/plugin_generator_test.rb
@@ -230,7 +230,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase
end
def test_ensure_that_tests_work
- run_generator
+ run_generator [destination_root, "--skip-active-storage"]
FileUtils.cd destination_root
quietly { system "bundle install" }
assert_match(/1 runs, 1 assertions, 0 failures, 0 errors/, `bin/test 2>&1`)
@@ -240,8 +240,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase
run_generator [destination_root, "--full", "--skip_active_record"]
FileUtils.cd destination_root
quietly { system "bundle install" }
- # FIXME: Active Storage will provoke a test error without ActiveRecord (fix by allowing to skip active storage)
- assert_match(/1 runs, 0 assertions, 0 failures, 1 errors/, `bundle exec rake test 2>&1`)
+ assert_match(/1 runs, 1 assertions, 0 failures, 0 errors/, `bundle exec rake test 2>&1`)
end
def test_ensure_that_migration_tasks_work_with_mountable_option
diff --git a/railties/test/generators/plugin_test_runner_test.rb b/railties/test/generators/plugin_test_runner_test.rb
index 89c3f1e496..48a3bcadcd 100644
--- a/railties/test/generators/plugin_test_runner_test.rb
+++ b/railties/test/generators/plugin_test_runner_test.rb
@@ -7,7 +7,7 @@ class PluginTestRunnerTest < ActiveSupport::TestCase
def setup
@destination_root = Dir.mktmpdir("bukkits")
- Dir.chdir(@destination_root) { `bundle exec rails plugin new bukkits --skip-bundle` }
+ Dir.chdir(@destination_root) { `bundle exec rails plugin new bukkits --skip-bundle --skip-active-storage` }
plugin_file "test/dummy/db/schema.rb", ""
end
diff --git a/railties/test/generators/scaffold_controller_generator_test.rb b/railties/test/generators/scaffold_controller_generator_test.rb
index 513b037043..fd5aa817b4 100644
--- a/railties/test/generators/scaffold_controller_generator_test.rb
+++ b/railties/test/generators/scaffold_controller_generator_test.rb
@@ -207,6 +207,7 @@ class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase
Dir.chdir(engine_path) do
quietly { `bin/rails g controller dashboard foo` }
+ quietly { `bin/rails db:migrate RAILS_ENV=test` }
assert_match(/2 runs, 2 assertions, 0 failures, 0 errors/, `bin/rails test 2>&1`)
end
end
@@ -218,6 +219,7 @@ class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase
Dir.chdir(engine_path) do
quietly { `bin/rails g controller dashboard foo` }
+ quietly { `bin/rails db:migrate RAILS_ENV=test` }
assert_match(/2 runs, 2 assertions, 0 failures, 0 errors/, `bin/rails test 2>&1`)
end
end
diff --git a/railties/test/generators/scaffold_generator_test.rb b/railties/test/generators/scaffold_generator_test.rb
index 03322c1c59..b6294c3b94 100644
--- a/railties/test/generators/scaffold_generator_test.rb
+++ b/railties/test/generators/scaffold_generator_test.rb
@@ -282,7 +282,14 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase
/class Admin::RolesTest < ApplicationSystemTestCase/
# Views
- %w(index edit new show _form).each do |view|
+ assert_file "app/views/admin/roles/index.html.erb" do |content|
+ assert_match("'Show', admin_role", content)
+ assert_match("'Edit', edit_admin_role_path(admin_role)", content)
+ assert_match("'Destroy', admin_role", content)
+ assert_match("'New Admin Role', new_admin_role_path", content)
+ end
+
+ %w(edit new show _form).each do |view|
assert_file "app/views/admin/roles/#{view}.html.erb"
end
assert_no_file "app/views/layouts/admin/roles.html.erb"
diff --git a/railties/test/generators/shared_generator_tests.rb b/railties/test/generators/shared_generator_tests.rb
index 654d16de65..ed09847443 100644
--- a/railties/test/generators/shared_generator_tests.rb
+++ b/railties/test/generators/shared_generator_tests.rb
@@ -63,7 +63,7 @@ module SharedGeneratorTests
end
def test_shebang_is_added_to_rails_file
- run_generator [destination_root, "--ruby", "foo/bar/baz", "--full"]
+ run_generator [destination_root, "--ruby", "foo/bar/baz", "--full", "--skip-active-storage"]
assert_file "bin/rails", /#!foo\/bar\/baz/
end
@@ -129,13 +129,26 @@ module SharedGeneratorTests
end
def test_default_frameworks_are_required_when_others_are_removed
- run_generator [destination_root, "--skip-active-record", "--skip-action-mailer", "--skip-action-cable", "--skip-sprockets"]
- assert_file "#{application_path}/config/application.rb", /require\s+["']rails["']/
- assert_file "#{application_path}/config/application.rb", /require\s+["']active_model\/railtie["']/
- assert_file "#{application_path}/config/application.rb", /require\s+["']active_job\/railtie["']/
- assert_file "#{application_path}/config/application.rb", /require\s+["']action_controller\/railtie["']/
- assert_file "#{application_path}/config/application.rb", /require\s+["']action_view\/railtie["']/
- assert_file "#{application_path}/config/application.rb", /require\s+["']active_storage\/engine["']/
+ run_generator [
+ destination_root,
+ "--skip-active-record",
+ "--skip-active-storage",
+ "--skip-action-mailer",
+ "--skip-action-cable",
+ "--skip-sprockets"
+ ]
+
+ assert_file "#{application_path}/config/application.rb", /^require\s+["']rails["']/
+ assert_file "#{application_path}/config/application.rb", /^require\s+["']active_model\/railtie["']/
+ assert_file "#{application_path}/config/application.rb", /^require\s+["']active_job\/railtie["']/
+ assert_file "#{application_path}/config/application.rb", /^# require\s+["']active_record\/railtie["']/
+ assert_file "#{application_path}/config/application.rb", /^# require\s+["']active_storage\/engine["']/
+ assert_file "#{application_path}/config/application.rb", /^require\s+["']action_controller\/railtie["']/
+ assert_file "#{application_path}/config/application.rb", /^# require\s+["']action_mailer\/railtie["']/
+ assert_file "#{application_path}/config/application.rb", /^require\s+["']action_view\/railtie["']/
+ assert_file "#{application_path}/config/application.rb", /^# require\s+["']action_cable\/engine["']/
+ assert_file "#{application_path}/config/application.rb", /^# require\s+["']sprockets\/railtie["']/
+ assert_file "#{application_path}/config/application.rb", /^require\s+["']rails\/test_unit\/railtie["']/
end
def test_generator_without_skips
@@ -189,6 +202,97 @@ module SharedGeneratorTests
end
end
+ def test_generator_for_active_storage
+ run_generator
+
+ assert_file "#{application_path}/app/assets/javascripts/application.js" do |content|
+ assert_match(/^\/\/= require activestorage/, content)
+ end
+
+ assert_file "#{application_path}/config/environments/development.rb" do |content|
+ assert_match(/config\.active_storage/, content)
+ end
+
+ assert_file "#{application_path}/config/environments/production.rb" do |content|
+ assert_match(/config\.active_storage/, content)
+ end
+
+ assert_file "#{application_path}/config/environments/test.rb" do |content|
+ assert_match(/config\.active_storage/, content)
+ end
+
+ assert_file "#{application_path}/config/storage.yml"
+ assert_directory "#{application_path}/db/migrate"
+ assert_directory "#{application_path}/storage"
+ assert_directory "#{application_path}/tmp/storage"
+
+ assert_file ".gitignore" do |content|
+ assert_match(/\/storage\//, content)
+ end
+ end
+
+ def test_generator_if_skip_active_storage_is_given
+ run_generator [destination_root, "--skip-active-storage"]
+
+ assert_file "#{application_path}/config/application.rb", /#\s+require\s+["']active_storage\/engine["']/
+
+ assert_file "#{application_path}/app/assets/javascripts/application.js" do |content|
+ assert_no_match(/^\/\/= require activestorage/, content)
+ end
+
+ assert_file "#{application_path}/config/environments/development.rb" do |content|
+ assert_no_match(/config\.active_storage/, content)
+ end
+
+ assert_file "#{application_path}/config/environments/production.rb" do |content|
+ assert_no_match(/config\.active_storage/, content)
+ end
+
+ assert_file "#{application_path}/config/environments/test.rb" do |content|
+ assert_no_match(/config\.active_storage/, content)
+ end
+
+ assert_no_file "#{application_path}/config/storage.yml"
+ assert_no_directory "#{application_path}/db/migrate"
+ assert_no_directory "#{application_path}/storage"
+ assert_no_directory "#{application_path}/tmp/storage"
+
+ assert_file ".gitignore" do |content|
+ assert_no_match(/\/storage\//, content)
+ end
+ end
+
+ def test_generator_does_not_generate_active_storage_contents_if_skip_active_record_is_given
+ run_generator [destination_root, "--skip-active-record"]
+
+ assert_file "#{application_path}/config/application.rb", /#\s+require\s+["']active_storage\/engine["']/
+
+ assert_file "#{application_path}/app/assets/javascripts/application.js" do |content|
+ assert_no_match(/^\/\/= require activestorage/, content)
+ end
+
+ assert_file "#{application_path}/config/environments/development.rb" do |content|
+ assert_no_match(/config\.active_storage/, content)
+ end
+
+ assert_file "#{application_path}/config/environments/production.rb" do |content|
+ assert_no_match(/config\.active_storage/, content)
+ end
+
+ assert_file "#{application_path}/config/environments/test.rb" do |content|
+ assert_no_match(/config\.active_storage/, content)
+ end
+
+ assert_no_file "#{application_path}/config/storage.yml"
+ assert_no_directory "#{application_path}/db/migrate"
+ assert_no_directory "#{application_path}/storage"
+ assert_no_directory "#{application_path}/tmp/storage"
+
+ assert_file ".gitignore" do |content|
+ assert_no_match(/\/storage\//, content)
+ end
+ end
+
def test_generator_if_skip_action_mailer_is_given
run_generator [destination_root, "--skip-action-mailer"]
assert_file "#{application_path}/config/application.rb", /#\s+require\s+["']action_mailer\/railtie["']/
diff --git a/railties/test/generators/test_runner_in_engine_test.rb b/railties/test/generators/test_runner_in_engine_test.rb
index 0e15b5e388..2acd96ecd4 100644
--- a/railties/test/generators/test_runner_in_engine_test.rb
+++ b/railties/test/generators/test_runner_in_engine_test.rb
@@ -7,7 +7,7 @@ class TestRunnerInEngineTest < ActiveSupport::TestCase
def setup
@destination_root = Dir.mktmpdir("bukkits")
- Dir.chdir(@destination_root) { `bundle exec rails plugin new bukkits --full --skip-bundle` }
+ Dir.chdir(@destination_root) { `bundle exec rails plugin new bukkits --full --skip-bundle --skip-active-storage` }
plugin_file "test/dummy/db/schema.rb", ""
end
diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb
index 29daaacdb2..7522237a38 100644
--- a/railties/test/isolation/abstract_unit.rb
+++ b/railties/test/isolation/abstract_unit.rb
@@ -153,6 +153,7 @@ module TestHelpers
def teardown_app
ENV["RAILS_ENV"] = @prev_rails_env if @prev_rails_env
+ FileUtils.rm_rf(tmp_path)
end
# Make a very basic app, without creating the whole directory structure.
diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb
index e6964b4b18..132b3b3a6e 100644
--- a/railties/test/railties/engine_test.rb
+++ b/railties/test/railties/engine_test.rb
@@ -32,6 +32,11 @@ module RailtiesTest
require "#{app_path}/config/environment"
end
+ def migrations
+ migration_root = File.expand_path(ActiveRecord::Migrator.migrations_paths.first, app_path)
+ ActiveRecord::Migrator.migrations(migration_root)
+ end
+
test "serving sprocket's assets" do
@plugin.write "app/assets/javascripts/engine.js.erb", "<%= :alert %>();"
add_to_env_config "development", "config.assets.digest = false"
@@ -82,31 +87,30 @@ module RailtiesTest
end
RUBY
- add_to_config "ActiveRecord::Base.timestamped_migrations = false"
-
boot_rails
Dir.chdir(app_path) do
output = `bundle exec rake bukkits:install:migrations`
- assert File.exist?("#{app_path}/db/migrate/2_create_users.bukkits.rb")
- assert File.exist?("#{app_path}/db/migrate/3_add_last_name_to_users.bukkits.rb")
- assert_match(/Copied migration 2_create_users\.bukkits\.rb from bukkits/, output)
- assert_match(/Copied migration 3_add_last_name_to_users\.bukkits\.rb from bukkits/, output)
- assert_match(/NOTE: Migration 3_create_sessions\.rb from bukkits has been skipped/, output)
- assert_equal 3, Dir["#{app_path}/db/migrate/*.rb"].length
+ ["CreateUsers", "AddLastNameToUsers", "CreateSessions"].each do |migration_name|
+ assert migrations.detect { |migration| migration.name == migration_name }
+ end
+ assert_match(/Copied migration \d+_create_users\.bukkits\.rb from bukkits/, output)
+ assert_match(/Copied migration \d+_add_last_name_to_users\.bukkits\.rb from bukkits/, output)
+ assert_match(/NOTE: Migration \d+_create_sessions\.rb from bukkits has been skipped/, output)
- output = `bundle exec rake railties:install:migrations`.split("\n")
+ migrations_count = Dir["#{app_path}/db/migrate/*.rb"].length
- assert_no_match(/2_create_users/, output.join("\n"))
+ assert_equal migrations.length, migrations_count
- bukkits_migration_order = output.index(output.detect { |o| /NOTE: Migration 3_create_sessions\.rb from bukkits has been skipped/ =~ o })
- assert_not_nil bukkits_migration_order, "Expected migration to be skipped"
-
- migrations_count = Dir["#{app_path}/db/migrate/*.rb"].length
- `bundle exec rake railties:install:migrations`
+ output = `bundle exec rake railties:install:migrations`.split("\n")
assert_equal migrations_count, Dir["#{app_path}/db/migrate/*.rb"].length
+
+ assert_no_match(/\d+_create_users/, output.join("\n"))
+
+ bukkits_migration_order = output.index(output.detect { |o| /NOTE: Migration \d+_create_sessions\.rb from bukkits has been skipped/ =~ o })
+ assert_not_nil bukkits_migration_order, "Expected migration to be skipped"
end
end
@@ -173,8 +177,8 @@ module RailtiesTest
Dir.chdir(app_path) do
output = `bundle exec rake railties:install:migrations`.split("\n")
- assert_match(/Copied migration \d+_create_users\.core_engine\.rb from core_engine/, output.second)
- assert_match(/Copied migration \d+_create_keys\.api_engine\.rb from api_engine/, output.last)
+ assert_match(/Copied migration \d+_create_users\.core_engine\.rb from core_engine/, output.first)
+ assert_match(/Copied migration \d+_create_keys\.api_engine\.rb from api_engine/, output.second)
end
end
@@ -203,9 +207,12 @@ module RailtiesTest
Dir.chdir(@plugin.path) do
output = `bundle exec rake app:bukkits:install:migrations`
- assert File.exist?("#{app_path}/db/migrate/0_add_first_name_to_users.bukkits.rb")
- assert_match(/Copied migration 0_add_first_name_to_users\.bukkits\.rb from bukkits/, output)
- assert_equal 1, Dir["#{app_path}/db/migrate/*.rb"].length
+
+ migration_with_engine_path = migrations.detect { |migration| migration.name == "AddFirstNameToUsers" }
+ assert migration_with_engine_path
+ assert_match(/\/db\/migrate\/\d+_add_first_name_to_users\.bukkits\.rb/, migration_with_engine_path.filename)
+ assert_match(/Copied migration \d+_add_first_name_to_users\.bukkits\.rb from bukkits/, output)
+ assert_equal migrations.length, Dir["#{app_path}/db/migrate/*.rb"].length
end
end