diff options
Diffstat (limited to 'railties/lib/rails')
62 files changed, 281 insertions, 159 deletions
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 b79dbdbc6f..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 + :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 @@ -67,6 +68,8 @@ module Rails @credentials.key_path = default_credentials_key_path @autoloader = :classic @disable_sandbox = false + @add_autoload_paths_to_load_path = true + @feature_policy = nil end def load_defaults(target_version) @@ -128,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) @@ -141,7 +145,15 @@ 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) + active_record.collection_cache_versioning = true end + when "6.1" + load_defaults "6.0" else raise "Unknown version #{target_version.to_s.inspect}" end @@ -200,7 +212,7 @@ module Rails yaml = Pathname.new(path) erb = DummyERB.new(yaml.read) - YAML.load(erb.result) + YAML.load(erb.result) || {} else {} end @@ -292,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 @@ -304,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 193cc59f3a..572f51fca2 100644 --- a/railties/lib/rails/application/default_middleware_stack.rb +++ b/railties/lib/rails/application/default_middleware_stack.rb @@ -49,6 +49,7 @@ module Rails middleware.use ::Rails::Rack::Logger, config.log_tags middleware.use ::ActionDispatch::ShowExceptions, show_exceptions_app middleware.use ::ActionDispatch::DebugExceptions, app, config.debug_exception_response_format + middleware.use ::ActionDispatch::ActionableExceptions unless config.cache_classes middleware.use ::ActionDispatch::Reloader, app.reloader @@ -67,6 +68,7 @@ module Rails unless config.api_only middleware.use ::ActionDispatch::ContentSecurityPolicy::Middleware + middleware.use ::ActionDispatch::FeaturePolicy::Middleware end middleware.use ::Rack::Head @@ -78,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/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/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/dev/dev_command.rb b/railties/lib/rails/commands/dev/dev_command.rb index a3f02f3172..9b2cb2b04a 100644 --- a/railties/lib/rails/commands/dev/dev_command.rb +++ b/railties/lib/rails/commands/dev/dev_command.rb @@ -5,8 +5,10 @@ require "rails/dev_caching" module Rails module Command class DevCommand < Base # :nodoc: - def help - say "rails dev:cache # Toggle development mode caching on/off." + no_commands do + def help + say "rails dev:cache # Toggle development mode caching on/off." + end end def cache 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 eb2f0e8fca..46f1d38b96 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -552,16 +552,15 @@ module Rails seed_file = paths["db/seeds.rb"].existent.first return unless seed_file - if config.active_job.queue_adapter == :async + if config.try(:active_job)&.queue_adapter == :async with_inline_jobs { load(seed_file) } else load(seed_file) end end - # Add configured load paths to Ruby's load path, and remove duplicate entries. - initializer :set_load_path, before: :bootstrap_hook do - _all_load_paths.reverse_each do |path| + initializer :set_load_path, before: :bootstrap_hook do |app| + _all_load_paths(app.config.add_autoload_paths_to_load_path).reverse_each do |path| $LOAD_PATH.unshift(path) if File.directory?(path) end $LOAD_PATH.uniq! @@ -655,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) @@ -709,8 +706,12 @@ module Rails @_all_autoload_paths ||= (config.autoload_paths + config.eager_load_paths + config.autoload_once_paths).uniq end - def _all_load_paths - @_all_load_paths ||= (config.paths.load_paths + _all_autoload_paths).uniq + def _all_load_paths(add_autoload_paths_to_load_path) + @_all_load_paths ||= begin + load_paths = config.paths.load_paths + load_paths += _all_autoload_paths if add_autoload_paths_to_load_path + load_paths.uniq + end end def build_request(env) 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/gem_version.rb b/railties/lib/rails/gem_version.rb index fea24810f5..a6b3ccf8f8 100644 --- a/railties/lib/rails/gem_version.rb +++ b/railties/lib/rails/gem_version.rb @@ -8,9 +8,9 @@ module Rails module VERSION MAJOR = 6 - MINOR = 0 + MINOR = 1 TINY = 0 - PRE = "beta3" + PRE = "alpha" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb index b835b3f3fd..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" @@ -35,6 +33,8 @@ module Rails rails: { actions: "-a", orm: "-o", + javascripts: "-j", + javascript_engine: "-je", resource_controller: "-c", scaffold_controller: "-c", stylesheets: "-y", @@ -285,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 66f6b57379..dbfb7337f0 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.0", "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 diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb index 5523a3f659..a153923ce3 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! @@ -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/erb/scaffold/templates/show.html.erb.tt b/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb.tt index 6b216001d2..d3f996188c 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb.tt +++ b/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb.tt @@ -4,7 +4,7 @@ <p> <strong><%= attribute.human_name %>:</strong> <% if attribute.attachment? -%> - <%%= link_to @<%= singular_table_name %>.<%= attribute.column_name %>.filename, @<%= singular_table_name %>.<%= attribute.column_name %> %> + <%%= link_to @<%= singular_table_name %>.<%= attribute.column_name %>.filename, @<%= singular_table_name %>.<%= attribute.column_name %> if @<%= singular_table_name %>.<%= attribute.column_name %>.attached? %> <% elsif attribute.attachments? -%> <%% @<%= singular_table_name %>.<%= attribute.column_name %>.each do |<%= attribute.singular_name %>| %> <div><%%= link_to <%= attribute.singular_name %>.filename, <%= attribute.singular_name %> %></div> diff --git a/railties/lib/rails/generators/generated_attribute.rb b/railties/lib/rails/generators/generated_attribute.rb index 99c1bc4269..4e348be9be 100644 --- a/railties/lib/rails/generators/generated_attribute.rb +++ b/railties/lib/rails/generators/generated_attribute.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require "active_support/time" +require "active_support/deprecation" module Rails module Generators @@ -38,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) @@ -51,6 +51,12 @@ module Rails type = $1 provided_options = $2.split(/[,.-]/) options = Hash[provided_options.map { |opt| [opt.to_sym, true] }] + + if options[:required] + ActiveSupport::Deprecation.warn("Passing {required} option has no effect on the model generator. It will be removed in Rails 6.1.\n") + options.delete(:required) + end + return type, options else return type, {} @@ -137,7 +143,7 @@ module Rails end def required? - attr_options[:required] + reference? && Rails.application.config.active_record.belongs_to_required_by_default end def has_index? @@ -183,7 +189,6 @@ module Rails def options_for_migration @attr_options.dup.tap do |options| if required? - options.delete(:required) options[:null] = false end diff --git a/railties/lib/rails/generators/named_base.rb b/railties/lib/rails/generators/named_base.rb index 42e64cd11f..d6732f8ff1 100644 --- a/railties/lib/rails/generators/named_base.rb +++ b/railties/lib/rails/generators/named_base.rb @@ -187,7 +187,6 @@ module Rails def attributes_names # :doc: @attributes_names ||= attributes.each_with_object([]) do |a, names| - next if a.attachments? names << a.column_name names << "password_confirmation" if a.password_digest? names << "#{a.name}_type" if a.polymorphic? 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 d7221453e7..cf5462f7dc 100644 --- a/railties/lib/rails/generators/rails/app/templates/Gemfile.tt +++ b/railties/lib/rails/generators/rails/app/templates/Gemfile.tt @@ -28,7 +28,7 @@ ruby <%= "'#{RUBY_VERSION}'" -%> <% if depend_on_bootsnap? -%> # Reduces boot times through caching; required in config/boot.rb -gem 'bootsnap', '>= 1.4.2', require: false +gem 'bootsnap', '>= 1.4.4', require: false <%- end -%> <%- if options.api? -%> 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..b8c1f21c0b 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 @@ -6,7 +6,7 @@ <%%= 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/bin/setup.tt b/railties/lib/rails/generators/rails/app/templates/bin/setup.tt index 3f73bae3da..5928deb6aa 100644 --- a/railties/lib/rails/generators/rails/app/templates/bin/setup.tt +++ b/railties/lib/rails/generators/rails/app/templates/bin/setup.tt @@ -8,7 +8,8 @@ def system!(*args) end FileUtils.chdir APP_ROOT do - # This script is a starting point to setup your application. + # This script is a way to setup or update your development environment automatically. + # This script is idempotent, so that you can run it at anytime and get an expectable outcome. # Add necessary setup steps to this file. puts '== Installing dependencies ==' @@ -27,7 +28,7 @@ FileUtils.chdir APP_ROOT do # end puts "\n== Preparing database ==" - system! 'bin/rails db:setup' + system! 'bin/rails db:prepare' <% end -%> puts "\n== Removing old logs and tempfiles ==" diff --git a/railties/lib/rails/generators/rails/app/templates/bin/update.tt b/railties/lib/rails/generators/rails/app/templates/bin/update.tt deleted file mode 100644 index 03b77d0d46..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/bin/update.tt +++ /dev/null @@ -1,33 +0,0 @@ -require 'fileutils' - -# path to your application root. -APP_ROOT = File.expand_path('..', __dir__) - -def system!(*args) - system(*args) || abort("\n== Command #{args} failed ==") -end - -FileUtils.chdir APP_ROOT do - # This script is a way to update your development environment automatically. - # Add necessary update steps to this file. - - puts '== Installing dependencies ==' - system! 'gem install bundler --conservative' - system('bundle check') || system!('bundle install') -<% unless options.skip_javascript? -%> - - # Install JavaScript dependencies - # system('bin/yarn') -<% end -%> -<% unless options.skip_active_record? -%> - - puts "\n== Updating database ==" - system! 'rails db:migrate' -<% end -%> - - puts "\n== Removing old logs and tempfiles ==" - system! 'rails log:clear tmp:clear' - - puts "\n== Restarting application server ==" - system! 'rails restart' -end 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/environments/development.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt index 2887bc2d67..404ab8b5de 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt @@ -15,9 +15,11 @@ Rails.application.configure do # Enable/disable caching. By default caching is disabled. # Run rails dev:cache to toggle caching. if Rails.root.join('tmp', 'caching-dev.txt').exist? + <%- unless options.api? -%> config.action_controller.perform_caching = true config.action_controller.enable_fragment_cache_logging = true + <%- end -%> config.cache_store = :memory_store config.public_file_server.headers = { 'Cache-Control' => "public, max-age=#{2.days.to_i}" diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt index ed1cf09eeb..08d437a0be 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt @@ -12,7 +12,9 @@ Rails.application.configure do # Full error reports are disabled and caching is turned on. config.consider_all_requests_local = false + <%- unless options.api? -%> config.action_controller.perform_caching = true + <%- end -%> # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). 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/assets/assets_generator.rb b/railties/lib/rails/generators/rails/assets/assets_generator.rb index 9ce8570172..e60637ff37 100644 --- a/railties/lib/rails/generators/rails/assets/assets_generator.rb +++ b/railties/lib/rails/generators/rails/assets/assets_generator.rb @@ -3,7 +3,10 @@ module Rails module Generators class AssetsGenerator < NamedBase # :nodoc: + class_option :javascripts, type: :boolean, desc: "Generate JavaScripts" class_option :stylesheets, type: :boolean, desc: "Generate Stylesheets" + + class_option :javascript_engine, desc: "Engine for JavaScripts" class_option :stylesheet_engine, desc: "Engine for Stylesheets" private @@ -11,6 +14,10 @@ module Rails file_name end + hook_for :javascript_engine do |javascript_engine| + invoke javascript_engine, [name] if options[:javascripts] + end + hook_for :stylesheet_engine do |stylesheet_engine| invoke stylesheet_engine, [name] if options[:stylesheets] end 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 8b46eb88ae..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,11 +34,16 @@ module Rails end private - def permitted_params - params = attributes_names.map { |name| ":#{name}" }.join(", ") - params += attributes.select(&:attachments?).map { |a| ", #{a.name}: []" }.join - params + attachments, others = attributes_names.partition { |name| attachments?(name) } + params = others.map { |name| ":#{name}" } + params += attachments.map { |name| "#{name}: []" } + params.join(", ") + end + + def attachments?(name) + attribute = attributes.find { |attr| attr.name == name } + attribute&.attachments? end end end 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 6df50c3217..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 @@ -49,16 +48,21 @@ module TestUnit # :nodoc: attributes_names.map do |name| if %w(password password_confirmation).include?(name) && attributes.any?(&:password_digest?) ["#{name}", "'secret'"] - else + elsif !virtual?(name) ["#{name}", "@#{singular_table_name}.#{name}"] end - end.sort.to_h + end.compact.sort.to_h end def boolean?(name) attribute = attributes.find { |attr| attr.name == name } attribute&.type == :boolean end + + def virtual?(name) + attribute = attributes.find { |attr| attr.name == name } + attribute&.virtual? + end end end 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/mailers_controller.rb b/railties/lib/rails/mailers_controller.rb index 5cffa52860..4a1942790b 100644 --- a/railties/lib/rails/mailers_controller.rb +++ b/railties/lib/rails/mailers_controller.rb @@ -5,8 +5,9 @@ require "rails/application_controller" class Rails::MailersController < Rails::ApplicationController # :nodoc: prepend_view_path ActionDispatch::DebugView::RESCUES_TEMPLATE_PATH + around_action :set_locale, only: :preview + before_action :find_preview, only: :preview before_action :require_local!, unless: :show_previews? - before_action :find_preview, :set_locale, only: :preview helper_method :part_query, :locale_query @@ -92,6 +93,8 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc: end def set_locale - I18n.locale = params[:locale] || I18n.default_locale + I18n.with_locale(params[:locale] || I18n.default_locale) do + yield + end end end 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.rb b/railties/lib/rails/tasks.rb index 2f644a20c9..0e592e15c3 100644 --- a/railties/lib/rails/tasks.rb +++ b/railties/lib/rails/tasks.rb @@ -15,6 +15,7 @@ require "rake" routes tmp yarn + zeitwerk ).tap { |arr| arr << "statistics" if Rake.application.current_scope.empty? }.each do |task| diff --git a/railties/lib/rails/tasks/zeitwerk.rake b/railties/lib/rails/tasks/zeitwerk.rake new file mode 100644 index 0000000000..5421af6e8b --- /dev/null +++ b/railties/lib/rails/tasks/zeitwerk.rake @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +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 + puts "Hold on, I am eager loading the application." + Zeitwerk::Loader.eager_load_all +end + +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 + + not_checked.each { |dir| puts " #{dir}" } + puts + + 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 = ->(not_checked) do + if not_checked.any? + report_not_checked[not_checked] + puts "Otherwise, all is good!" + else + puts "All is good!" + end +end + +namespace :zeitwerk do + desc "Checks project structure for Zeitwerk compatibility" + task check: :environment do + ensure_zeitwerk_mode[] + + 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 + + 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..7b294751fc 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 |