diff options
Diffstat (limited to 'railties')
92 files changed, 1088 insertions, 233 deletions
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index 7bc7391f9e..cfb30719da 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,3 +1,5 @@ +* Support using environment variable to set pidfile + *Ben Thorner* Please check [6-0-stable](https://github.com/rails/rails/blob/6-0-stable/railties/CHANGELOG.md) for previous changes. diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb index 1f533a8c04..440d2953c3 100644 --- a/railties/lib/rails.rb +++ b/railties/lib/rails.rb @@ -5,7 +5,6 @@ require "rails/ruby_version_check" require "pathname" require "active_support" -require "active_support/dependencies/autoload" require "active_support/core_ext/kernel/reporting" require "active_support/core_ext/module/delegation" require "active_support/core_ext/array/extract_options" diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 038284ebdd..cbaab6cc33 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -270,7 +270,9 @@ module Rails "action_dispatch.use_cookies_with_metadata" => config.action_dispatch.use_cookies_with_metadata, "action_dispatch.content_security_policy" => config.content_security_policy, "action_dispatch.content_security_policy_report_only" => config.content_security_policy_report_only, - "action_dispatch.content_security_policy_nonce_generator" => config.content_security_policy_nonce_generator + "action_dispatch.content_security_policy_nonce_generator" => config.content_security_policy_nonce_generator, + "action_dispatch.content_security_policy_nonce_directives" => config.content_security_policy_nonce_directives, + "action_dispatch.feature_policy" => config.feature_policy, ) end end @@ -501,7 +503,6 @@ module Rails end protected - alias :build_middleware_stack :app def run_tasks_blocks(app) #:nodoc: @@ -581,7 +582,6 @@ module Rails end private - def generate_development_secret if secrets.secret_key_base.nil? key_file = Rails.root.join("tmp/development_secret.txt") @@ -623,7 +623,6 @@ module Rails end private - def convert_key(key) unless key.kind_of?(Symbol) ActiveSupport::Deprecation.warn(<<~MESSAGE.squish) diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb index e3c0759f95..1fdc7b2d71 100644 --- a/railties/lib/rails/application/bootstrap.rb +++ b/railties/lib/rails/application/bootstrap.rb @@ -19,14 +19,14 @@ module Rails initializer :set_eager_load, group: :all do if config.eager_load.nil? - warn <<-INFO -config.eager_load is set to nil. Please update your config/environments/*.rb files accordingly: + warn <<~INFO + config.eager_load is set to nil. Please update your config/environments/*.rb files accordingly: - * development - set it to false - * test - set it to false (unless you use a tool that preloads your test environment) - * production - set it to true + * development - set it to false + * test - set it to false (unless you use a tool that preloads your test environment) + * production - set it to true -INFO + INFO config.eager_load = config.cache_classes end end @@ -34,20 +34,12 @@ INFO # Initialize the logger early in the stack in case we need to log some deprecation. initializer :initialize_logger, group: :all do Rails.logger ||= config.logger || begin - path = config.paths["log"].first - unless File.exist? File.dirname path - FileUtils.mkdir_p File.dirname path - end - - f = File.open path, "a" - f.binmode - f.sync = config.autoflush_log # if true make sure every write flushes - - logger = ActiveSupport::Logger.new f + logger = ActiveSupport::Logger.new(config.default_log_file) logger.formatter = config.log_formatter logger = ActiveSupport::TaggedLogging.new(logger) logger rescue StandardError + path = config.paths["log"].first logger = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new(STDERR)) logger.level = ActiveSupport::Logger::WARN logger.warn( diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index 0b758dd3dd..934578e9f1 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -18,8 +18,8 @@ module Rails :session_options, :time_zone, :reload_classes_only_on_change, :beginning_of_week, :filter_redirect, :x, :enable_dependency_loading, :read_encrypted_secrets, :log_level, :content_security_policy_report_only, - :content_security_policy_nonce_generator, :require_master_key, :credentials, - :disable_sandbox, :add_autoload_paths_to_load_path + :content_security_policy_nonce_generator, :content_security_policy_nonce_directives, + :require_master_key, :credentials, :disable_sandbox, :add_autoload_paths_to_load_path attr_reader :encoding, :api_only, :loaded_config_version, :autoloader @@ -60,6 +60,7 @@ module Rails @content_security_policy = nil @content_security_policy_report_only = false @content_security_policy_nonce_generator = nil + @content_security_policy_nonce_directives = nil @require_master_key = false @loaded_config_version = nil @credentials = ActiveSupport::OrderedOptions.new @@ -68,6 +69,7 @@ module Rails @autoloader = :classic @disable_sandbox = false @add_autoload_paths_to_load_path = true + @feature_policy = nil end def load_defaults(target_version) @@ -129,6 +131,7 @@ module Rails if respond_to?(:action_dispatch) action_dispatch.use_cookies_with_metadata = true + action_dispatch.return_only_media_type_on_content_type = false end if respond_to?(:action_mailer) @@ -142,6 +145,8 @@ module Rails if respond_to?(:active_storage) active_storage.queues.analysis = :active_storage_analysis active_storage.queues.purge = :active_storage_purge + + active_storage.replace_on_assign_to_many = true end if respond_to?(:active_record) @@ -207,7 +212,7 @@ module Rails yaml = Pathname.new(path) erb = DummyERB.new(yaml.read) - YAML.load(erb.result) + YAML.load(erb.result) || {} else {} end @@ -299,6 +304,14 @@ module Rails end end + def feature_policy(&block) + if block_given? + @feature_policy = ActionDispatch::FeaturePolicy.new(&block) + else + @feature_policy + end + end + def autoloader=(autoloader) case autoloader when :classic @@ -311,6 +324,18 @@ module Rails end end + def default_log_file + path = paths["log"].first + unless File.exist? File.dirname path + FileUtils.mkdir_p File.dirname path + end + + f = File.open path, "a" + f.binmode + f.sync = autoflush_log # if true make sure every write flushes + f + end + class Custom #:nodoc: def initialize @configurations = Hash.new diff --git a/railties/lib/rails/application/default_middleware_stack.rb b/railties/lib/rails/application/default_middleware_stack.rb index 9800b19274..572f51fca2 100644 --- a/railties/lib/rails/application/default_middleware_stack.rb +++ b/railties/lib/rails/application/default_middleware_stack.rb @@ -68,6 +68,7 @@ module Rails unless config.api_only middleware.use ::ActionDispatch::ContentSecurityPolicy::Middleware + middleware.use ::ActionDispatch::FeaturePolicy::Middleware end middleware.use ::Rack::Head @@ -79,7 +80,6 @@ module Rails end private - def load_rack_cache rack_cache = config.action_dispatch.rack_cache return unless rack_cache diff --git a/railties/lib/rails/application/dummy_erb_compiler.rb b/railties/lib/rails/application/dummy_erb_compiler.rb index c4659123bb..028e790292 100644 --- a/railties/lib/rails/application/dummy_erb_compiler.rb +++ b/railties/lib/rails/application/dummy_erb_compiler.rb @@ -11,9 +11,8 @@ end class DummyCompiler < ERB::Compiler # :nodoc: def compile_content(stag, out) - case stag - when "<%=" - out.push "_erbout << 'dummy_compiler'" + if stag == "<%=" + out.push "_erbout << ''" end end end diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index 109c560c80..9f4009ad20 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -39,8 +39,14 @@ module Rails example = autoloaded.first example_klass = example.constantize.class - ActiveSupport::DescendantsTracker.clear - ActiveSupport::Dependencies.clear + if config.autoloader == :zeitwerk + ActiveSupport::DescendantsTracker.clear + ActiveSupport::Dependencies.clear + + unload_message = "#{these} autoloaded #{constants} #{have} been unloaded." + else + unload_message = "`config.autoloader` is set to `#{config.autoloader}`. #{these} autoloaded #{constants} would have been unloaded if `config.autoloader` had been set to `:zeitwerk`." + end ActiveSupport::Deprecation.warn(<<~WARNING) Initialization autoloaded the #{constants} #{enum}. @@ -52,7 +58,7 @@ module Rails initialization does not run again. So, if you reload #{example}, for example, the expected changes won't be reflected in that stale #{example_klass} object. - #{these} autoloaded #{constants} #{have} been unloaded. + #{unload_message} Please, check the "Autoloading and Reloading Constants" guide for solutions. WARNING diff --git a/railties/lib/rails/application/routes_reloader.rb b/railties/lib/rails/application/routes_reloader.rb index 3ecb8e264e..1070362253 100644 --- a/railties/lib/rails/application/routes_reloader.rb +++ b/railties/lib/rails/application/routes_reloader.rb @@ -25,7 +25,6 @@ module Rails end private - def updater @updater ||= ActiveSupport::FileUpdateChecker.new(paths) { reload! } end diff --git a/railties/lib/rails/application_controller.rb b/railties/lib/rails/application_controller.rb index b3fe822218..8c00633515 100644 --- a/railties/lib/rails/application_controller.rb +++ b/railties/lib/rails/application_controller.rb @@ -12,7 +12,6 @@ class Rails::ApplicationController < ActionController::Base # :nodoc: end private - def require_local! unless local_request? render html: "<p>For security purposes, this information is only available to local requests.</p>".html_safe, status: :forbidden diff --git a/railties/lib/rails/code_statistics.rb b/railties/lib/rails/code_statistics.rb index 09082282f3..aa5c0d0b5b 100644 --- a/railties/lib/rails/code_statistics.rb +++ b/railties/lib/rails/code_statistics.rb @@ -44,7 +44,7 @@ class CodeStatistics #:nodoc: Dir.foreach(directory) do |file_name| path = "#{directory}/#{file_name}" - if File.directory?(path) && (/^\./ !~ file_name) + if File.directory?(path) && !(/^\./.match?(file_name)) stats.add(calculate_directory_statistics(path, pattern)) elsif file_name&.match?(pattern) stats.add_by_file_path(path) diff --git a/railties/lib/rails/code_statistics_calculator.rb b/railties/lib/rails/code_statistics_calculator.rb index 85f86bdbd0..8dd415d9d1 100644 --- a/railties/lib/rails/code_statistics_calculator.rb +++ b/railties/lib/rails/code_statistics_calculator.rb @@ -58,20 +58,20 @@ class CodeStatisticsCalculator #:nodoc: @lines += 1 if comment_started - if patterns[:end_block_comment] && line =~ patterns[:end_block_comment] + if patterns[:end_block_comment] && patterns[:end_block_comment].match?(line) comment_started = false end next else - if patterns[:begin_block_comment] && line =~ patterns[:begin_block_comment] + if patterns[:begin_block_comment] && patterns[:begin_block_comment].match?(line) comment_started = true next end end - @classes += 1 if patterns[:class] && line =~ patterns[:class] - @methods += 1 if patterns[:method] && line =~ patterns[:method] - if line !~ /^\s*$/ && (patterns[:line_comment].nil? || line !~ patterns[:line_comment]) + @classes += 1 if patterns[:class] && patterns[:class].match?(line) + @methods += 1 if patterns[:method] && patterns[:method].match?(line) + if !line.match?(/^\s*$/) && (patterns[:line_comment].nil? || !line.match?(patterns[:line_comment])) @code_lines += 1 end end diff --git a/railties/lib/rails/command.rb b/railties/lib/rails/command.rb index f09aa3ae0d..7e6e968c92 100644 --- a/railties/lib/rails/command.rb +++ b/railties/lib/rails/command.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require "active_support" -require "active_support/dependencies/autoload" require "active_support/core_ext/enumerable" require "active_support/core_ext/object/blank" diff --git a/railties/lib/rails/command/base.rb b/railties/lib/rails/command/base.rb index a22b198c66..415bab199f 100644 --- a/railties/lib/rails/command/base.rb +++ b/railties/lib/rails/command/base.rb @@ -52,7 +52,7 @@ module Rails def inherited(base) #:nodoc: super - if base.name && base.name !~ /Base$/ + if base.name && !base.name.match?(/Base$/) Rails::Command.subclasses << base end end diff --git a/railties/lib/rails/command/behavior.rb b/railties/lib/rails/command/behavior.rb index 7fb2a99e67..90650059f4 100644 --- a/railties/lib/rails/command/behavior.rb +++ b/railties/lib/rails/command/behavior.rb @@ -44,7 +44,7 @@ module Rails require path return rescue LoadError => e - raise unless e.message =~ /#{Regexp.escape(path)}$/ + raise unless /#{Regexp.escape(path)}$/.match?(e.message) rescue Exception => e warn "[WARNING] Could not load #{command_type} #{path.inspect}. Error: #{e.message}.\n#{e.backtrace.join("\n")}" end diff --git a/railties/lib/rails/command/environment_argument.rb b/railties/lib/rails/command/environment_argument.rb index 9945fd1430..df3cc1b2bb 100644 --- a/railties/lib/rails/command/environment_argument.rb +++ b/railties/lib/rails/command/environment_argument.rb @@ -28,7 +28,7 @@ module Rails if available_environments.include? env env else - %w( production development test ).detect { |e| e =~ /^#{env}/ } || env + %w( production development test ).detect { |e| /^#{env}/.match?(e) } || env end end diff --git a/railties/lib/rails/command/helpers/pretty_credentials.rb b/railties/lib/rails/command/helpers/pretty_credentials.rb new file mode 100644 index 0000000000..873ed0e825 --- /dev/null +++ b/railties/lib/rails/command/helpers/pretty_credentials.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require "fileutils" + +module Rails + module Command + module Helpers + module PrettyCredentials + Error = Class.new(StandardError) + + def opt_in_pretty_credentials + unless already_answered? || already_opted_in? + answer = yes?("Would you like to make the credentials diff from git more readable in the future? [Y/n]") + end + + opt_in! if answer + FileUtils.touch(tracker) unless answer.nil? + rescue Error + say("Couldn't setup git to prettify the credentials diff") + end + + private + def already_answered? + tracker.exist? + end + + def already_opted_in? + system_call("git config --get 'diff.rails_credentials.textconv'", accepted_codes: [0, 1]) + end + + def opt_in! + system_call("git config diff.rails_credentials.textconv 'bin/rails credentials:show'", accepted_codes: [0]) + + git_attributes = Rails.root.join(".gitattributes") + File.open(git_attributes, "a+") do |file| + file.write(<<~EOM) + config/credentials/*.yml.enc diff=rails_credentials + config/credentials.yml.enc diff=rails_credentials + EOM + end + end + + def tracker + Rails.root.join("tmp", "rails_pretty_credentials") + end + + def system_call(command_line, accepted_codes:) + result = system(command_line) + raise(Error) if accepted_codes.exclude?($?.exitstatus) + result + end + end + end + end +end diff --git a/railties/lib/rails/command/spellchecker.rb b/railties/lib/rails/command/spellchecker.rb index 085d5b16df..c5d0253185 100644 --- a/railties/lib/rails/command/spellchecker.rb +++ b/railties/lib/rails/command/spellchecker.rb @@ -13,7 +13,6 @@ module Rails end private - # This code is based directly on the Text gem implementation. # Copyright (c) 2006-2013 Paul Battley, Michael Neumann, Tim Fletcher. # diff --git a/railties/lib/rails/commands/credentials/credentials_command.rb b/railties/lib/rails/commands/credentials/credentials_command.rb index e23a1b3008..772e105007 100644 --- a/railties/lib/rails/commands/credentials/credentials_command.rb +++ b/railties/lib/rails/commands/credentials/credentials_command.rb @@ -2,12 +2,15 @@ require "active_support" require "rails/command/helpers/editor" +require "rails/command/helpers/pretty_credentials" require "rails/command/environment_argument" +require "pathname" module Rails module Command class CredentialsCommand < Rails::Command::Base # :nodoc: include Helpers::Editor + include Helpers::PrettyCredentials include EnvironmentArgument self.environment_desc = "Uses credentials from config/credentials/:environment.yml.enc encrypted by config/credentials/:environment.key key" @@ -34,20 +37,29 @@ module Rails end say "File encrypted and saved." + opt_in_pretty_credentials rescue ActiveSupport::MessageEncryptor::InvalidMessage say "Couldn't decrypt #{content_path}. Perhaps you passed the wrong key?" end - def show - extract_environment_option_from_argument(default_environment: nil) + def show(git_textconv_path = nil) + if git_textconv_path + default_environment = extract_environment_from_path(git_textconv_path) + fallback_message = File.read(git_textconv_path) + end + + extract_environment_option_from_argument(default_environment: default_environment) require_application! - say credentials.read.presence || missing_credentials_message + say credentials(git_textconv_path).read.presence || fallback_message || missing_credentials_message + rescue => e + raise(e) unless git_textconv_path + fallback_message end private - def credentials - Rails.application.encrypted(content_path, key_path: key_path) + def credentials(content = nil) + Rails.application.encrypted(content || content_path, key_path: key_path) end def ensure_encryption_key_has_been_added @@ -77,7 +89,6 @@ module Rails end end - def content_path options[:environment] ? "config/credentials/#{options[:environment]}.yml.enc" : "config/credentials.yml.enc" end @@ -86,6 +97,17 @@ module Rails options[:environment] ? "config/credentials/#{options[:environment]}.key" : "config/master.key" end + def extract_environment_from_path(path) + regex = %r{ + ([A-Za-z0-9]+) # match the environment + (?<!credentials) # don't match if file contains the word "credentials" + # in such case, the environment should be the default one + \.yml\.enc # look for `.yml.enc` file extension + }x + path.match(regex) + + Regexp.last_match(1) + end def encryption_key_file_generator require "rails/generators" diff --git a/railties/lib/rails/commands/server/server_command.rb b/railties/lib/rails/commands/server/server_command.rb index 982b83ead5..84248e03c1 100644 --- a/railties/lib/rails/commands/server/server_command.rb +++ b/railties/lib/rails/commands/server/server_command.rb @@ -99,7 +99,7 @@ module Rails RACK_SERVERS = %w(cgi fastcgi webrick lsws scgi thin puma unicorn) DEFAULT_PORT = 3000 - DEFAULT_PID_PATH = "tmp/pids/server.pid" + DEFAULT_PIDFILE = "tmp/pids/server.pid" argument :using, optional: true @@ -114,8 +114,8 @@ module Rails desc: "Runs server as a Daemon." class_option :using, aliases: "-u", type: :string, desc: "Specifies the Rack server used to run the application (thin/puma/webrick).", banner: :name - class_option :pid, aliases: "-P", type: :string, default: DEFAULT_PID_PATH, - desc: "Specifies the PID file." + class_option :pid, aliases: "-P", type: :string, + desc: "Specifies the PID file - defaults to #{DEFAULT_PIDFILE}." class_option :dev_caching, aliases: "-C", type: :boolean, default: nil, desc: "Specifies whether to perform caching in development." class_option :restart, type: :boolean, default: nil, hide: true @@ -207,6 +207,7 @@ module Rails end user_supplied_options << :Host if ENV["HOST"] || ENV["BINDING"] user_supplied_options << :Port if ENV["PORT"] + user_supplied_options << :pid if ENV["PIDFILE"] user_supplied_options.uniq end end @@ -253,7 +254,7 @@ module Rails end def pid - File.expand_path(options[:pid]) + File.expand_path(options[:pid] || ENV.fetch("PIDFILE", DEFAULT_PIDFILE)) end def self.banner(*) @@ -261,7 +262,7 @@ module Rails end def prepare_restart - FileUtils.rm_f(options[:pid]) if options[:restart] + FileUtils.rm_f(pid) if options[:restart] end def deprecate_positional_rack_server_and_rewrite_to_option(original_options) diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index d1b8c7803f..b4c0028b1f 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -362,7 +362,7 @@ module Rails base.called_from = begin call_stack = caller_locations.map { |l| l.absolute_path || l.path } - File.dirname(call_stack.detect { |p| p !~ %r[railties[\w.-]*/lib/rails|rack[\w.-]*/lib/rack] }) + File.dirname(call_stack.detect { |p| !p.match?(%r[railties[\w.-]*/lib/rails|rack[\w.-]*/lib/rack]) }) end end @@ -654,14 +654,12 @@ module Rails end protected - def run_tasks_blocks(*) #:nodoc: super paths["lib/tasks"].existent.sort.each { |ext| load(ext) } end private - def load_config_initializer(initializer) # :doc: ActiveSupport::Notifications.instrument("load_config_initializer.railties", initializer: initializer) do load(initializer) diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb index 4143b3c881..612bd170c6 100644 --- a/railties/lib/rails/engine/configuration.rb +++ b/railties/lib/rails/engine/configuration.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require "rails/railtie/configuration" +require "yaml" module Rails class Engine @@ -40,7 +41,7 @@ module Rails paths.add "app", eager_load: true, glob: "{*,*/concerns}", - exclude: %w(assets javascript) + exclude: ["assets", webpacker_path] paths.add "app/assets", glob: "*" paths.add "app/controllers", eager_load: true paths.add "app/channels", eager_load: true, glob: "**/*_channel.rb" @@ -85,6 +86,14 @@ module Rails def autoload_paths @autoload_paths ||= paths.autoload_paths end + + def webpacker_path + if File.file?("#{Rails.root}/config/webpacker.yml") + YAML.load_file("#{Rails.root}/config/webpacker.yml")[Rails.env]["source_path"]&.gsub("app/", "") + else + "javascript" + end + end end end end diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb index 0be00d5151..436315ce1e 100644 --- a/railties/lib/rails/generators.rb +++ b/railties/lib/rails/generators.rb @@ -6,8 +6,6 @@ $:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.inc require "thor/group" require "rails/command" -require "active_support" -require "active_support/core_ext/object/blank" require "active_support/core_ext/kernel/singleton_class" require "active_support/core_ext/array/extract_options" require "active_support/core_ext/hash/deep_merge" @@ -287,7 +285,6 @@ module Rails end private - def print_list(base, namespaces) # :doc: namespaces = namespaces.reject { |n| hidden_namespaces.include?(n) } super diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb index 1a5f2ff203..b6225cd8c0 100644 --- a/railties/lib/rails/generators/actions.rb +++ b/railties/lib/rails/generators/actions.rb @@ -40,8 +40,7 @@ module Rails in_root do str = "gem #{parts.join(", ")}" str = indentation + str - str = "\n" + str - append_file "Gemfile", str, verbose: false + append_file_with_newline "Gemfile", str, verbose: false end end @@ -58,9 +57,9 @@ module Rails log :gemfile, "group #{str}" in_root do - append_file "Gemfile", "\ngroup #{str} do", force: true + append_file_with_newline "Gemfile", "\ngroup #{str} do", force: true with_indentation(&block) - append_file "Gemfile", "\nend\n", force: true + append_file_with_newline "Gemfile", "end", force: true end end @@ -71,9 +70,13 @@ module Rails log :github, "github #{str}" in_root do - append_file "Gemfile", "\n#{indentation}github #{str} do", force: true + if @indentation.zero? + append_file_with_newline "Gemfile", "\ngithub #{str} do", force: true + else + append_file_with_newline "Gemfile", "#{indentation}github #{str} do", force: true + end with_indentation(&block) - append_file "Gemfile", "\n#{indentation}end", force: true + append_file_with_newline "Gemfile", "#{indentation}end", force: true end end @@ -91,9 +94,9 @@ module Rails in_root do if block - append_file "Gemfile", "\nsource #{quote(source)} do", force: true + append_file_with_newline "Gemfile", "\nsource #{quote(source)} do", force: true with_indentation(&block) - append_file "Gemfile", "\nend\n", force: true + append_file_with_newline "Gemfile", "end", force: true else prepend_file "Gemfile", "source #{quote(source)}\n", verbose: false end @@ -268,7 +271,6 @@ module Rails end private - # Define log for backwards compatibility. If just one argument is sent, # invoke say, otherwise invoke say_status. Differently from say and # similarly to say_status, this method respects the quiet? option given. @@ -345,6 +347,13 @@ module Rails ensure @indentation -= 1 end + + # Append string to a file with a newline if necessary + def append_file_with_newline(path, str, options = {}) + gsub_file path, /\n?\z/, options do |match| + match.end_with?("\n") ? "" : "\n#{str}\n" + end + end end end end diff --git a/railties/lib/rails/generators/actions/create_migration.rb b/railties/lib/rails/generators/actions/create_migration.rb index 05bc242447..67a8139cd3 100644 --- a/railties/lib/rails/generators/actions/create_migration.rb +++ b/railties/lib/rails/generators/actions/create_migration.rb @@ -40,7 +40,6 @@ module Rails alias :exists? :existing_migration private - def on_conflict_behavior # :doc: options = base.options.merge(config) if identical? diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index 7e3560d9d2..ed0215bda9 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -108,7 +108,6 @@ module Rails end private - def gemfile_entry(name, *args) # :doc: options = args.extract_options! version = args.first @@ -307,7 +306,7 @@ module Rails def assets_gemfile_entry return [] if options[:skip_sprockets] - GemfileEntry.version("sass-rails", "~> 5", "Use SCSS for stylesheets") + GemfileEntry.version("sass-rails", ">= 5", "Use SCSS for stylesheets") end def webpacker_gemfile_entry @@ -322,7 +321,7 @@ module Rails def jbuilder_gemfile_entry comment = "Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder" - GemfileEntry.new "jbuilder", "~> 2.5", comment, {}, options[:api] + GemfileEntry.new "jbuilder", "~> 2.7", comment, {}, options[:api] end def javascript_gemfile_entry @@ -401,7 +400,7 @@ module Rails end def os_supports_listen_out_of_the_box? - RbConfig::CONFIG["host_os"] =~ /darwin|linux/ + /darwin|linux/.match?(RbConfig::CONFIG["host_os"]) end def run_bundle diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb index 5523a3f659..1d3c947cb0 100644 --- a/railties/lib/rails/generators/base.rb +++ b/railties/lib/rails/generators/base.rb @@ -20,6 +20,8 @@ module Rails class_option :skip_namespace, type: :boolean, default: false, desc: "Skip namespace (affects only isolated applications)" + class_option :skip_collision_check, type: :boolean, default: false, + desc: "Skip collision check" add_runtime_options! strict_args_position! @@ -231,7 +233,7 @@ module Rails # Invoke source_root so the default_source_root is set. base.source_root - if base.name && base.name !~ /Base$/ + if base.name && !base.name.match?(/Base$/) Rails::Generators.subclasses << base Rails::Generators.templates_path.each do |path| @@ -245,11 +247,11 @@ module Rails end private - # Check whether the given class names are already taken by user # application or Ruby on Rails. def class_collisions(*class_names) return unless behavior == :invoke + return if options.skip_collision_check? class_names.flatten.each do |class_name| class_name = class_name.to_s @@ -262,8 +264,8 @@ module Rails if last && last.const_defined?(last_name.camelize, false) raise Error, "The name '#{class_name}' is either already used in your application " \ - "or reserved by Ruby on Rails. Please choose an alternative and run " \ - "this generator again." + "or reserved by Ruby on Rails. Please choose an alternative or use --skip-collision-check " \ + "to skip this check and run this generator again." end end end diff --git a/railties/lib/rails/generators/erb.rb b/railties/lib/rails/generators/erb.rb index ba20bcd32a..aab2d634d3 100644 --- a/railties/lib/rails/generators/erb.rb +++ b/railties/lib/rails/generators/erb.rb @@ -6,7 +6,6 @@ module Erb # :nodoc: module Generators # :nodoc: class Base < Rails::Generators::NamedBase #:nodoc: private - def formats [format] end diff --git a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb index 997602cb8c..f66be1ee44 100644 --- a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb +++ b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb @@ -29,7 +29,6 @@ module Erb # :nodoc: end private - def formats [:text, :html] end diff --git a/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb index 2fc04e4094..6d3bccab0b 100644 --- a/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb @@ -24,7 +24,6 @@ module Erb # :nodoc: end private - def available_views %w(index edit show new _form) end diff --git a/railties/lib/rails/generators/generated_attribute.rb b/railties/lib/rails/generators/generated_attribute.rb index 1a80e71eae..377a5dfc65 100644 --- a/railties/lib/rails/generators/generated_attribute.rb +++ b/railties/lib/rails/generators/generated_attribute.rb @@ -39,7 +39,6 @@ module Rails end private - # parse possible attribute options like :limit for string/text/binary/integer, :precision/:scale for decimals or :polymorphic for references/belongs_to # when declaring options curly brackets should be used def parse_type_and_options(type) @@ -132,7 +131,7 @@ module Rails end def foreign_key? - !!(name =~ /_id$/) + /_id$/.match?(name) end def reference? diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index f2f46d6e25..ea3968bf39 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -243,7 +243,9 @@ module Rails # can change in Ruby 1.8.7 when we FileUtils.cd. RAILS_DEV_PATH = File.expand_path("../../../../../..", __dir__) - class AppGenerator < AppBase # :nodoc: + class AppGenerator < AppBase + # :stopdoc: + WEBPACKS = %w( react vue angular elm stimulus ) add_shared_options_for "application" @@ -492,8 +494,9 @@ module Rails "rails new #{arguments.map(&:usage).join(' ')} [options]" end - private + # :startdoc: + private # Define file as an alias to create_file for backwards compatibility. def file(*args, &block) create_file(*args, &block) @@ -538,7 +541,6 @@ module Rails end private - def handle_version_request!(argument) if ["--version", "-v"].include?(argument) require "rails/version" diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile.tt b/railties/lib/rails/generators/rails/app/templates/Gemfile.tt index cf5462f7dc..f13dab59b1 100644 --- a/railties/lib/rails/generators/rails/app/templates/Gemfile.tt +++ b/railties/lib/rails/generators/rails/app/templates/Gemfile.tt @@ -72,7 +72,7 @@ group :test do # Easy installation and use of web drivers to run system tests with browsers gem 'webdrivers' end -<%- end -%> +<%- end -%> # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] diff --git a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt index 9a7267c783..437bf84ce3 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +++ b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt @@ -2,11 +2,12 @@ <html> <head> <title><%= camelized %></title> + <meta name="viewport" content="width=device-width,initial-scale=1"> <%%= csrf_meta_tags %> <%%= csp_meta_tag %> <%- if options[:skip_javascript] -%> - <%%= stylesheet_link_tag 'application', media: 'all' %> + <%%= stylesheet_link_tag 'application', media: 'all' %> <%- else -%> <%- unless options[:skip_turbolinks] -%> <%%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt index 371415e6a8..006b0a74c3 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt @@ -1,4 +1,4 @@ -# SQLite version 3.x +# SQLite. Versions 3.8.0 and up are supported. # gem 'activerecord-jdbcsqlite3-adapter' # # Configure Using Gemfile diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt b/railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt index 9510568124..a7c2bf2eac 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt @@ -1,4 +1,4 @@ -# SQLite version 3.x +# SQLite. Versions 3.8.0 and up are supported. # gem install sqlite3 # # Ensure the SQLite 3 gem is defined in your Gemfile diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/backtrace_silencers.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/backtrace_silencers.rb.tt index 59385cdf37..3c56b21b3c 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/backtrace_silencers.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/backtrace_silencers.rb.tt @@ -1,7 +1,7 @@ # Be sure to restart your server when you modify this file. # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. -# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } +# Rails.backtrace_cleaner.add_silencer { |line| /my_noisy_library/.match?(line) } # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. # Rails.backtrace_cleaner.remove_silencers! diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt index c517b0f96b..3d468f7633 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt @@ -23,6 +23,9 @@ # If you are using UJS then enable automatic nonce generation # Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) } +# Set the nonce only to specific directives +# Rails.application.config.content_security_policy_nonce_directives = %w(script-src) + # Report CSP violations to a specified URI # For further information see the following documentation: # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/feature_policy.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/feature_policy.rb.tt new file mode 100644 index 0000000000..a1c46695d2 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/feature_policy.rb.tt @@ -0,0 +1,11 @@ +# Define an application-wide HTTP feature policy. For further +# information see https://developers.google.com/web/updates/2018/06/feature-policy +# +# Rails.application.config.feature_policy do |f| +# f.camera :none +# f.gyroscope :none +# f.microphone :none +# f.usb :none +# f.fullscreen :self +# f.payment :self, "https://secure.example.com" +# end diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt index 4a994e1e7b..eea99edb65 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt @@ -1,4 +1,6 @@ # Be sure to restart your server when you modify this file. # Configure sensitive parameters which will be filtered from the log file. -Rails.application.config.filter_parameters += [:password] +Rails.application.config.filter_parameters += [ + :password, :secret, :token, :_key, :auth, :crypt, :salt, :certificate, :otp, :access, :private, :protected, :ssn +] diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_6_0.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_6_0.rb.tt index d25552e923..2510ab906f 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_6_0.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_6_0.rb.tt @@ -16,6 +16,9 @@ # It's best enabled when your entire app is migrated and stable on 6.0. # Rails.application.config.action_dispatch.use_cookies_with_metadata = true +# Change the return value of `ActionDispatch::Response#content_type` to Content-Type header without modification. +# Rails.application.config.action_dispatch.return_only_media_type_on_content_type = true + # Return false instead of self when enqueuing is aborted from a callback. # Rails.application.config.active_job.return_false_on_aborted_enqueue = true @@ -23,6 +26,10 @@ # Rails.application.config.active_storage.queues.analysis = :active_storage_analysis # Rails.application.config.active_storage.queues.purge = :active_storage_purge +# When assigning to a collection of attachments declared via `has_many_attached`, replace existing +# attachments instead of appending. Use #attach to add new attachments without replacing existing ones. +# Rails.application.config.active_storage.replace_on_assign_to_many = true + # Use ActionMailer::MailDeliveryJob for sending parameterized and normal mail. # # The default delivery jobs (ActionMailer::Parameterized::DeliveryJob, ActionMailer::DeliveryJob), @@ -31,3 +38,8 @@ # MailDeliveryJob to ensure all delivery jobs are processed properly. # Make sure your entire app is migrated and stable on 6.0 before using this setting. # Rails.application.config.action_mailer.delivery_job = "ActionMailer::MailDeliveryJob" + +# Enable the same cache key to be reused when the object being cached of type +# `ActiveRecord::Relation` changes by moving the volatile information (max updated at and count) +# of the relation's cache key into the cache version to support recycling cache key. +# Rails.application.config.active_record.collection_cache_versioning = true diff --git a/railties/lib/rails/generators/rails/app/templates/config/puma.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/puma.rb.tt index 649253aeca..5ed4437744 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/puma.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/puma.rb.tt @@ -16,6 +16,9 @@ port ENV.fetch("PORT") { 3000 } # environment ENV.fetch("RAILS_ENV") { "development" } +# Specifies the `pidfile` that Puma will use. +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + # Specifies the number of `workers` to boot in clustered mode. # Workers are forked web server processes. If using threads and workers together # the concurrency of the application would be max `threads` * `workers`. diff --git a/railties/lib/rails/generators/rails/app/templates/public/robots.txt b/railties/lib/rails/generators/rails/app/templates/public/robots.txt index 37b576a4a0..c19f78ab68 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/robots.txt +++ b/railties/lib/rails/generators/rails/app/templates/public/robots.txt @@ -1 +1 @@ -# See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file diff --git a/railties/lib/rails/generators/rails/controller/controller_generator.rb b/railties/lib/rails/generators/rails/controller/controller_generator.rb index eb75e7e661..88729545f3 100644 --- a/railties/lib/rails/generators/rails/controller/controller_generator.rb +++ b/railties/lib/rails/generators/rails/controller/controller_generator.rb @@ -25,7 +25,6 @@ module Rails end private - def file_name @_file_name ||= remove_possible_suffix(super) end diff --git a/railties/lib/rails/generators/rails/generator/generator_generator.rb b/railties/lib/rails/generators/rails/generator/generator_generator.rb index 747acd68d1..b0146641b4 100644 --- a/railties/lib/rails/generators/rails/generator/generator_generator.rb +++ b/railties/lib/rails/generators/rails/generator/generator_generator.rb @@ -15,7 +15,6 @@ module Rails hook_for :test_framework private - def generator_dir if options[:namespace] File.join("lib", "generators", regular_class_path, file_name) diff --git a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb index 895b3b2e92..4c18bdb430 100644 --- a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb +++ b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb @@ -269,7 +269,6 @@ task default: :test end private - def create_dummy_app(path = nil) dummy_path(path) if path diff --git a/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb b/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb index e1ca54ec91..b2cdeee6d1 100644 --- a/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb +++ b/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb @@ -34,7 +34,6 @@ module Rails end private - def permitted_params attachments, others = attributes_names.partition { |name| attachments?(name) } params = others.map { |name| ":#{name}" } diff --git a/railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb.tt b/railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb.tt index ff41fef9e9..a69a24e281 100644 --- a/railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb.tt +++ b/railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb.tt @@ -16,7 +16,7 @@ class <%= class_name %>ControllerTest < ActionDispatch::IntegrationTest get <%= url_helper_prefix %>_<%= action %>_url assert_response :success end - +<%= "\n" unless action == actions.last -%> <% end -%> <% end -%> end diff --git a/railties/lib/rails/generators/test_unit/generator/generator_generator.rb b/railties/lib/rails/generators/test_unit/generator/generator_generator.rb index 19be4f2f51..ae7e28580e 100644 --- a/railties/lib/rails/generators/test_unit/generator/generator_generator.rb +++ b/railties/lib/rails/generators/test_unit/generator/generator_generator.rb @@ -15,7 +15,6 @@ module TestUnit # :nodoc: end private - def generator_path if options[:namespace] File.join("generators", regular_class_path, file_name, "#{file_name}_generator") diff --git a/railties/lib/rails/generators/test_unit/integration/integration_generator.rb b/railties/lib/rails/generators/test_unit/integration/integration_generator.rb index ba27ed329b..86fea3f677 100644 --- a/railties/lib/rails/generators/test_unit/integration/integration_generator.rb +++ b/railties/lib/rails/generators/test_unit/integration/integration_generator.rb @@ -12,7 +12,6 @@ module TestUnit # :nodoc: end private - def file_name @_file_name ||= super.sub(/_test\z/i, "") end diff --git a/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb index 26002a0704..a4bc81cad6 100644 --- a/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb @@ -38,7 +38,6 @@ module TestUnit # :nodoc: end private - def attributes_string attributes_hash.map { |k, v| "#{k}: #{v}" }.join(", ") end diff --git a/railties/lib/rails/generators/testing/behaviour.rb b/railties/lib/rails/generators/testing/behaviour.rb index ec29ad12ba..a092faec89 100644 --- a/railties/lib/rails/generators/testing/behaviour.rb +++ b/railties/lib/rails/generators/testing/behaviour.rb @@ -88,7 +88,6 @@ module Rails end private - def destination_root_is_set? raise "You need to configure your Rails::Generators::TestCase destination root." unless destination_root end diff --git a/railties/lib/rails/info_controller.rb b/railties/lib/rails/info_controller.rb index f74d979721..d51010d422 100644 --- a/railties/lib/rails/info_controller.rb +++ b/railties/lib/rails/info_controller.rb @@ -33,7 +33,6 @@ class Rails::InfoController < Rails::ApplicationController # :nodoc: end private - def match_route _routes.routes.select { |route| yield route.path diff --git a/railties/lib/rails/paths.rb b/railties/lib/rails/paths.rb index 8367ac8980..0664338e0b 100644 --- a/railties/lib/rails/paths.rb +++ b/railties/lib/rails/paths.rb @@ -98,7 +98,6 @@ module Rails end private - def filter_by(&block) all_paths.find_all(&block).flat_map { |path| paths = path.existent @@ -223,14 +222,11 @@ module Rails alias to_a expanded private - def files_in(path) - Dir.chdir(path) do - files = Dir.glob(@glob) - files -= @exclude if @exclude - files.map! { |file| File.join(path, file) } - files.sort - end + files = Dir.glob(@glob, base: path) + files -= @exclude if @exclude + files.map! { |file| File.join(path, file) } + files.sort end end end diff --git a/railties/lib/rails/rack/logger.rb b/railties/lib/rails/rack/logger.rb index 3a95b55811..8d69663dbd 100644 --- a/railties/lib/rails/rack/logger.rb +++ b/railties/lib/rails/rack/logger.rb @@ -30,7 +30,6 @@ module Rails end private - def call_app(request, env) # :doc: instrumenter = ActiveSupport::Notifications.instrumenter instrumenter.start "request.action_dispatch", request: request diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb index a67b90e285..178c584f95 100644 --- a/railties/lib/rails/railtie.rb +++ b/railties/lib/rails/railtie.rb @@ -228,7 +228,6 @@ module Rails end protected - def run_console_blocks(app) #:nodoc: each_registered_block(:console) { |block| block.call(app) } end @@ -247,7 +246,6 @@ module Rails end private - # run `&block` in every registered block in `#register_block_for` def each_registered_block(type, &block) klass = self.class diff --git a/railties/lib/rails/railtie/configurable.rb b/railties/lib/rails/railtie/configurable.rb index 7f42fae10a..ba14089a2a 100644 --- a/railties/lib/rails/railtie/configurable.rb +++ b/railties/lib/rails/railtie/configurable.rb @@ -27,7 +27,6 @@ module Rails end private - def method_missing(*args, &block) instance.send(*args, &block) end diff --git a/railties/lib/rails/railtie/configuration.rb b/railties/lib/rails/railtie/configuration.rb index 70274b948c..c90fcac51a 100644 --- a/railties/lib/rails/railtie/configuration.rb +++ b/railties/lib/rails/railtie/configuration.rb @@ -87,7 +87,6 @@ module Rails end private - def method_missing(name, *args, &blk) if name.to_s =~ /=$/ @@options[$`.to_sym] = args.first diff --git a/railties/lib/rails/source_annotation_extractor.rb b/railties/lib/rails/source_annotation_extractor.rb index 9ce22b96a6..77a99036ec 100644 --- a/railties/lib/rails/source_annotation_extractor.rb +++ b/railties/lib/rails/source_annotation_extractor.rb @@ -2,11 +2,6 @@ require "active_support/deprecation" -# Remove this deprecated class in the next minor version -#:nodoc: -SourceAnnotationExtractor = ActiveSupport::Deprecation::DeprecatedConstantProxy. - new("SourceAnnotationExtractor", "Rails::SourceAnnotationExtractor") - module Rails # Implements the logic behind <tt>Rails::Command::NotesCommand</tt>. See <tt>rails notes --help</tt> for usage information. # @@ -160,3 +155,8 @@ module Rails end end end + +# Remove this deprecated class in the next minor version +#:nodoc: +SourceAnnotationExtractor = ActiveSupport::Deprecation::DeprecatedConstantProxy. + new("SourceAnnotationExtractor", "Rails::SourceAnnotationExtractor") diff --git a/railties/lib/rails/tasks/zeitwerk.rake b/railties/lib/rails/tasks/zeitwerk.rake index b7f5cd154b..5421af6e8b 100644 --- a/railties/lib/rails/tasks/zeitwerk.rake +++ b/railties/lib/rails/tasks/zeitwerk.rake @@ -1,78 +1,66 @@ # frozen_string_literal: true -ensure_classic_mode = ->() do - if Rails.autoloaders.zeitwerk_enabled? - abort <<~EOS - Please, enable temporarily :classic mode: - - # config/application.rb - config.autoloader = :classic - - and try again. When all is good, you can delete that line. - EOS +ensure_zeitwerk_mode = ->() do + unless Rails.autoloaders.zeitwerk_enabled? + abort "Please, enable :zeitwerk mode in config/application.rb and try again." end end eager_load = ->() do - Rails.configuration.eager_load_namespaces.each(&:eager_load!) + puts "Hold on, I am eager loading the application." + Zeitwerk::Loader.eager_load_all end -mismatches = [] -check_directory = ->(directory, parent) do - # test/mailers/previews might not exist. - return unless File.exist?(directory) - - Dir.foreach(directory) do |entry| - next if entry.start_with?(".") - next if parent == Object && entry == "concerns" +report_not_checked = ->(not_checked) do + puts + puts <<~EOS + WARNING: The files in these directories cannot be checked because they + are not eager loaded: + EOS + puts - abspath = File.join(directory, entry) + not_checked.each { |dir| puts " #{dir}" } + puts - if File.directory?(abspath) || abspath.end_with?(".rb") - print "." - cname = File.basename(abspath, ".rb").camelize.to_sym - if parent.const_defined?(cname, false) - if File.directory?(abspath) - check_directory[abspath, parent.const_get(cname)] - end - else - mismatches << [abspath, parent, cname] - end - end - end + puts <<~EOS + You may verify them manually, or add them to config.eager_load_paths + in config/application.rb and run zeitwerk:check again. + EOS + puts end -report = ->() do - puts - if mismatches.empty? - puts "All is good!" - puts "Please, remember to delete `config.autoloader = :classic` from config/application.rb." +report = ->(not_checked) do + if not_checked.any? + report_not_checked[not_checked] + puts "Otherwise, all is good!" else - mismatches.each do |abspath, parent, cname| - relpath = abspath.sub(%r{\A#{Regexp.escape(Rails.root.to_path)}/}, "") - cpath = parent == Object ? cname : "#{parent.name}::#{cname}" - puts "expected #{relpath} to define #{cpath}" - end - puts - puts <<~EOS - Please revise the reported mismatches. You can normally fix them by adding - acronyms to config/initializers/inflections.rb or renaming the constants. - EOS + puts "All is good!" end end namespace :zeitwerk do desc "Checks project structure for Zeitwerk compatibility" task check: :environment do - ensure_classic_mode[] - eager_load[] + ensure_zeitwerk_mode[] - $stdout.sync = true - ActiveSupport::Dependencies.autoload_paths.each do |autoload_path| - check_directory[autoload_path, Object] + begin + eager_load[] + rescue NameError => e + if e.message =~ /expected file .*? to define constant \S+/ + abort $&.sub(/#{Regexp.escape(Rails.root.to_s)}./, "") + else + raise + end end - puts - report[] + eager_load_paths = Rails.configuration.eager_load_namespaces.map do |eln| + eln.config.eager_load_paths if eln.respond_to?(:config) + end.compact.flatten + + not_checked = ActiveSupport::Dependencies.autoload_paths - eager_load_paths + not_checked.select! { |dir| Dir.exist?(dir) } + not_checked.reject! { |dir| Dir.empty?(dir) } + + report[not_checked] end end diff --git a/railties/lib/rails/test_unit/runner.rb b/railties/lib/rails/test_unit/runner.rb index d38952bb30..b8bce8c772 100644 --- a/railties/lib/rails/test_unit/runner.rb +++ b/railties/lib/rails/test_unit/runner.rb @@ -45,7 +45,7 @@ module Rails patterns = extract_filters(argv) tests = Rake::FileList[patterns.any? ? patterns : "test/**/*_test.rb"] - tests.exclude("test/system/**/*") if patterns.empty? + tests.exclude("test/system/**/*", "test/dummy/**/*") if patterns.empty? tests.to_a.each { |path| require File.expand_path(path) } end @@ -61,7 +61,7 @@ module Rails private def extract_filters(argv) # Extract absolute and relative paths but skip -n /.*/ regexp filters. - argv.select { |arg| arg =~ %r%^/?\w+/% && !arg.end_with?("/") }.map do |path| + argv.select { |arg| %r%^/?\w+/%.match?(arg) && !arg.end_with?("/") }.map do |path| case when /(:\d+)+$/.match?(path) file, *lines = path.split(":") diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb index a80581211b..651897d8f3 100644 --- a/railties/test/application/assets_test.rb +++ b/railties/test/application/assets_test.rb @@ -311,7 +311,7 @@ module ApplicationTests manifest = Dir["#{app_path}/public/assets/.sprockets-manifest-*.json"].first assets = ActiveSupport::JSON.decode(File.read(manifest)) - assert asset_path = assets["assets"].find { |(k, _)| k && k =~ /.png/ }[1] + assert asset_path = assets["assets"].find { |(k, _)| /.png/.match?(k) }[1] # Load app env app "development" @@ -491,7 +491,6 @@ module ApplicationTests end private - def app_with_assets_in_view app_file "app/assets/javascripts/application.js", "//= require_tree ." app_file "app/assets/javascripts/xmlhr.js", "function f1() { alert(); }" diff --git a/railties/test/application/bin_setup_test.rb b/railties/test/application/bin_setup_test.rb index aa0da0931d..d84ab61cf9 100644 --- a/railties/test/application/bin_setup_test.rb +++ b/railties/test/application/bin_setup_test.rb @@ -31,7 +31,7 @@ module ApplicationTests Dir.chdir(app_path) do # SQLite3 seems to auto-create the database on first checkout. rails "db:system:change", "--to=postgresql" - rails "db:drop" + rails "db:drop", allow_failure: true app_file "db/schema.rb", "" diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index 7c613585e0..cca86bc13a 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -456,7 +456,7 @@ module ApplicationTests test "filter_parameters should be able to set via config.filter_parameters" do add_to_config <<-RUBY config.filter_parameters += [ :foo, 'bar', lambda { |key, value| - value = value.reverse if key =~ /baz/ + value = value.reverse if /baz/.match?(key) }] RUBY @@ -790,7 +790,7 @@ module ApplicationTests end get "/" - assert last_response.body =~ /csrf\-param/ + assert /csrf\-param/.match?(last_response.body) end test "default form builder specified as a string" do @@ -1607,6 +1607,13 @@ module ApplicationTests assert_not_nil Rails::SourceAnnotationExtractor::Annotation.extensions[/\.(coffee)$/] end + test "config.default_log_file returns a File instance" do + app "development" + + assert_instance_of File, app.config.default_log_file + assert_equal Rails.application.config.paths["log"].first, app.config.default_log_file.path + end + test "rake_tasks block works at instance level" do app_file "config/environments/development.rb", <<-RUBY Rails.application.configure do @@ -1701,7 +1708,7 @@ module ApplicationTests app "development" ActiveSupport::Dependencies.autoload_paths.each do |path| assert_not_operator path, :ends_with?, "app/assets" - assert_not_operator path, :ends_with?, "app/javascript" + assert_not_operator path, :ends_with?, "app/#{Rails.configuration.webpacker_path}" end end @@ -1786,6 +1793,11 @@ module ApplicationTests assert_equal [X, D], C.descendants end + test "load_database_yaml returns blank hash if configuration file is blank" do + app_file "config/database.yml", "" + app "development" + assert_equal({}, Rails.application.config.load_database_yaml) + end test "raises with proper error message if no database configuration found" do FileUtils.rm("#{app_path}/config/database.yml") @@ -2429,6 +2441,33 @@ module ApplicationTests assert_nil ActiveStorage.queues[:purge] end + test "ActionDispatch::Response.return_only_media_type_on_content_type is false by default" do + app "development" + + assert_equal false, ActionDispatch::Response.return_only_media_type_on_content_type + end + + test "ActionDispatch::Response.return_only_media_type_on_content_type is true in the 5.x defaults" do + remove_from_config '.*config\.load_defaults.*\n' + add_to_config 'config.load_defaults "5.2"' + + app "development" + + assert_equal true, ActionDispatch::Response.return_only_media_type_on_content_type + end + + test "ActionDispatch::Response.return_only_media_type_on_content_type can be configured in the new framework defaults" do + remove_from_config '.*config\.load_defaults.*\n' + + app_file "config/initializers/new_framework_defaults_6_0.rb", <<-RUBY + Rails.application.config.action_dispatch.return_only_media_type_on_content_type = true + RUBY + + app "development" + + assert_equal true, ActionDispatch::Response.return_only_media_type_on_content_type + end + test "ActionMailbox.logger is Rails.logger by default" do app "development" @@ -2554,6 +2593,21 @@ module ApplicationTests MESSAGE end + test "ActiveStorage.draw_routes can be configured via config.active_storage.draw_routes" do + app_file "config/environments/development.rb", <<-RUBY + Rails.application.configure do + config.active_storage.draw_routes = false + end + RUBY + + output = rails("routes") + assert_not_includes(output, "rails_service_blob") + assert_not_includes(output, "rails_blob_representation") + assert_not_includes(output, "rails_disk_service") + assert_not_includes(output, "update_rails_disk_service") + assert_not_includes(output, "rails_direct_uploads") + end + test "hosts include .localhost in development" do app "development" assert_includes Rails.application.config.hosts, ".localhost" diff --git a/railties/test/application/content_security_policy_test.rb b/railties/test/application/content_security_policy_test.rb index 0d28df16f8..0bb6ee917a 100644 --- a/railties/test/application/content_security_policy_test.rb +++ b/railties/test/application/content_security_policy_test.rb @@ -119,6 +119,38 @@ module ApplicationTests assert_policy "default-src 'self' https:", report_only: true end + test "global content security policy nonce directives in an initializer" do + controller :pages, <<-RUBY + class PagesController < ApplicationController + def index + render html: "<h1>Welcome to Rails!</h1>" + end + end + RUBY + + app_file "config/initializers/content_security_policy.rb", <<-RUBY + Rails.application.config.content_security_policy do |p| + p.default_src :self, :https + p.script_src :self, :https + p.style_src :self, :https + end + + Rails.application.config.content_security_policy_nonce_generator = proc { "iyhD0Yc0W+c=" } + Rails.application.config.content_security_policy_nonce_directives = %w(script-src) + RUBY + + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + root to: "pages#index" + end + RUBY + + app("development") + + get "/" + assert_policy "default-src 'self' https:; script-src 'self' https: 'nonce-iyhD0Yc0W+c='; style-src 'self' https:" + end + test "override content security policy in a controller" do controller :pages, <<-RUBY class PagesController < ApplicationController @@ -204,7 +236,6 @@ module ApplicationTests end private - def assert_policy(expected, report_only: false) assert_equal 200, last_response.status diff --git a/railties/test/application/feature_policy_test.rb b/railties/test/application/feature_policy_test.rb new file mode 100644 index 0000000000..e751d782ee --- /dev/null +++ b/railties/test/application/feature_policy_test.rb @@ -0,0 +1,191 @@ +# frozen_string_literal: true + +require "isolation/abstract_unit" +require "rack/test" + +module ApplicationTests + class FeaturePolicyTest < ActiveSupport::TestCase + include ActiveSupport::Testing::Isolation + include Rack::Test::Methods + + def setup + build_app + end + + def teardown + teardown_app + end + + test "feature policy is not enabled by default" do + controller :pages, <<-RUBY + class PagesController < ApplicationController + def index + render html: "<h1>Welcome to Rails!</h1>" + end + end + RUBY + + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + root to: "pages#index" + end + RUBY + + app("development") + + get "/" + assert_nil last_response.headers["Feature-Policy"] + end + + test "global feature policy in an initializer" do + controller :pages, <<-RUBY + class PagesController < ApplicationController + def index + render html: "<h1>Welcome to Rails!</h1>" + end + end + RUBY + + app_file "config/initializers/feature_policy.rb", <<-RUBY + Rails.application.config.feature_policy do |p| + p.geolocation :none + end + RUBY + + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + root to: "pages#index" + end + RUBY + + app("development") + + get "/" + assert_policy "geolocation 'none'" + end + + test "override feature policy using same directive in a controller" do + controller :pages, <<-RUBY + class PagesController < ApplicationController + feature_policy do |p| + p.geolocation "https://example.com" + end + + def index + render html: "<h1>Welcome to Rails!</h1>" + end + end + RUBY + + app_file "config/initializers/feature_policy.rb", <<-RUBY + Rails.application.config.feature_policy do |p| + p.geolocation :none + end + RUBY + + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + root to: "pages#index" + end + RUBY + + app("development") + + get "/" + assert_policy "geolocation https://example.com" + end + + test "override feature policy by unsetting a directive in a controller" do + controller :pages, <<-RUBY + class PagesController < ApplicationController + feature_policy do |p| + p.geolocation nil + end + + def index + render html: "<h1>Welcome to Rails!</h1>" + end + end + RUBY + + app_file "config/initializers/feature_policy.rb", <<-RUBY + Rails.application.config.feature_policy do |p| + p.geolocation :none + end + RUBY + + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + root to: "pages#index" + end + RUBY + + app("development") + + get "/" + assert_equal 200, last_response.status + assert_nil last_response.headers["Feature-Policy"] + end + + test "override feature policy using different directives in a controller" do + controller :pages, <<-RUBY + class PagesController < ApplicationController + feature_policy do |p| + p.geolocation nil + p.payment "https://secure.example.com" + p.autoplay :none + end + + def index + render html: "<h1>Welcome to Rails!</h1>" + end + end + RUBY + + app_file "config/initializers/feature_policy.rb", <<-RUBY + Rails.application.config.feature_policy do |p| + p.geolocation :none + end + RUBY + + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + root to: "pages#index" + end + RUBY + + app("development") + + get "/" + assert_policy "payment https://secure.example.com; autoplay 'none'" + end + + test "global feature policy added to rack app" do + app_file "config/initializers/feature_policy.rb", <<-RUBY + Rails.application.config.feature_policy do |p| + p.payment :none + end + RUBY + + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + app = ->(env) { + [200, { "Content-Type" => "text/html" }, ["<p>Hello, World!</p>"]] + } + root to: app + end + RUBY + + app("development") + + get "/" + assert_policy "payment 'none'" + end + + private + def assert_policy(expected) + assert_equal 200, last_response.status + assert_equal expected, last_response.headers["Feature-Policy"] + end + end +end diff --git a/railties/test/application/generators_test.rb b/railties/test/application/generators_test.rb index e5e557d204..8ec26db772 100644 --- a/railties/test/application/generators_test.rb +++ b/railties/test/application/generators_test.rb @@ -198,5 +198,15 @@ module ApplicationTests assert_no_match "active_record:migration", output end end + + test "skip collision check" do + rails("generate", "model", "post", "title:string") + + output = rails("generate", "model", "post", "title:string", "body:string") + assert_match(/The name 'Post' is either already used in your application or reserved/, output) + + output = rails("generate", "model", "post", "title:string", "body:string", "--skip-collision-check") + assert_no_match(/The name 'Post' is either already used in your application or reserved/, output) + end end end diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb index a35247fc43..05978e1d99 100644 --- a/railties/test/application/initializers/frameworks_test.rb +++ b/railties/test/application/initializers/frameworks_test.rb @@ -218,8 +218,9 @@ module ApplicationTests rails %w(generate model post title:string) rails %w(db:migrate db:schema:cache:dump) require "#{app_path}/config/environment" - ActiveRecord::Base.connection.drop_table("posts") # force drop posts table for test. assert ActiveRecord::Base.connection.schema_cache.data_sources("posts") + ensure + ActiveRecord::Base.connection.drop_table("posts", if_exists: true) # force drop posts table for test. end test "expire schema cache dump" do diff --git a/railties/test/application/loading_test.rb b/railties/test/application/loading_test.rb index 9c98489590..9ab400acfc 100644 --- a/railties/test/application/loading_test.rb +++ b/railties/test/application/loading_test.rb @@ -116,7 +116,7 @@ class LoadingTest < ActiveSupport::TestCase RUBY app_file "app/models/post.rb", <<-MODEL - class Post < ActiveRecord::Base + class Post < ApplicationRecord end MODEL @@ -133,11 +133,12 @@ class LoadingTest < ActiveSupport::TestCase require "#{rails_root}/config/environment" setup_ar! - assert_equal [ActiveStorage::Blob, ActiveStorage::Attachment, ActiveRecord::SchemaMigration, ActiveRecord::InternalMetadata].collect(&:to_s).sort, ActiveRecord::Base.descendants.collect(&:to_s).sort + initial = [ActiveStorage::Blob, ActiveStorage::Attachment, ActiveRecord::SchemaMigration, ActiveRecord::InternalMetadata, ApplicationRecord, "primary::SchemaMigration"].collect(&:to_s).sort + assert_equal initial, ActiveRecord::Base.descendants.collect(&:to_s).sort get "/load" - assert_equal [ActiveStorage::Blob, ActiveStorage::Attachment, ActiveRecord::SchemaMigration, ActiveRecord::InternalMetadata, Post].collect(&:to_s).sort, ActiveRecord::Base.descendants.collect(&:to_s).sort + assert_equal [Post].collect(&:to_s).sort, ActiveRecord::Base.descendants.collect(&:to_s).sort - initial get "/unload" - assert_equal [ActiveStorage::Blob, ActiveStorage::Attachment, ActiveRecord::SchemaMigration, ActiveRecord::InternalMetadata].collect(&:to_s).sort, ActiveRecord::Base.descendants.collect(&:to_s).sort + assert_equal ["ActiveRecord::InternalMetadata", "ActiveRecord::SchemaMigration", "primary::SchemaMigration"], ActiveRecord::Base.descendants.collect(&:to_s).sort.uniq end test "initialize cant be called twice" do @@ -454,7 +455,6 @@ class LoadingTest < ActiveSupport::TestCase end private - def setup_ar! ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:") ActiveRecord::Migration.verbose = false diff --git a/railties/test/application/middleware/exceptions_test.rb b/railties/test/application/middleware/exceptions_test.rb index 17df78ed4e..5fae521937 100644 --- a/railties/test/application/middleware/exceptions_test.rb +++ b/railties/test/application/middleware/exceptions_test.rb @@ -136,5 +136,21 @@ module ApplicationTests assert_match(/boooom/, last_response.body) assert_match(/測試テスト시험/, last_response.body) end + + test "displays diagnostics message when malformed query parameters are provided" do + controller :foo, <<-RUBY + class FooController < ActionController::Base + def index + end + end + RUBY + + app.config.action_dispatch.show_exceptions = true + app.config.consider_all_requests_local = true + + get "/foo?x[y]=1&x[y][][w]=2" + assert_equal 400, last_response.status + assert_match "Invalid query parameters", last_response.body + end end end diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb index 54b2e95d75..e93f2f5aa4 100644 --- a/railties/test/application/middleware_test.rb +++ b/railties/test/application/middleware_test.rb @@ -46,6 +46,7 @@ module ApplicationTests "ActionDispatch::Session::CookieStore", "ActionDispatch::Flash", "ActionDispatch::ContentSecurityPolicy::Middleware", + "ActionDispatch::FeaturePolicy::Middleware", "Rack::Head", "Rack::ConditionalGet", "Rack::ETag", @@ -309,7 +310,6 @@ module ApplicationTests end private - def boot! require "#{app_path}/config/environment" end diff --git a/railties/test/application/rake/dbs_test.rb b/railties/test/application/rake/dbs_test.rb index 258066a7e6..c9931c45a6 100644 --- a/railties/test/application/rake/dbs_test.rb +++ b/railties/test/application/rake/dbs_test.rb @@ -40,6 +40,15 @@ module ApplicationTests end end + def db_create_with_warning(expected_database) + Dir.chdir(app_path) do + output = rails("db:create") + assert_match(/Rails couldn't infer whether you are using multiple databases/, output) + assert_match(/Created database/, output) + assert File.exist?(expected_database) + end + end + test "db:create and db:drop without database URL" do require "#{app_path}/config/environment" db_create_and_drop ActiveRecord::Base.configurations[Rails.env]["database"] @@ -86,6 +95,25 @@ module ApplicationTests db_create_and_drop("db/development.sqlite3", environment_loaded: false) end + test "db:create and db:drop show warning but doesn't raise errors when loading YAML with alias ERB" do + app_file "config/database.yml", <<-YAML + sqlite: &sqlite + adapter: sqlite3 + database: db/development.sqlite3 + + development: + <<: *<%= ENV["DB"] || "sqlite" %> + YAML + + app_file "config/environments/development.rb", <<-RUBY + Rails.application.configure do + config.database = "db/development.sqlite3" + end + RUBY + + db_create_with_warning("db/development.sqlite3") + end + test "db:create and db:drop don't raise errors when loading YAML containing conditional statements in ERB" do app_file "config/database.yml", <<-YAML development: @@ -122,6 +150,39 @@ module ApplicationTests db_create_and_drop("db/development.sqlite3", environment_loaded: false) end + test "db:create and db:drop dont raise errors when loading YAML with FIXME ERB" do + app_file "config/database.yml", <<-YAML + development: + <%= Rails.application.config.database ? 'database: db/development.sqlite3' : 'database: db/development.sqlite3' %> + adapter: sqlite3 + YAML + + app_file "config/environments/development.rb", <<-RUBY + Rails.application.configure do + config.database = "db/development.sqlite3" + end + RUBY + + db_create_and_drop("db/development.sqlite3", environment_loaded: false) + end + + test "db:create and db:drop don't raise errors when loading YAML which contains a key's value as an ERB statement" do + app_file "config/database.yml", <<-YAML + development: + database: <%= Rails.application.config.database ? 'db/development.sqlite3' : 'db/development.sqlite3' %> + custom_option: <%= ENV['CUSTOM_OPTION'] %> + adapter: sqlite3 + YAML + + app_file "config/environments/development.rb", <<-RUBY + Rails.application.configure do + config.database = "db/development.sqlite3" + end + RUBY + + db_create_and_drop("db/development.sqlite3", environment_loaded: false) + end + def with_database_existing Dir.chdir(app_path) do set_database_url @@ -569,6 +630,22 @@ module ApplicationTests assert_match(/CreateRecipes: migrated/, output) end end + + test "db:prepare does not touch schema when dumping is disabled" do + Dir.chdir(app_path) do + rails "generate", "model", "book", "title:string" + rails "db:create", "db:migrate" + + app_file "db/schema.rb", "Not touched" + app_file "config/initializers/disable_dumping_schema.rb", <<-RUBY + Rails.application.config.active_record.dump_schema_after_migration = false + RUBY + + rails "db:prepare" + + assert_equal("Not touched", File.read("db/schema.rb").strip) + end + end end end end diff --git a/railties/test/application/rake/multi_dbs_test.rb b/railties/test/application/rake/multi_dbs_test.rb index 31ea2246a9..2606e64424 100644 --- a/railties/test/application/rake/multi_dbs_test.rb +++ b/railties/test/application/rake/multi_dbs_test.rb @@ -299,10 +299,56 @@ module ApplicationTests db_migrate_and_schema_cache_dump_and_schema_cache_clear end + test "db:abort_if_pending_migrations works on all databases" do + require "#{app_path}/config/environment" + + app_file "db/animals_migrate/02_two_migration.rb", <<-MIGRATION + class TwoMigration < ActiveRecord::Migration::Current + end + MIGRATION + + output = rails("db:abort_if_pending_migrations", allow_failure: true) + assert_match(/You have 1 pending migration/, output) + end + + test "db:abort_if_pending_migrations:namespace works" do + require "#{app_path}/config/environment" + + app_file "db/animals_migrate/02_two_migration.rb", <<-MIGRATION + class TwoMigration < ActiveRecord::Migration::Current + end + MIGRATION + + output = rails("db:abort_if_pending_migrations:primary") + assert_no_match(/You have \d+ pending migration/, output) + output = rails("db:abort_if_pending_migrations:animals", allow_failure: true) + assert_match(/You have 1 pending migration/, output) + end + test "db:prepare works on all databases" do require "#{app_path}/config/environment" db_prepare end + + test "db:prepare setups missing database without clearing existing one" do + require "#{app_path}/config/environment" + Dir.chdir(app_path) do + # Bug not visible on SQLite3. Can be simplified when https://github.com/rails/rails/issues/36383 resolved + use_postgresql(multi_db: true) + generate_models_for_animals + + rails "db:create:animals", "db:migrate:animals", "db:create:primary", "db:migrate:primary", "db:schema:dump" + rails "db:drop:primary" + Dog.create! + output = rails("db:prepare") + + assert_match(/Created database/, output) + assert_equal 1, Dog.count + ensure + Dog.connection.disconnect! + rails "db:drop" rescue nil + end + end end end end diff --git a/railties/test/application/rake/notes_test.rb b/railties/test/application/rake/notes_test.rb index 60802ef7c4..47822e55b9 100644 --- a/railties/test/application/rake/notes_test.rb +++ b/railties/test/application/rake/notes_test.rb @@ -159,7 +159,6 @@ module ApplicationTests end private - def run_rake_notes(command = "bin/rake notes") Dir.chdir(app_path) do output = `#{command}` diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb index fe56e3d076..e8456e8c19 100644 --- a/railties/test/application/rake_test.rb +++ b/railties/test/application/rake_test.rb @@ -162,7 +162,6 @@ module ApplicationTests rails "generate", "scaffold", "user", "username:string", "password:string" with_rails_env("test") do rails("db:migrate") - rails("webpacker:compile") end output = rails("test") @@ -194,7 +193,6 @@ module ApplicationTests rails "generate", "scaffold", "LineItems", "product:references", "cart:belongs_to" with_rails_env("test") do rails("db:migrate") - rails("webpacker:compile") end output = rails("test") diff --git a/railties/test/application/system_test_case_test.rb b/railties/test/application/system_test_case_test.rb new file mode 100644 index 0000000000..d15a0d9210 --- /dev/null +++ b/railties/test/application/system_test_case_test.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require "isolation/abstract_unit" +require "rack/test" + +class SystemTestCaseTest < ActiveSupport::TestCase + include ActiveSupport::Testing::Isolation + + def setup + build_app + end + + def teardown + teardown_app + end + + test "url helpers are delegated to a proxy class" do + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + get 'foo', to: 'foo#index', as: 'test_foo' + end + RUBY + + app("test") + + assert_not_includes(ActionDispatch::SystemTestCase.runnable_methods, :test_foo_url) + end + + test "system tests set the Capybara host in the url_options by default" do + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + get 'foo', to: 'foo#index', as: 'test_foo' + end + RUBY + + app("test") + system_test = ActionDispatch::SystemTestCase.new("my_test") + previous_app_host = ::Capybara.app_host + ::Capybara.app_host = "https://my_test_example.com" + + assert_equal("https://my_test_example.com/foo", system_test.test_foo_url) + ensure + ::Capybara.app_host = previous_app_host + end +end diff --git a/railties/test/application/test_runner_test.rb b/railties/test/application/test_runner_test.rb index 1ab45abcd0..7fc918898b 100644 --- a/railties/test/application/test_runner_test.rb +++ b/railties/test/application/test_runner_test.rb @@ -564,6 +564,24 @@ module ApplicationTests assert_no_match "create_table(:users)", output end + def test_run_in_parallel_with_process_worker_crash + exercise_parallelization_regardless_of_machine_core_count(with: :processes) + + file_name = app_file("test/models/parallel_test.rb", <<-RUBY) + require 'test_helper' + + class ParallelTest < ActiveSupport::TestCase + def test_crash + Kernel.exit 1 + end + end + RUBY + + output = run_test_command(file_name) + + assert_match %r{Queue not empty, but all workers have finished. This probably means that a worker crashed and 1 tests were missed.}, output + end + def test_run_in_parallel_with_threads exercise_parallelization_regardless_of_machine_core_count(with: :threads) diff --git a/railties/test/application/zeitwerk_integration_test.rb b/railties/test/application/zeitwerk_integration_test.rb index 9146222f73..d03fa3d0c6 100644 --- a/railties/test/application/zeitwerk_integration_test.rb +++ b/railties/test/application/zeitwerk_integration_test.rb @@ -98,6 +98,15 @@ class ZeitwerkIntegrationTest < ActiveSupport::TestCase assert_nil deps.safe_constantize("Admin") end + test "autoloaded? and overridden class names" do + invalid_constant_name = Module.new do + def self.name + "primary::SchemaMigration" + end + end + assert_not deps.autoloaded?(invalid_constant_name) + end + test "unloadable constants (main)" do app_file "app/models/user.rb", "class User; end" app_file "app/models/post.rb", "class Post; end" @@ -141,6 +150,35 @@ class ZeitwerkIntegrationTest < ActiveSupport::TestCase assert_empty deps.autoloaded_constants end + [true, false].each do |add_aps_to_lp| + test "require_dependency looks autoload paths up (#{add_aps_to_lp})" do + add_to_config "config.add_autoload_paths_to_load_path = #{add_aps_to_lp}" + app_file "app/models/user.rb", "class User; end" + boot + + assert require_dependency("user") + end + + test "require_dependency handles absolute paths correctly (#{add_aps_to_lp})" do + add_to_config "config.add_autoload_paths_to_load_path = #{add_aps_to_lp}" + app_file "app/models/user.rb", "class User; end" + boot + + assert require_dependency("#{app_path}/app/models/user.rb") + end + + test "require_dependency supports arguments that repond to to_path (#{add_aps_to_lp})" do + add_to_config "config.add_autoload_paths_to_load_path = #{add_aps_to_lp}" + app_file "app/models/user.rb", "class User; end" + boot + + user = Object.new + def user.to_path; "user"; end + + assert require_dependency(user) + end + end + test "eager loading loads the application code" do $zeitwerk_integration_test_user = false $zeitwerk_integration_test_post = false diff --git a/railties/test/commands/console_test.rb b/railties/test/commands/console_test.rb index f6df2b694a..ee4335e31d 100644 --- a/railties/test/commands/console_test.rb +++ b/railties/test/commands/console_test.rb @@ -116,7 +116,6 @@ class Rails::ConsoleTest < ActiveSupport::TestCase private :output private - def start(argv = []) rails_console = Rails::Console.new(app, parse_arguments(argv)) @output = capture(:stdout) { rails_console.start } diff --git a/railties/test/commands/credentials_test.rb b/railties/test/commands/credentials_test.rb index 0ee36081c0..3dec6fbe10 100644 --- a/railties/test/commands/credentials_test.rb +++ b/railties/test/commands/credentials_test.rb @@ -4,6 +4,8 @@ require "isolation/abstract_unit" require "env_helpers" require "rails/command" require "rails/commands/credentials/credentials_command" +require "fileutils" +require "tempfile" class Rails::Command::CredentialsCommandTest < ActiveSupport::TestCase include ActiveSupport::Testing::Isolation, EnvHelpers @@ -88,10 +90,107 @@ class Rails::Command::CredentialsCommandTest < ActiveSupport::TestCase assert_match(/secret_key_base/, output) end + test "edit ask the user to opt in to pretty credentials" do + assert_match(/Would you like to make the credentials diff from git/, run_edit_command) + end + + test "edit doesn't ask the user to opt in to pretty credentials when alreasy asked" do + app_file("tmp/rails_pretty_credentials", "") + + assert_no_match(/Would you like to make the credentials diff from git/, run_edit_command) + end + + test "edit doesn't ask the user to opt in when user already opted in" do + content = <<~EOM + [diff "rails_credentials"] + textconv = bin/rails credentials:show + EOM + app_file(".git/config", content) + + assert_no_match(/Would you like to make the credentials diff from git/, run_edit_command) + end + + test "edit ask the user to opt in to pretty credentials, user accepts" do + file = Tempfile.open("credentials_test") + file.write("y") + file.rewind + + run_edit_command(stdin: file.path) + + git_attributes = app_path(".gitattributes") + expected = <<~EOM + config/credentials/*.yml.enc diff=rails_credentials + config/credentials.yml.enc diff=rails_credentials + EOM + assert(File.exist?(git_attributes)) + assert_equal(expected, File.read(git_attributes)) + Dir.chdir(app_path) do + assert_equal("bin/rails credentials:show\n", `git config --get 'diff.rails_credentials.textconv'`) + end + ensure + file.close! + end + + test "edit ask the user to opt in to pretty credentials, user refuses" do + file = Tempfile.open("credentials_test") + file.write("n") + file.rewind + + run_edit_command(stdin: file.path) + + git_attributes = app_path(".gitattributes") + assert_not(File.exist?(git_attributes)) + ensure + file.close! + end + test "show credentials" do assert_match(/access_key_id: 123/, run_show_command) end + test "show command when argument is provided (from git diff left file)" do + run_edit_command(environment: "development") + + assert_match(/access_key_id: 123/, run_show_command("config/credentials/development.yml.enc")) + end + + test "show command when argument is provided (from git diff right file)" do + run_edit_command(environment: "development") + + dir = Dir.mktmpdir + file_path = File.join(dir, "KnAM4a_development.yml.enc") + file_content = File.read(app_path("config", "credentials", "development.yml.enc")) + File.write(file_path, file_content) + + assert_match(/access_key_id: 123/, run_show_command(file_path)) + ensure + FileUtils.rm_rf(dir) + end + + test "show command when argument is provided (git diff) and filename is the master credentials" do + assert_match(/access_key_id: 123/, run_show_command("config/credentials.yml.enc")) + end + + test "show command when argument is provided (git diff) and master key is not available" do + remove_file "config/master.key" + + raw_content = File.read(app_path("config", "credentials.yml.enc")) + assert_match(raw_content, run_show_command("config/credentials.yml.enc")) + end + + test "show command when argument is provided (git diff) return the raw encrypted content in an error occurs" do + run_edit_command(environment: "development") + + dir = Dir.mktmpdir + file_path = File.join(dir, "20190807development.yml.enc") + file_content = File.read(app_path("config", "credentials", "development.yml.enc")) + File.write(file_path, file_content) + + assert_match(file_content, run_show_command(file_path)) + ensure + FileUtils.rm_rf(dir) + end + test "show command raises error when require_master_key is specified and key does not exist" do remove_file "config/master.key" add_to_config "config.require_master_key = true" @@ -128,8 +227,9 @@ class Rails::Command::CredentialsCommandTest < ActiveSupport::TestCase end end - def run_show_command(environment: nil, **options) + def run_show_command(path = nil, environment: nil, **options) args = environment ? ["--environment", environment] : [] + args.unshift(path) rails "credentials:show", args, **options end end diff --git a/railties/test/commands/dbconsole_test.rb b/railties/test/commands/dbconsole_test.rb index 76a7cd055f..45b72fd909 100644 --- a/railties/test/commands/dbconsole_test.rb +++ b/railties/test/commands/dbconsole_test.rb @@ -275,7 +275,6 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase private :aborted, :output private - def app_db_config(results) Rails.application.config.stub(:database_configuration, results || {}) do yield diff --git a/railties/test/commands/server_test.rb b/railties/test/commands/server_test.rb index b78370a233..c9026e2d95 100644 --- a/railties/test/commands/server_test.rb +++ b/railties/test/commands/server_test.rb @@ -116,6 +116,13 @@ class Rails::Command::ServerCommandTest < ActiveSupport::TestCase end end + def test_environment_with_pidfile + switch_env "PIDFILE", "/tmp/rails.pid" do + options = parse_arguments + assert_equal "/tmp/rails.pid", options[:pid] + end + end + def test_caching_without_option args = [] options = parse_arguments(args) @@ -234,6 +241,12 @@ class Rails::Command::ServerCommandTest < ActiveSupport::TestCase options = parse_arguments(args) assert_equal "127.0.0.1", options[:Host] end + + switch_env "PIDFILE", "/tmp/rails.pid" do + args = ["-P", "/somewhere/else.pid"] + options = parse_arguments(args) + assert_equal "/somewhere/else.pid", options[:pid] + end end def test_records_user_supplied_options @@ -253,6 +266,16 @@ class Rails::Command::ServerCommandTest < ActiveSupport::TestCase server_options = parse_arguments assert_equal [:Host], server_options[:user_supplied_options] end + + switch_env "PORT", "3001" do + server_options = parse_arguments + assert_equal [:Port], server_options[:user_supplied_options] + end + + switch_env "PIDFILE", "/tmp/server.pid" do + server_options = parse_arguments + assert_equal [:pid], server_options[:user_supplied_options] + end end def test_default_options diff --git a/railties/test/configuration/middleware_stack_proxy_test.rb b/railties/test/configuration/middleware_stack_proxy_test.rb index bc72b7f0c9..b67142f4c2 100644 --- a/railties/test/configuration/middleware_stack_proxy_test.rb +++ b/railties/test/configuration/middleware_stack_proxy_test.rb @@ -51,7 +51,6 @@ module Rails end private - def assert_playback(msg_name, args) mock = Minitest::Mock.new mock.expect :send, nil, [msg_name, args] diff --git a/railties/test/env_helpers.rb b/railties/test/env_helpers.rb index 336832b867..e3157e0c77 100644 --- a/railties/test/env_helpers.rb +++ b/railties/test/env_helpers.rb @@ -4,7 +4,6 @@ require "rails" module EnvHelpers private - def with_rails_env(env) Rails.instance_variable_set :@_env, nil switch_env "RAILS_ENV", env do diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb index d913bb5438..5d6d7f1595 100644 --- a/railties/test/generators/actions_test.rb +++ b/railties/test/generators/actions_test.rb @@ -43,7 +43,7 @@ class ActionsTest < Rails::Generators::TestCase def test_add_source_adds_source_to_gemfile run_generator action :add_source, "http://gems.github.com" - assert_file "Gemfile", /source 'http:\/\/gems\.github\.com'/ + assert_file "Gemfile", /source 'http:\/\/gems\.github\.com'\n/ end def test_add_source_with_block_adds_source_to_gemfile_with_gem @@ -51,7 +51,7 @@ class ActionsTest < Rails::Generators::TestCase action :add_source, "http://gems.github.com" do gem "rspec-rails" end - assert_file "Gemfile", /source 'http:\/\/gems\.github\.com' do\n gem 'rspec-rails'\nend/ + assert_file "Gemfile", /\n\nsource 'http:\/\/gems\.github\.com' do\n gem 'rspec-rails'\nend\n\z/ end def test_add_source_with_block_adds_source_to_gemfile_after_gem @@ -60,13 +60,25 @@ class ActionsTest < Rails::Generators::TestCase action :add_source, "http://gems.github.com" do gem "rspec-rails" end - assert_file "Gemfile", /gem 'will-paginate'\nsource 'http:\/\/gems\.github\.com' do\n gem 'rspec-rails'\nend/ + assert_file "Gemfile", /\ngem 'will-paginate'\n\nsource 'http:\/\/gems\.github\.com' do\n gem 'rspec-rails'\nend\n\z/ + end + + def test_add_source_should_create_newline_between_blocks + run_generator + action :add_source, "http://gems.github.com" do + gem "rspec-rails" + end + + action :add_source, "http://gems2.github.com" do + gem "fakeweb" + end + assert_file "Gemfile", /\n\nsource 'http:\/\/gems\.github\.com' do\n gem 'rspec-rails'\nend\n\nsource 'http:\/\/gems2\.github\.com' do\n gem 'fakeweb'\nend\n\z/ end def test_gem_should_put_gem_dependency_in_gemfile run_generator action :gem, "will-paginate" - assert_file "Gemfile", /gem 'will\-paginate'/ + assert_file "Gemfile", /gem 'will\-paginate'\n\z/ end def test_gem_with_version_should_include_version_in_gemfile @@ -141,7 +153,7 @@ class ActionsTest < Rails::Generators::TestCase gem "fakeweb" end - assert_file "Gemfile", /\ngroup :development, :test do\n gem 'rspec-rails'\nend\n\ngroup :test do\n gem 'fakeweb'\nend/ + assert_file "Gemfile", /\n\ngroup :development, :test do\n gem 'rspec-rails'\nend\n\ngroup :test do\n gem 'fakeweb'\nend\n\z/ end def test_github_should_create_an_indented_block @@ -153,7 +165,7 @@ class ActionsTest < Rails::Generators::TestCase gem "baz" end - assert_file "Gemfile", /\ngithub 'user\/repo' do\n gem 'foo'\n gem 'bar'\n gem 'baz'\nend/ + assert_file "Gemfile", /\n\ngithub 'user\/repo' do\n gem 'foo'\n gem 'bar'\n gem 'baz'\nend\n\z/ end def test_github_should_create_an_indented_block_with_options @@ -165,7 +177,7 @@ class ActionsTest < Rails::Generators::TestCase gem "baz" end - assert_file "Gemfile", /\ngithub 'user\/repo', a: 'correct', other: true do\n gem 'foo'\n gem 'bar'\n gem 'baz'\nend/ + assert_file "Gemfile", /\n\ngithub 'user\/repo', a: 'correct', other: true do\n gem 'foo'\n gem 'bar'\n gem 'baz'\nend\n\z/ end def test_github_should_create_an_indented_block_within_a_group @@ -177,9 +189,73 @@ class ActionsTest < Rails::Generators::TestCase gem "bar" gem "baz" end + github "user/repo2", a: "correct", other: true do + gem "foo" + gem "bar" + gem "baz" + end + end + + assert_file "Gemfile", /\n\ngroup :magic do\n github 'user\/repo', a: 'correct', other: true do\n gem 'foo'\n gem 'bar'\n gem 'baz'\n end\n github 'user\/repo2', a: 'correct', other: true do\n gem 'foo'\n gem 'bar'\n gem 'baz'\n end\nend\n\z/ + end + + def test_github_should_create_newline_between_blocks + run_generator + + action :github, "user/repo", a: "correct", other: true do + gem "foo" + gem "bar" + gem "baz" + end + + action :github, "user/repo2", a: "correct", other: true do + gem "foo" + gem "bar" + gem "baz" + end + + assert_file "Gemfile", /\n\ngithub 'user\/repo', a: 'correct', other: true do\n gem 'foo'\n gem 'bar'\n gem 'baz'\nend\n\ngithub 'user\/repo2', a: 'correct', other: true do\n gem 'foo'\n gem 'bar'\n gem 'baz'\nend\n\z/ + end + + def test_gem_with_gemfile_without_newline_at_the_end + run_generator + File.open("Gemfile", "a") { |f| f.write("gem 'rspec-rails'") } + + action :gem, "will-paginate" + assert_file "Gemfile", /gem 'rspec-rails'\ngem 'will-paginate'\n\z/ + end + + def test_gem_group_with_gemfile_without_newline_at_the_end + run_generator + File.open("Gemfile", "a") { |f| f.write("gem 'rspec-rails'") } + + action :gem_group, :test do + gem "fakeweb" end - assert_file "Gemfile", /\ngroup :magic do\n github 'user\/repo', a: 'correct', other: true do\n gem 'foo'\n gem 'bar'\n gem 'baz'\n end\nend\n/ + assert_file "Gemfile", /gem 'rspec-rails'\n\ngroup :test do\n gem 'fakeweb'\nend\n\z/ + end + + def test_add_source_with_gemfile_without_newline_at_the_end + run_generator + File.open("Gemfile", "a") { |f| f.write("gem 'rspec-rails'") } + + action :add_source, "http://gems.github.com" do + gem "fakeweb" + end + + assert_file "Gemfile", /gem 'rspec-rails'\n\nsource 'http:\/\/gems\.github\.com' do\n gem 'fakeweb'\nend\n\z/ + end + + def test_github_with_gemfile_without_newline_at_the_end + run_generator + File.open("Gemfile", "a") { |f| f.write("gem 'rspec-rails'") } + + action :github, "user/repo" do + gem "fakeweb" + end + + assert_file "Gemfile", /gem 'rspec-rails'\n\ngithub 'user\/repo' do\n gem 'fakeweb'\nend\n\z/ end def test_environment_should_include_data_in_environment_initializer_block @@ -505,7 +581,6 @@ F end private - def action(*args, &block) capture(:stdout) { generator.send(*args, &block) } end diff --git a/railties/test/generators/api_app_generator_test.rb b/railties/test/generators/api_app_generator_test.rb index d03178da66..099bad8fb9 100644 --- a/railties/test/generators/api_app_generator_test.rb +++ b/railties/test/generators/api_app_generator_test.rb @@ -109,7 +109,6 @@ class ApiAppGeneratorTest < Rails::Generators::TestCase end private - def default_files %w(.gitignore .ruby-version diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index 5b439fdcba..43461036f3 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -678,7 +678,7 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_inclusion_of_listen_related_configuration_by_default run_generator - if RbConfig::CONFIG["host_os"] =~ /darwin|linux/ + if /darwin|linux/.match?(RbConfig::CONFIG["host_os"]) assert_listen_related_configuration else assert_no_listen_related_configuration @@ -690,7 +690,7 @@ class AppGeneratorTest < Rails::Generators::TestCase Object.const_set(:RUBY_ENGINE, "MyRuby") run_generator - if RbConfig::CONFIG["host_os"] =~ /darwin|linux/ + if /darwin|linux/.match?(RbConfig::CONFIG["host_os"]) assert_listen_related_configuration else assert_no_listen_related_configuration @@ -708,7 +708,7 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_evented_file_update_checker_config run_generator assert_file "config/environments/development.rb" do |content| - if RbConfig::CONFIG["host_os"] =~ /darwin|linux/ + if /darwin|linux/.match?(RbConfig::CONFIG["host_os"]) assert_match(/^\s*config\.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content) else assert_match(/^\s*# config\.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content) diff --git a/railties/test/generators/migration_generator_test.rb b/railties/test/generators/migration_generator_test.rb index e6b614a935..080e54a1ca 100644 --- a/railties/test/generators/migration_generator_test.rb +++ b/railties/test/generators/migration_generator_test.rb @@ -270,6 +270,21 @@ class MigrationGeneratorTest < Rails::Generators::TestCase end end + def test_create_table_migration_with_timestamps + run_generator ["create_books", "title:string", "content:text"] + assert_migration "db/migrate/create_books.rb", /t.timestamps/ + end + + def test_create_table_timestamps_are_skipped + run_generator ["create_books", "title:string", "content:text", "--no-timestamps"] + + assert_migration "db/migrate/create_books.rb" do |m| + assert_method :change, m do |change| + assert_no_match(/t.timestamps/, change) + end + end + end + def test_add_uuid_to_create_table_migration run_generator ["create_books", "--primary_key_type=uuid"] assert_migration "db/migrate/create_books.rb" do |content| @@ -430,7 +445,6 @@ class MigrationGeneratorTest < Rails::Generators::TestCase end private - def with_singular_table_name old_state = ActiveRecord::Base.pluralize_table_names ActiveRecord::Base.pluralize_table_names = false diff --git a/railties/test/generators/named_base_test.rb b/railties/test/generators/named_base_test.rb index 4e61b660d7..1b45c58b0e 100644 --- a/railties/test/generators/named_base_test.rb +++ b/railties/test/generators/named_base_test.rb @@ -169,7 +169,6 @@ class NamedBaseTest < Rails::Generators::TestCase end private - def assert_name(generator, value, method) assert_equal value, generator.send(method) end diff --git a/railties/test/generators/plugin_generator_test.rb b/railties/test/generators/plugin_generator_test.rb index f45464f8d0..db774f6ac1 100644 --- a/railties/test/generators/plugin_generator_test.rb +++ b/railties/test/generators/plugin_generator_test.rb @@ -713,7 +713,6 @@ class PluginGeneratorTest < Rails::Generators::TestCase end private - def action(*args, &block) silence(:stdout) { generator.send(*args, &block) } end diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb index fab704944b..6077ba3ee7 100644 --- a/railties/test/isolation/abstract_unit.rb +++ b/railties/test/isolation/abstract_unit.rb @@ -301,7 +301,7 @@ module TestHelpers # stderr:: true to pass STDERR output straight to the "real" STDERR. # By default, the STDERR and STDOUT of the process will be # combined in the returned string. - def rails(*args, allow_failure: false, stderr: false) + def rails(*args, allow_failure: false, stderr: false, stdin: File::NULL) args = args.flatten fork = true @@ -328,7 +328,7 @@ module TestHelpers out_read.close err_read.close if err_read - $stdin.reopen(File::NULL, "r") + $stdin.reopen(stdin, "r") $stdout.reopen(out_write) $stderr.reopen(err_write) @@ -448,18 +448,36 @@ module TestHelpers $:.reject! { |path| path =~ %r'/(#{to_remove.join('|')})/' } end - def use_postgresql - File.open("#{app_path}/config/database.yml", "w") do |f| - f.puts <<-YAML - default: &default - adapter: postgresql - pool: 5 - database: railties_test - development: - <<: *default - test: - <<: *default - YAML + def use_postgresql(multi_db: false) + if multi_db + File.open("#{app_path}/config/database.yml", "w") do |f| + f.puts <<-YAML + default: &default + adapter: postgresql + pool: 5 + development: + primary: + <<: *default + database: railties_test + animals: + <<: *default + database: railties_animals_test + migrations_paths: db/animals_migrate + YAML + end + else + File.open("#{app_path}/config/database.yml", "w") do |f| + f.puts <<-YAML + default: &default + adapter: postgresql + pool: 5 + database: railties_test + development: + <<: *default + test: + <<: *default + YAML + end end end end diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index 8ce68dbcfa..06836844f0 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -34,7 +34,7 @@ module RailtiesTest def migrations migration_root = File.expand_path(ActiveRecord::Migrator.migrations_paths.first, app_path) - ActiveRecord::MigrationContext.new(migration_root).migrations + ActiveRecord::MigrationContext.new(migration_root, ActiveRecord::SchemaMigration).migrations end test "serving sprocket's assets" do @@ -110,7 +110,7 @@ module RailtiesTest 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 }) + bukkits_migration_order = output.index(output.detect { |o| /NOTE: Migration \d+_create_sessions\.rb from bukkits has been skipped/.match?(o) }) assert_not_nil bukkits_migration_order, "Expected migration to be skipped" end end |