diff options
Diffstat (limited to 'railties/lib/rails')
58 files changed, 339 insertions, 212 deletions
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index b1429df18b..a9dee10981 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -174,8 +174,9 @@ module Rails # team. Details at https://github.com/rails/rails/pull/6952#issuecomment-7661220 @caching_key_generator ||= if secret_key_base - ActiveSupport::CachingKeyGenerator.new \ + ActiveSupport::CachingKeyGenerator.new( ActiveSupport::KeyGenerator.new(secret_key_base, iterations: 1000) + ) else ActiveSupport::LegacyKeyGenerator.new(secrets.secret_token) end @@ -265,7 +266,10 @@ module Rails "action_dispatch.signed_cookie_digest" => config.action_dispatch.signed_cookie_digest, "action_dispatch.cookies_serializer" => config.action_dispatch.cookies_serializer, "action_dispatch.cookies_digest" => config.action_dispatch.cookies_digest, - "action_dispatch.cookies_rotations" => config.action_dispatch.cookies_rotations + "action_dispatch.cookies_rotations" => config.action_dispatch.cookies_rotations, + "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 ) end end @@ -400,8 +404,9 @@ module Rails secrets.secret_token ||= config.secret_token if secrets.secret_token.present? - ActiveSupport::Deprecation.warn \ + ActiveSupport::Deprecation.warn( "`secrets.secret_token` is deprecated in favor of `secret_key_base` and will be removed in Rails 6.0." + ) end secrets @@ -424,8 +429,9 @@ module Rails if Rails.env.test? || Rails.env.development? Digest::MD5.hexdigest self.class.name else - validate_secret_key_base \ + validate_secret_key_base( ENV["SECRET_KEY_BASE"] || credentials.secret_key_base || secrets.secret_key_base + ) end end @@ -464,10 +470,12 @@ module Rails # # Rails.application.encrypted("config/special_tokens.yml.enc", key_path: "config/special_tokens.key") def encrypted(path, key_path: "config/master.key", env_key: "RAILS_MASTER_KEY") - ActiveSupport::EncryptedConfiguration.new \ + ActiveSupport::EncryptedConfiguration.new( config_path: Rails.root.join(path), key_path: Rails.root.join(key_path), - env_key: env_key + env_key: env_key, + raise_if_missing_key: config.require_master_key + ) end def to_app #:nodoc: diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index 290ec13878..b42ffe50d8 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -16,44 +16,50 @@ module Rails :ssl_options, :public_file_server, :session_options, :time_zone, :reload_classes_only_on_change, :beginning_of_week, :filter_redirect, :x, :enable_dependency_loading, - :read_encrypted_secrets, :log_level + :read_encrypted_secrets, :log_level, :content_security_policy_report_only, + :content_security_policy_nonce_generator, :require_master_key - attr_reader :encoding, :api_only + attr_reader :encoding, :api_only, :loaded_config_version def initialize(*) super - self.encoding = Encoding::UTF_8 - @allow_concurrency = nil - @consider_all_requests_local = false - @filter_parameters = [] - @filter_redirect = [] - @helpers_paths = [] - @public_file_server = ActiveSupport::OrderedOptions.new - @public_file_server.enabled = true - @public_file_server.index_name = "index" - @force_ssl = false - @ssl_options = {} - @session_store = nil - @time_zone = "UTC" - @beginning_of_week = :monday - @log_level = :debug - @generators = app_generators - @cache_store = [ :file_store, "#{root}/tmp/cache/" ] - @railties_order = [:all] - @relative_url_root = ENV["RAILS_RELATIVE_URL_ROOT"] - @reload_classes_only_on_change = true - @file_watcher = ActiveSupport::FileUpdateChecker - @exceptions_app = nil - @autoflush_log = true - @log_formatter = ActiveSupport::Logger::SimpleFormatter.new - @eager_load = nil - @secret_token = nil - @secret_key_base = nil - @api_only = false - @debug_exception_response_format = nil - @x = Custom.new - @enable_dependency_loading = false - @read_encrypted_secrets = false + self.encoding = Encoding::UTF_8 + @allow_concurrency = nil + @consider_all_requests_local = false + @filter_parameters = [] + @filter_redirect = [] + @helpers_paths = [] + @public_file_server = ActiveSupport::OrderedOptions.new + @public_file_server.enabled = true + @public_file_server.index_name = "index" + @force_ssl = false + @ssl_options = {} + @session_store = nil + @time_zone = "UTC" + @beginning_of_week = :monday + @log_level = :debug + @generators = app_generators + @cache_store = [ :file_store, "#{root}/tmp/cache/" ] + @railties_order = [:all] + @relative_url_root = ENV["RAILS_RELATIVE_URL_ROOT"] + @reload_classes_only_on_change = true + @file_watcher = ActiveSupport::FileUpdateChecker + @exceptions_app = nil + @autoflush_log = true + @log_formatter = ActiveSupport::Logger::SimpleFormatter.new + @eager_load = nil + @secret_token = nil + @secret_key_base = nil + @api_only = false + @debug_exception_response_format = nil + @x = Custom.new + @enable_dependency_loading = false + @read_encrypted_secrets = false + @content_security_policy = nil + @content_security_policy_report_only = false + @content_security_policy_nonce_generator = nil + @require_master_key = false + @loaded_config_version = nil end def load_defaults(target_version) @@ -71,7 +77,6 @@ module Rails end self.ssl_options = { hsts: { subdomains: true } } - when "5.1" load_defaults "5.0" @@ -82,7 +87,6 @@ module Rails if respond_to?(:action_view) action_view.form_with_generates_remote_forms = true end - when "5.2" load_defaults "5.1" @@ -100,15 +104,24 @@ module Rails if respond_to?(:active_support) active_support.use_authenticated_message_encryption = true + active_support.use_sha1_digests = true end if respond_to?(:action_controller) action_controller.default_protect_from_forgery = true end + if respond_to?(:action_view) + action_view.form_with_generates_ids = true + end + when "6.0" + load_defaults "5.2" + else raise "Unknown version #{target_version.to_s.inspect}" end + + @loaded_config_version = target_version end def encoding=(value) @@ -228,6 +241,14 @@ module Rails SourceAnnotationExtractor::Annotation end + def content_security_policy(&block) + if block_given? + @content_security_policy = ActionDispatch::ContentSecurityPolicy.new(&block) + else + @content_security_policy + end + 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 ea2273c1f2..433a7ab41f 100644 --- a/railties/lib/rails/application/default_middleware_stack.rb +++ b/railties/lib/rails/application/default_middleware_stack.rb @@ -63,9 +63,15 @@ module Rails middleware.use ::ActionDispatch::Flash end + unless config.api_only + middleware.use ::ActionDispatch::ContentSecurityPolicy::Middleware + end + middleware.use ::Rack::Head middleware.use ::Rack::ConditionalGet middleware.use ::Rack::ETag, "no-cache" + + middleware.use ::Rack::TempfileReaper unless config.api_only end end diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index 3d938be951..c4b188aeee 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -58,7 +58,7 @@ module Rails end # This needs to happen before eager load so it happens - # in exactly the same point regardless of config.cache_classes + # in exactly the same point regardless of config.eager_load initializer :run_prepare_callbacks do |app| app.reloader.prepare! end diff --git a/railties/lib/rails/command.rb b/railties/lib/rails/command.rb index 812e846837..078e9f937f 100644 --- a/railties/lib/rails/command.rb +++ b/railties/lib/rails/command.rb @@ -4,7 +4,6 @@ require "active_support" require "active_support/dependencies/autoload" require "active_support/core_ext/enumerable" require "active_support/core_ext/object/blank" -require "active_support/core_ext/hash/transform_values" require "thor" diff --git a/railties/lib/rails/command/helpers/editor.rb b/railties/lib/rails/command/helpers/editor.rb index 5e9ecc05e7..6191d97672 100644 --- a/railties/lib/rails/command/helpers/editor.rb +++ b/railties/lib/rails/command/helpers/editor.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/encrypted_file" module Rails diff --git a/railties/lib/rails/commands/credentials/credentials_command.rb b/railties/lib/rails/commands/credentials/credentials_command.rb index 8085f07c2b..fa54c0362a 100644 --- a/railties/lib/rails/commands/credentials/credentials_command.rb +++ b/railties/lib/rails/commands/credentials/credentials_command.rb @@ -20,7 +20,7 @@ module Rails require_application_and_environment! ensure_editor_available(command: "bin/rails credentials:edit") || (return) - ensure_master_key_has_been_added + ensure_master_key_has_been_added if Rails.application.credentials.key.nil? ensure_credentials_have_been_added catch_editing_exceptions do @@ -33,8 +33,7 @@ module Rails def show require_application_and_environment! - say Rails.application.credentials.read.presence || - "No credentials have been added yet. Use bin/rails credentials:edit to change that." + say Rails.application.credentials.read.presence || missing_credentials_message end private @@ -67,6 +66,14 @@ module Rails Rails::Generators::CredentialsGenerator.new end + + def missing_credentials_message + if Rails.application.credentials.key.nil? + "Missing master key to decrypt credentials. See bin/rails credentials:help" + else + "No credentials have been added yet. Use bin/rails credentials:edit to change that." + end + end end end end diff --git a/railties/lib/rails/commands/encrypted/encrypted_command.rb b/railties/lib/rails/commands/encrypted/encrypted_command.rb index 898094f1a4..3bc8f76ce4 100644 --- a/railties/lib/rails/commands/encrypted/encrypted_command.rb +++ b/railties/lib/rails/commands/encrypted/encrypted_command.rb @@ -21,9 +21,10 @@ module Rails def edit(file_path) require_application_and_environment! + encrypted = Rails.application.encrypted(file_path, key_path: options[:key]) ensure_editor_available(command: "bin/rails encrypted:edit") || (return) - ensure_encryption_key_has_been_added(options[:key]) + ensure_encryption_key_has_been_added(options[:key]) if encrypted.key.nil? ensure_encrypted_file_has_been_added(file_path, options[:key]) catch_editing_exceptions do @@ -37,9 +38,9 @@ module Rails def show(file_path) require_application_and_environment! + encrypted = Rails.application.encrypted(file_path, key_path: options[:key]) - say Rails.application.encrypted(file_path, key_path: options[:key]).read.presence || - "File '#{file_path}' does not exist. Use bin/rails encrypted:edit #{file_path} to change that." + say encrypted.read.presence || missing_encrypted_message(key: encrypted.key, key_path: options[:key], file_path: file_path) end private @@ -72,6 +73,14 @@ module Rails Rails::Generators::EncryptedFileGenerator.new end + + def missing_encrypted_message(key:, key_path:, file_path:) + if key.nil? + "Missing '#{key_path}' to decrypt data. See bin/rails encrypted:help" + else + "File '#{file_path}' does not exist. Use bin/rails encrypted:edit #{file_path} to change that." + end + end end end end diff --git a/railties/lib/rails/commands/secrets/secrets_command.rb b/railties/lib/rails/commands/secrets/secrets_command.rb index 73a88767e2..a36ccf314c 100644 --- a/railties/lib/rails/commands/secrets/secrets_command.rb +++ b/railties/lib/rails/commands/secrets/secrets_command.rb @@ -56,7 +56,7 @@ module Rails private def deprecate_in_favor_of_credentials_and_exit say "Encrypted secrets is deprecated in favor of credentials. Run:" - say "bin/rails credentials --help" + say "bin/rails credentials:help" exit 1 end diff --git a/railties/lib/rails/commands/server/server_command.rb b/railties/lib/rails/commands/server/server_command.rb index 703ec59087..e546fe3e4b 100644 --- a/railties/lib/rails/commands/server/server_command.rb +++ b/railties/lib/rails/commands/server/server_command.rb @@ -27,7 +27,7 @@ module Rails app = super if app.is_a?(Class) ActiveSupport::Deprecation.warn(<<-MSG.squish) - Use `Rails::Application` subclass to start the server is deprecated and will be removed in Rails 6.0. + Using `Rails::Application` subclass to start the server is deprecated and will be removed in Rails 6.0. Please change `run #{app}` to `run Rails.application` in config.ru. MSG end diff --git a/railties/lib/rails/gem_version.rb b/railties/lib/rails/gem_version.rb index 92b5e0392a..54bfbdd516 100644 --- a/railties/lib/rails/gem_version.rb +++ b/railties/lib/rails/gem_version.rb @@ -7,8 +7,8 @@ module Rails end module VERSION - MAJOR = 5 - MINOR = 2 + MAJOR = 6 + MINOR = 0 TINY = 0 PRE = "alpha" diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb index 5592e8d78e..6a7175c02b 100644 --- a/railties/lib/rails/generators.rb +++ b/railties/lib/rails/generators.rb @@ -218,6 +218,9 @@ module Rails rails.delete("app") rails.delete("plugin") rails.delete("encrypted_secrets") + rails.delete("encrypted_file") + rails.delete("encryption_key_file") + rails.delete("master_key") rails.delete("credentials") hidden_namespaces.each { |n| groups.delete(n.to_s) } @@ -274,8 +277,9 @@ module Rails else options = sorted_groups.flat_map(&:last) suggestions = options.sort_by { |suggested| levenshtein_distance(namespace.to_s, suggested) }.first(3) + suggestions.map! { |s| "'#{s}'" } msg = "Could not find generator '#{namespace}'. ".dup - msg << "Maybe you meant #{ suggestions.map { |s| "'#{s}'" }.to_sentence(last_word_connector: " or ", locale: :en) }\n" + msg << "Maybe you meant #{ suggestions[0...-1].join(', ')} or #{suggestions[-1]}\n" msg << "Run `rails generate --help` for more options." puts msg end diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb index 3362bf629a..d85bbfb03e 100644 --- a/railties/lib/rails/generators/actions.rb +++ b/railties/lib/rails/generators/actions.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require "active_support/core_ext/string/strip" + module Rails module Generators module Actions diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index 73256bec61..e1889979d7 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -2,7 +2,6 @@ require "fileutils" require "digest/md5" -require "active_support/core_ext/string/strip" require "rails/version" unless defined?(Rails::VERSION) require "open-uri" require "uri" @@ -84,6 +83,9 @@ module Rails class_option :skip_system_test, type: :boolean, default: false, desc: "Skip system test files" + class_option :skip_bootsnap, type: :boolean, default: false, + desc: "Skip bootsnap gem" + class_option :dev, type: :boolean, default: false, desc: "Setup the #{name} with Gemfile pointing to your Rails checkout" @@ -192,7 +194,7 @@ module Rails def webserver_gemfile_entry # :doc: return [] if options[:skip_puma] comment = "Use Puma as the app server" - GemfileEntry.new("puma", "~> 3.7", comment) + GemfileEntry.new("puma", "~> 3.11", comment) end def include_all_railties? # :doc: @@ -297,8 +299,8 @@ module Rails def gem_for_database # %w( mysql postgresql sqlite3 oracle frontbase ibm_db sqlserver jdbcmysql jdbcsqlite3 jdbcpostgresql ) case options[:database] - when "mysql" then ["mysql2", [">= 0.3.18", "< 0.5"]] - when "postgresql" then ["pg", ["~> 0.18"]] + when "mysql" then ["mysql2", ["~> 0.4.4"]] + when "postgresql" then ["pg", [">= 0.18", "< 2.0"]] when "oracle" then ["activerecord-oracle_enhanced-adapter", nil] when "frontbase" then ["ruby-frontbase", nil] when "sqlserver" then ["activerecord-sqlserver-adapter", nil] @@ -312,11 +314,13 @@ module Rails def convert_database_option_for_jruby if defined?(JRUBY_VERSION) - case options[:database] - when "postgresql" then options[:database].replace "jdbcpostgresql" - when "mysql" then options[:database].replace "jdbcmysql" - when "sqlite3" then options[:database].replace "jdbcsqlite3" + opt = options.dup + case opt[:database] + when "postgresql" then opt[:database] = "jdbcpostgresql" + when "mysql" then opt[:database] = "jdbcmysql" + when "sqlite3" then opt[:database] = "jdbcsqlite3" end + self.options = opt.freeze end end @@ -435,6 +439,10 @@ module Rails !options[:skip_listen] && os_supports_listen_out_of_the_box? end + def depend_on_bootsnap? + !options[:skip_bootsnap] && !options[:dev] + end + def os_supports_listen_out_of_the_box? RbConfig::CONFIG["host_os"] =~ /darwin|linux/ end @@ -456,16 +464,6 @@ module Rails end end - def run_active_storage - unless skip_active_storage? - if bundle_install? - rails_command "active_storage:install", capture: options[:quiet] - else - log("Active Storage installation was skipped. Please run `bin/rails active_storage:install` to install Active Storage files.") - end - end - end - def empty_directory_with_keep_file(destination, config = {}) empty_directory(destination, config) keep_file(destination) diff --git a/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb.tt b/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb.tt index 0eb9d82bbb..518cb1121e 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb.tt +++ b/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb.tt @@ -15,15 +15,15 @@ <div class="field"> <% if attribute.password_digest? -%> <%%= form.label :password %> - <%%= form.password_field :password, id: :<%= field_id(:password) %> %> + <%%= form.password_field :password %> </div> <div class="field"> <%%= form.label :password_confirmation %> - <%%= form.password_field :password_confirmation, id: :<%= field_id(:password_confirmation) %> %> + <%%= form.password_field :password_confirmation %> <% else -%> <%%= form.label :<%= attribute.column_name %> %> - <%%= form.<%= attribute.field_type %> :<%= attribute.column_name %>, id: :<%= field_id(attribute.column_name) %> %> + <%%= form.<%= attribute.field_type %> :<%= attribute.column_name %> %> <% end -%> </div> diff --git a/railties/lib/rails/generators/generated_attribute.rb b/railties/lib/rails/generators/generated_attribute.rb index 2728459968..f7fd30a5fb 100644 --- a/railties/lib/rails/generators/generated_attribute.rb +++ b/railties/lib/rails/generators/generated_attribute.rb @@ -75,7 +75,7 @@ module Rails when :date then :date_select when :text then :text_area when :boolean then :check_box - else + else :text_field end end @@ -91,7 +91,7 @@ module Rails when :text then "MyText" when :boolean then false when :references, :belongs_to then nil - else + else "" end end diff --git a/railties/lib/rails/generators/named_base.rb b/railties/lib/rails/generators/named_base.rb index 99165168fd..d6732f8ff1 100644 --- a/railties/lib/rails/generators/named_base.rb +++ b/railties/lib/rails/generators/named_base.rb @@ -31,12 +31,8 @@ module Rails end end - # TODO Change this to private once we've dropped Ruby 2.2 support. - # Workaround for Ruby 2.2 "private attribute?" warning. - protected - attr_reader :file_name - private + attr_reader :file_name # FIXME: We are avoiding to use alias because a bug on thor that make # this method public and add it to the task list. @@ -114,10 +110,6 @@ module Rails "new_#{singular_route_name}_url" end - def field_id(attribute_name) - [singular_table_name, attribute_name].join("_") - end - def singular_table_name # :doc: @singular_table_name ||= (pluralize_table_names? ? table_name.singularize : table_name) end diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 1fdfc3ca52..5ee9ae05e3 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -128,6 +128,9 @@ module Rails active_storage_config_exist = File.exist?("config/storage.yml") rack_cors_config_exist = File.exist?("config/initializers/cors.rb") assets_config_exist = File.exist?("config/initializers/assets.rb") + csp_config_exist = File.exist?("config/initializers/content_security_policy.rb") + + @config_target_version = Rails.application.config.loaded_config_version || "5.0" config @@ -155,6 +158,10 @@ module Rails unless assets_config_exist remove_file "config/initializers/assets.rb" end + + unless csp_config_exist + remove_file "config/initializers/content_security_policy.rb" + end end end @@ -162,7 +169,7 @@ module Rails return if options[:pretend] || options[:dummy_app] require "rails/generators/rails/master_key/master_key_generator" - master_key_generator = Rails::Generators::MasterKeyGenerator.new([], quiet: options[:quiet]) + master_key_generator = Rails::Generators::MasterKeyGenerator.new([], quiet: options[:quiet], force: options[:force]) master_key_generator.add_master_key_file_silently master_key_generator.ignore_master_key_file_silently end @@ -228,6 +235,10 @@ module Rails def vendor empty_directory_with_keep_file "vendor" end + + def config_target_version + defined?(@config_target_version) ? @config_target_version : Rails::VERSION::STRING.to_f + end end module Generators @@ -237,7 +248,7 @@ module Rails RESERVED_NAMES = %w[application destroy plugin runner test] class AppGenerator < AppBase # :nodoc: - WEBPACKS = %w( react vue angular elm ) + WEBPACKS = %w( react vue angular elm stimulus ) add_shared_options_for "application" @@ -343,6 +354,14 @@ module Rails build(:public_directory) end + def create_tmp_files + build(:tmp) + end + + def create_vendor_files + build(:vendor) + end + def create_test_files build(:test) unless options[:skip_test] end @@ -355,14 +374,6 @@ module Rails build(:storage) unless skip_active_storage? end - def create_tmp_files - build(:tmp) - end - - def create_vendor_files - build(:vendor) - end - def delete_app_assets_if_api_option if options[:api] remove_dir "app/assets" @@ -378,9 +389,13 @@ module Rails end end - def delete_application_layout_file_if_api_option + def delete_app_views_if_api_option if options[:api] - remove_file "app/views/layouts/application.html.erb" + if options[:skip_action_mailer] + remove_dir "app/views" + else + remove_file "app/views/layouts/application.html.erb" + end end end @@ -432,6 +447,7 @@ module Rails def delete_non_api_initializers_if_api_option if options[:api] remove_file "config/initializers/cookies_serializer.rb" + remove_file "config/initializers/content_security_policy.rb" end end @@ -457,7 +473,6 @@ module Rails public_task :apply_rails_template, :run_bundle public_task :run_webpack, :generate_spring_binstubs - public_task :run_active_storage def run_after_bundle_callbacks @after_bundle_callbacks.each(&:call) diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile.tt b/railties/lib/rails/generators/rails/app/templates/Gemfile.tt index 61026f5182..23bb89f4ce 100644 --- a/railties/lib/rails/generators/rails/app/templates/Gemfile.tt +++ b/railties/lib/rails/generators/rails/app/templates/Gemfile.tt @@ -29,9 +29,11 @@ ruby <%= "'#{RUBY_VERSION}'" -%> # Use Capistrano for deployment # gem 'capistrano-rails', group: :development +<% if depend_on_bootsnap? -%> # Reduces boot times through caching; required in config/boot.rb gem 'bootsnap', '>= 1.1.0', require: false +<%- end -%> <%- if options.api? -%> # Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin AJAX possible # gem 'rack-cors' @@ -41,13 +43,6 @@ gem 'bootsnap', '>= 1.1.0', require: false group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] - <%- if depends_on_system_test? -%> - # Adds support for Capybara system testing and selenium driver - gem 'capybara', '~> 2.15' - gem 'selenium-webdriver' - # Easy installation and use of chromedriver to run system tests with Chrome - gem 'chromedriver-helper' - <%- end -%> end group :development do @@ -70,6 +65,16 @@ group :development do <% end -%> <% end -%> end + +<%- if depends_on_system_test? -%> +group :test do + # Adds support for Capybara system testing and selenium driver + gem 'capybara', '~> 2.15' + gem 'selenium-webdriver' + # Easy installation and use of chromedriver to run system tests with Chrome + gem 'chromedriver-helper' +end +<%- end -%> <% end -%> # Windows does not include zoneinfo files, so bundle the tzinfo-data gem 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 5460155b3e..ef715f1368 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 @@ -3,6 +3,7 @@ <head> <title><%= camelized %></title> <%%= csrf_meta_tags %> + <%%= csp_meta_tag %> <%- if options[:skip_javascript] -%> <%%= stylesheet_link_tag 'application', media: 'all' %> diff --git a/railties/lib/rails/generators/rails/app/templates/bin/yarn.tt b/railties/lib/rails/generators/rails/app/templates/bin/yarn.tt index b4e4d95286..90ddcc520e 100644 --- a/railties/lib/rails/generators/rails/app/templates/bin/yarn.tt +++ b/railties/lib/rails/generators/rails/app/templates/bin/yarn.tt @@ -1,7 +1,7 @@ APP_ROOT = File.expand_path('..', __dir__) Dir.chdir(APP_ROOT) do begin - exec "yarnpkg #{ARGV.join(' ')}" + exec "yarnpkg", *ARGV rescue Errno::ENOENT $stderr.puts "Yarn executable was not detected in the system." $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install" diff --git a/railties/lib/rails/generators/rails/app/templates/config/application.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/application.rb.tt index 9e03e86771..9a427113c7 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/application.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb.tt @@ -24,11 +24,12 @@ Bundler.require(*Rails.groups) module <%= app_const_base %> class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. - config.load_defaults <%= Rails::VERSION::STRING.to_f %> + config.load_defaults <%= build(:config_target_version) %> # Settings in config/environments/* take precedence over those specified here. - # Application configuration should go into files in config/initializers - # -- all .rb files in that directory are automatically loaded. + # Application configuration can go into files in config/initializers + # -- all .rb files in that directory are automatically loaded after loading + # the framework and any gems in your application. <%- if options.api? -%> # Only loads a smaller set of middleware suitable for API only apps. diff --git a/railties/lib/rails/generators/rails/app/templates/config/boot.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/boot.rb.tt index b9e460cef3..42d46b8175 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/boot.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/boot.rb.tt @@ -1,4 +1,6 @@ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) require 'bundler/setup' # Set up gems listed in the Gemfile. +<% if depend_on_bootsnap? -%> require 'bootsnap/setup' # Speed up boot time by caching expensive operations. +<%- end -%> 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 b383228dc0..a87649b50f 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 @@ -14,7 +14,7 @@ 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? + if Rails.root.join('tmp', 'caching-dev.txt').exist? config.action_controller.perform_caching = true config.cache_store = :memory_store @@ -46,6 +46,9 @@ Rails.application.configure do # Raise an error on page load if there are pending migrations. config.active_record.migration_error = :page_load + # Highlight code that triggered database queries in logs. + config.active_record.verbose_query_logs = true + <%- end -%> <%- unless options.skip_sprockets? -%> # Debug mode disables concatenation and preprocessing of assets. 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 4c0f36db98..926326b5bb 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 @@ -34,8 +34,6 @@ Rails.application.configure do # Do not fallback to assets pipeline if a precompiled asset is missed. config.assets.compile = false - # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb - <%- end -%> # Enable serving of images, stylesheets, and JavaScripts from an asset server. # config.action_controller.asset_host = 'http://assets.example.com' 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 new file mode 100644 index 0000000000..d3bcaa5ec8 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt @@ -0,0 +1,25 @@ +# Be sure to restart your server when you modify this file. + +# Define an application-wide content security policy +# For further information see the following documentation +# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy + +# Rails.application.config.content_security_policy do |policy| +# policy.default_src :self, :https +# policy.font_src :self, :https, :data +# policy.img_src :self, :https, :data +# policy.object_src :none +# policy.script_src :self, :https +# policy.style_src :self, :https + +# # Specify URI for violation reports +# # policy.report_uri "/csp-violation-report-endpoint" +# end + +# If you are using UJS then enable automatic nonce generation +# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) } + +# 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 +# Rails.application.config.content_security_policy_report_only = true diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_5_2.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_5_2.rb.tt index 25dcddb27a..b4ef455802 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_5_2.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_5_2.rb.tt @@ -10,7 +10,7 @@ # This is needed for recyclable cache keys. # Rails.application.config.active_record.cache_versioning = true -# Use AES 256 GCM authenticated encryption for encrypted cookies. +# Use AES-256-GCM authenticated encryption for encrypted cookies. # Existing cookies will be converted on read then written with the new scheme. # Rails.application.config.action_dispatch.use_authenticated_cookie_encryption = true @@ -25,3 +25,6 @@ # Store boolean values are in sqlite3 databases as 1 and 0 instead of 't' and # 'f' after migrating old data. # Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true + +# Use SHA-1 instead of MD5 to generate non-sensitive digests, such as the ETag header. +# Rails.application.config.active_support.use_sha1_digests = 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 1e19380dcb..a5eccf816b 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 @@ -26,31 +26,9 @@ environment ENV.fetch("RAILS_ENV") { "development" } # Use the `preload_app!` method when specifying a `workers` number. # This directive tells Puma to first boot the application and load code # before forking the application. This takes advantage of Copy On Write -# process behavior so workers use less memory. If you use this option -# you need to make sure to reconnect any threads in the `on_worker_boot` -# block. +# process behavior so workers use less memory. # # preload_app! -# If you are preloading your application and using Active Record, it's -# recommended that you close any connections to the database before workers -# are forked to prevent connection leakage. -# -# before_fork do -# ActiveRecord::Base.connection_pool.disconnect! if defined?(ActiveRecord) -# end - -# The code in the `on_worker_boot` will be called if you are using -# clustered mode by specifying a number of `workers`. After each worker -# process is booted, this block will be run. If you are using the `preload_app!` -# option, you will want to use this block to reconnect to any threads -# or connections that may have been created at application boot, as Ruby -# cannot share connections between processes. -# -# on_worker_boot do -# ActiveRecord::Base.establish_connection if defined?(ActiveRecord) -# end -# - # Allow puma to be restarted by `rails restart` command. plugin :tmp_restart diff --git a/railties/lib/rails/generators/rails/app/templates/config/storage.yml.tt b/railties/lib/rails/generators/rails/app/templates/config/storage.yml.tt index 9bada4b66d..1c0cde0b09 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/storage.yml.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/storage.yml.tt @@ -18,7 +18,7 @@ local: # google: # service: GCS # project: your_project -# keyfile: <%%= Rails.root.join("path/to/gcs.keyfile") %> +# credentials: <%%= Rails.root.join("path/to/gcs.keyfile") %> # bucket: your_own_bucket # Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) diff --git a/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb.tt b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb.tt index 6ad1f11781..c918b57eca 100644 --- a/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb.tt @@ -1,7 +1,15 @@ +ENV['RAILS_ENV'] ||= 'test' require_relative '../config/environment' require 'rails/test_help' class ActiveSupport::TestCase + # Run tests in parallel with specified workers +<% if defined?(JRUBY_VERSION) -%> + parallelize(workers: 2, with: :threads) +<%- else -%> + parallelize(workers: 2) +<% end -%> + <% unless options[:skip_active_record] -%> # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. fixtures :all diff --git a/railties/lib/rails/generators/rails/controller/controller_generator.rb b/railties/lib/rails/generators/rails/controller/controller_generator.rb index 6d45d6e8f8..6e2495d45f 100644 --- a/railties/lib/rails/generators/rails/controller/controller_generator.rb +++ b/railties/lib/rails/generators/rails/controller/controller_generator.rb @@ -16,6 +16,7 @@ module Rails def add_routes return if options[:skip_routes] + return if actions.empty? route generate_routing_code end diff --git a/railties/lib/rails/generators/rails/credentials/credentials_generator.rb b/railties/lib/rails/generators/rails/credentials/credentials_generator.rb index ab15da5423..719e0c1e4c 100644 --- a/railties/lib/rails/generators/rails/credentials/credentials_generator.rb +++ b/railties/lib/rails/generators/rails/credentials/credentials_generator.rb @@ -6,9 +6,9 @@ require "active_support/encrypted_configuration" module Rails module Generators - class CredentialsGenerator < Base + class CredentialsGenerator < Base # :nodoc: def add_credentials_file - unless credentials.exist? + unless credentials.content_path.exist? template = credentials_template say "Adding #{credentials.content_path} to store encrypted credentials." @@ -26,21 +26,30 @@ module Rails end def add_credentials_file_silently(template = nil) - credentials.write(credentials_template) + unless credentials.content_path.exist? + credentials.write(credentials_template) + end end private def credentials - ActiveSupport::EncryptedConfiguration.new \ + ActiveSupport::EncryptedConfiguration.new( config_path: "config/credentials.yml.enc", key_path: "config/master.key", - env_key: "RAILS_MASTER_KEY" + env_key: "RAILS_MASTER_KEY", + raise_if_missing_key: true + ) end def credentials_template - "# aws:\n# access_key_id: 123\n# secret_access_key: 345\n\n" + - "# Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies.\n" + - "secret_key_base: #{SecureRandom.hex(64)}" + <<~YAML + # aws: + # access_key_id: 123 + # secret_access_key: 345 + + # Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies. + secret_key_base: #{SecureRandom.hex(64)} + YAML end end end diff --git a/railties/lib/rails/generators/rails/encrypted_file/encrypted_file_generator.rb b/railties/lib/rails/generators/rails/encrypted_file/encrypted_file_generator.rb index ddce5f6fe2..867e28c6db 100644 --- a/railties/lib/rails/generators/rails/encrypted_file/encrypted_file_generator.rb +++ b/railties/lib/rails/generators/rails/encrypted_file/encrypted_file_generator.rb @@ -5,33 +5,22 @@ require "active_support/encrypted_file" module Rails module Generators - class EncryptedFileGenerator < Base - def add_encrypted_file(file_path, key_path) - unless File.exist?(file_path) - say "Adding #{file_path} to store encrypted content." - say "" - say "The following content has been encrypted with the encryption key:" - say "" - say template, :on_green - say "" - - add_encrypted_file_silently(file_path, key_path) - - say "You can edit encrypted file with `bin/rails encrypted:edit #{file_path}`." - say "" - end - end - + class EncryptedFileGenerator < Base # :nodoc: def add_encrypted_file_silently(file_path, key_path, template = encrypted_file_template) unless File.exist?(file_path) - setup = { content_path: file_path, key_path: key_path, env_key: "RAILS_MASTER_KEY" } + setup = { content_path: file_path, key_path: key_path, env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true } ActiveSupport::EncryptedFile.new(setup).write(template) end end private def encrypted_file_template - "# aws:\n# access_key_id: 123\n# secret_access_key: 345\n\n" + <<~YAML + # aws: + # access_key_id: 123 + # secret_access_key: 345 + + YAML end end end diff --git a/railties/lib/rails/generators/rails/encryption_key_file/encryption_key_file_generator.rb b/railties/lib/rails/generators/rails/encryption_key_file/encryption_key_file_generator.rb index a396a9661f..90068c678d 100644 --- a/railties/lib/rails/generators/rails/encryption_key_file/encryption_key_file_generator.rb +++ b/railties/lib/rails/generators/rails/encryption_key_file/encryption_key_file_generator.rb @@ -6,7 +6,7 @@ require "active_support/encrypted_file" module Rails module Generators - class EncryptionKeyFileGenerator < Base + class EncryptionKeyFileGenerator < Base # :nodoc: def add_key_file(key_path) key_path = Pathname.new(key_path) diff --git a/railties/lib/rails/generators/rails/master_key/master_key_generator.rb b/railties/lib/rails/generators/rails/master_key/master_key_generator.rb index 7f57340c11..21664ea86d 100644 --- a/railties/lib/rails/generators/rails/master_key/master_key_generator.rb +++ b/railties/lib/rails/generators/rails/master_key/master_key_generator.rb @@ -7,7 +7,7 @@ require "active_support/encrypted_file" module Rails module Generators - class MasterKeyGenerator < Base + class MasterKeyGenerator < Base # :nodoc: MASTER_KEY_PATH = Pathname.new("config/master.key") def add_master_key_file @@ -27,7 +27,9 @@ module Rails end def add_master_key_file_silently(key = nil) - key_file_generator.add_key_file_silently(MASTER_KEY_PATH, key) + unless MASTER_KEY_PATH.exist? + key_file_generator.add_key_file_silently(MASTER_KEY_PATH, key) + end end def ignore_master_key_file diff --git a/railties/lib/rails/generators/rails/plugin/templates/app/controllers/%namespaced_name%/application_controller.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/controllers/%namespaced_name%/application_controller.rb.tt index abbacd9bec..b86ef0f2f8 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/app/controllers/%namespaced_name%/application_controller.rb.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/app/controllers/%namespaced_name%/application_controller.rb.tt @@ -1,4 +1,4 @@ -<%= wrap_in_modules <<-rb.strip_heredoc +<%= wrap_in_modules <<~rb class ApplicationController < ActionController::#{api? ? "API" : "Base"} #{ api? ? '# ' : '' }protect_from_forgery with: :exception end diff --git a/railties/lib/rails/generators/rails/plugin/templates/app/helpers/%namespaced_name%/application_helper.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/helpers/%namespaced_name%/application_helper.rb.tt index 25d692732d..be078f36de 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/app/helpers/%namespaced_name%/application_helper.rb.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/app/helpers/%namespaced_name%/application_helper.rb.tt @@ -1,4 +1,4 @@ -<%= wrap_in_modules <<-rb.strip_heredoc +<%= wrap_in_modules <<~rb module ApplicationHelper end rb diff --git a/railties/lib/rails/generators/rails/plugin/templates/app/jobs/%namespaced_name%/application_job.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/jobs/%namespaced_name%/application_job.rb.tt index bad1ff2d16..846863bc13 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/app/jobs/%namespaced_name%/application_job.rb.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/app/jobs/%namespaced_name%/application_job.rb.tt @@ -1,4 +1,4 @@ -<%= wrap_in_modules <<-rb.strip_heredoc +<%= wrap_in_modules <<~rb class ApplicationJob < ActiveJob::Base end rb diff --git a/railties/lib/rails/generators/rails/plugin/templates/app/mailers/%namespaced_name%/application_mailer.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/mailers/%namespaced_name%/application_mailer.rb.tt index 09aac13f42..246e274348 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/app/mailers/%namespaced_name%/application_mailer.rb.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/app/mailers/%namespaced_name%/application_mailer.rb.tt @@ -1,4 +1,4 @@ -<%= wrap_in_modules <<-rb.strip_heredoc +<%= wrap_in_modules <<~rb class ApplicationMailer < ActionMailer::Base default from: 'from@example.com' layout 'mailer' diff --git a/railties/lib/rails/generators/rails/plugin/templates/app/models/%namespaced_name%/application_record.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/models/%namespaced_name%/application_record.rb.tt index 8aa3de78f1..21465278be 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/app/models/%namespaced_name%/application_record.rb.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/app/models/%namespaced_name%/application_record.rb.tt @@ -1,4 +1,4 @@ -<%= wrap_in_modules <<-rb.strip_heredoc +<%= wrap_in_modules <<~rb class ApplicationRecord < ActiveRecord::Base self.abstract_class = true end diff --git a/railties/lib/rails/generators/rails/plugin/templates/app/views/layouts/%namespaced_name%/application.html.erb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/views/layouts/%namespaced_name%/application.html.erb.tt index 6bc480161d..6e54a1ce9d 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/app/views/layouts/%namespaced_name%/application.html.erb.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/app/views/layouts/%namespaced_name%/application.html.erb.tt @@ -2,9 +2,13 @@ <html> <head> <title><%= humanized %></title> + <%%= csrf_meta_tags %> + <%%= csp_meta_tag %> + <%%= stylesheet_link_tag "<%= namespaced_name %>/application", media: "all" %> + <%- unless options[:skip_javascript] -%> <%%= javascript_include_tag "<%= namespaced_name %>/application" %> - <%%= csrf_meta_tags %> + <%- end -%> </head> <body> diff --git a/railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt b/railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt index b3264509fc..ee8e469da2 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt @@ -19,10 +19,10 @@ require "rails" require "active_model/railtie" require "active_job/railtie" <%= comment_if :skip_active_record %>require "active_record/railtie" +<%= comment_if :skip_active_storage %>require "active_storage/engine" require "action_controller/railtie" <%= comment_if :skip_action_mailer %>require "action_mailer/railtie" require "action_view/railtie" -require "active_storage/engine" <%= comment_if :skip_action_cable %>require "action_cable/engine" <%= comment_if :skip_sprockets %>require "sprockets/railtie" <%= comment_if :skip_test %>require "rails/test_unit/railtie" diff --git a/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/engine.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/engine.rb.tt index 8938770fc4..4ec1804940 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/engine.rb.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/engine.rb.tt @@ -1,4 +1,4 @@ -<%= wrap_in_modules <<-rb.strip_heredoc +<%= wrap_in_modules <<~rb class Engine < ::Rails::Engine #{mountable? ? ' isolate_namespace ' + camelized_modules : ' '} #{api? ? " config.generators.api_only = true" : ' '} diff --git a/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/railtie.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/railtie.rb.tt index 7bdf4ee5fb..b853fabcc3 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/railtie.rb.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/railtie.rb.tt @@ -1,4 +1,4 @@ -<%= wrap_in_modules <<-rb.strip_heredoc +<%= wrap_in_modules <<~rb class Railtie < ::Rails::Railtie end rb diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js.tt b/railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js.tt index f3d80c87f5..51049826bf 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js.tt @@ -10,6 +10,7 @@ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details // about supported directives. // +//= require rails-ujs <% unless skip_active_storage? -%> //= require activestorage <% end -%> diff --git a/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt index 7fa9973931..755d19ef5d 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt @@ -1,3 +1,6 @@ +# Configure Rails Environment +ENV["RAILS_ENV"] = "test" + require_relative "<%= File.join('..', options[:dummy_path], 'config/environment') -%>" <% unless options[:skip_active_record] -%> ActiveRecord::Migrator.migrations_paths = [File.expand_path("../<%= options[:dummy_path] -%>/db/migrate", __dir__)] diff --git a/railties/lib/rails/generators/resource_helpers.rb b/railties/lib/rails/generators/resource_helpers.rb index a146a8fda6..5675faff70 100644 --- a/railties/lib/rails/generators/resource_helpers.rb +++ b/railties/lib/rails/generators/resource_helpers.rb @@ -25,13 +25,8 @@ module Rails assign_controller_names!(controller_name.pluralize) end - # TODO Change this to private once we've dropped Ruby 2.2 support. - # Workaround for Ruby 2.2 "private attribute?" warning. - protected - - attr_reader :controller_name, :controller_file_name - private + attr_reader :controller_name, :controller_file_name def controller_class_path if options[:model_name] 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 b6c13b41ae..e2e8b18eab 100644 --- a/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb @@ -23,7 +23,7 @@ module TestUnit # :nodoc: template template_file, File.join("test/controllers", controller_class_path, "#{controller_file_name}_controller_test.rb") - unless options.api? || options[:system_tests].nil? + if !options.api? && options[:system_tests] template "system_test.rb", File.join("test/system", class_path, "#{file_name.pluralize}_test.rb") end end diff --git a/railties/lib/rails/info.rb b/railties/lib/rails/info.rb index d8f361f524..d5c9973c6b 100644 --- a/railties/lib/rails/info.rb +++ b/railties/lib/rails/info.rb @@ -99,7 +99,7 @@ module Rails end property "Database schema version" do - ActiveRecord::Migrator.current_version rescue nil + ActiveRecord::Base.connection.migration_context.current_version rescue nil end end end diff --git a/railties/lib/rails/mailers_controller.rb b/railties/lib/rails/mailers_controller.rb index 66636e5d6b..0b0e802358 100644 --- a/railties/lib/rails/mailers_controller.rb +++ b/railties/lib/rails/mailers_controller.rb @@ -6,9 +6,9 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc: prepend_view_path ActionDispatch::DebugExceptions::RESCUES_TEMPLATE_PATH before_action :require_local!, unless: :show_previews? - before_action :find_preview, only: :preview + before_action :find_preview, :set_locale, only: :preview - helper_method :part_query + helper_method :part_query, :locale_query def index @previews = ActionMailer::Preview.all @@ -84,4 +84,12 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc: def part_query(mime_type) request.query_parameters.merge(part: mime_type).to_query end + + def locale_query(locale) + request.query_parameters.merge(locale: locale).to_query + end + + def set_locale + I18n.locale = params[:locale] || I18n.default_locale + end end diff --git a/railties/lib/rails/railtie/configuration.rb b/railties/lib/rails/railtie/configuration.rb index 48853129bc..70274b948c 100644 --- a/railties/lib/rails/railtie/configuration.rb +++ b/railties/lib/rails/railtie/configuration.rb @@ -55,7 +55,7 @@ module Rails ActiveSupport.on_load(:before_configuration, yield: true, &block) end - # Third configurable block to run. Does not run if +config.cache_classes+ + # Third configurable block to run. Does not run if +config.eager_load+ # set to false. def before_eager_load(&block) ActiveSupport.on_load(:before_eager_load, yield: true, &block) diff --git a/railties/lib/rails/ruby_version_check.rb b/railties/lib/rails/ruby_version_check.rb index 76b6b80d28..f8d3311156 100644 --- a/railties/lib/rails/ruby_version_check.rb +++ b/railties/lib/rails/ruby_version_check.rb @@ -1,15 +1,15 @@ # frozen_string_literal: true -if RUBY_VERSION < "2.2.2" && RUBY_ENGINE == "ruby" +if RUBY_VERSION < "2.4.1" && RUBY_ENGINE == "ruby" desc = defined?(RUBY_DESCRIPTION) ? RUBY_DESCRIPTION : "ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE})" abort <<-end_message - Rails 5 requires Ruby 2.2.2 or newer. + Rails 6 requires Ruby 2.4.1 or newer. You're running #{desc} - Please upgrade to Ruby 2.2.2 or newer to continue. + Please upgrade to Ruby 2.4.1 or newer to continue. end_message end diff --git a/railties/lib/rails/secrets.rb b/railties/lib/rails/secrets.rb index 30e3478c9b..747cf31d7a 100644 --- a/railties/lib/rails/secrets.rb +++ b/railties/lib/rails/secrets.rb @@ -2,7 +2,6 @@ require "yaml" require "active_support/message_encryptor" -require "active_support/core_ext/string/strip" module Rails # Greatly inspired by Ara T. Howard's magnificent sekrets gem. 😘 diff --git a/railties/lib/rails/tasks/engine.rake b/railties/lib/rails/tasks/engine.rake index 9db9d78ec4..8d77904210 100644 --- a/railties/lib/rails/tasks/engine.rake +++ b/railties/lib/rails/tasks/engine.rake @@ -53,7 +53,7 @@ namespace :db do desc "Rolls the schema back to the previous version (specify steps w/ STEP=n)." app_task "rollback" - desc "Create a db/schema.rb file that can be portably used against any DB supported by Active Record" + desc "Create a db/schema.rb file that can be portably used against any database supported by Active Record" app_task "schema:dump" desc "Load a schema.rb file into the database" @@ -62,7 +62,7 @@ namespace :db do desc "Load the seed data from db/seeds.rb" app_task "seed" - desc "Create the database, load the schema, and initialize with the seed data (use db:reset to also drop the db first)" + desc "Create the database, load the schema, and initialize with the seed data (use db:reset to also drop the database first)" app_task "setup" desc "Dump the database structure to an SQL file" diff --git a/railties/lib/rails/templates/rails/mailers/email.html.erb b/railties/lib/rails/templates/rails/mailers/email.html.erb index 89c1129f90..2a41c29602 100644 --- a/railties/lib/rails/templates/rails/mailers/email.html.erb +++ b/railties/lib/rails/templates/rails/mailers/email.html.erb @@ -95,11 +95,25 @@ </dd> <% end %> + <dt>Format:</dt> <% if @email.multipart? %> <dd> - <select onchange="formatChanged(this);"> - <option <%= request.format == Mime[:html] ? 'selected' : '' %> value="?<%= part_query('text/html') %>">View as HTML email</option> - <option <%= request.format == Mime[:text] ? 'selected' : '' %> value="?<%= part_query('text/plain') %>">View as plain-text email</option> + <select id="part" onchange="refreshBody();"> + <option <%= request.format == Mime[:html] ? 'selected' : '' %> value="<%= part_query('text/html') %>">View as HTML email</option> + <option <%= request.format == Mime[:text] ? 'selected' : '' %> value="<%= part_query('text/plain') %>">View as plain-text email</option> + </select> + </dd> + <% else %> + <dd id="mime_type" data-mime-type="<%= part_query(@email.mime_type) %>"><%= @email.mime_type == 'text/html' ? 'HTML email' : 'plain-text email' %></dd> + <% end %> + + <% if I18n.available_locales.count > 1 %> + <dt>Locale:</dt> + <dd> + <select id="locale" onchange="refreshBody();"> + <% I18n.available_locales.each do |locale| %> + <option <%= I18n.locale == locale ? 'selected' : '' %> value="<%= locale_query(locale) %>"><%= locale %></option> + <% end %> </select> </dd> <% end %> @@ -116,15 +130,27 @@ <% end %> <script> - function formatChanged(form) { - var part_name = form.options[form.selectedIndex].value - var iframe =document.getElementsByName('messageBody')[0]; - iframe.contentWindow.location.replace(part_name); + function refreshBody() { + var part_select = document.querySelector('select#part'); + var locale_select = document.querySelector('select#locale'); + var iframe = document.getElementsByName('messageBody')[0]; + var part_param = part_select ? + part_select.options[part_select.selectedIndex].value : + document.querySelector('#mime_type').dataset.mimeType; + var locale_param = locale_select ? locale_select.options[locale_select.selectedIndex].value : null; + var fresh_location; + if (locale_param) { + fresh_location = '?' + part_param + '&' + locale_param; + } else { + fresh_location = '?' + part_param; + } + iframe.contentWindow.location = fresh_location; if (history.replaceState) { - var url = location.pathname.replace(/\.(txt|html)$/, ''); - var format = /html/.test(part_name) ? '.html' : '.txt'; - window.history.replaceState({}, '', url + format); + var url = location.pathname.replace(/\.(txt|html)$/, ''); + var format = /html/.test(part_param) ? '.html' : '.txt'; + var state_to_replace = locale_param ? (url + format + '?' + locale_param) : (url + format); + window.history.replaceState({}, '', state_to_replace); } } </script> diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb index 732c5c1e1f..4bd7d74b04 100644 --- a/railties/lib/rails/test_help.rb +++ b/railties/lib/rails/test_help.rb @@ -22,6 +22,7 @@ if defined?(ActiveRecord::Base) module ActiveSupport class TestCase + include ActiveRecord::TestDatabases include ActiveRecord::TestFixtures self.fixture_path = "#{Rails.root}/test/fixtures/" self.file_fixture_path = fixture_path + "files" @@ -29,10 +30,6 @@ if defined?(ActiveRecord::Base) end ActionDispatch::IntegrationTest.fixture_path = ActiveSupport::TestCase.fixture_path - - def create_fixtures(*fixture_set_names, &block) - FixtureSet.create_fixtures(ActiveSupport::TestCase.fixture_path, fixture_set_names, {}, &block) - end end # :enddoc: diff --git a/railties/lib/rails/test_unit/reporter.rb b/railties/lib/rails/test_unit/reporter.rb index 7d3164f1eb..28b93cee5a 100644 --- a/railties/lib/rails/test_unit/reporter.rb +++ b/railties/lib/rails/test_unit/reporter.rb @@ -64,11 +64,17 @@ module Rails end def format_line(result) - "%s#%s = %.2f s = %s" % [result.class, result.name, result.time, result.result_code] + klass = result.respond_to?(:klass) ? result.klass : result.class + "%s#%s = %.2f s = %s" % [klass, result.name, result.time, result.result_code] end def format_rerun_snippet(result) - location, line = result.method(result.name).source_location + location, line = if result.respond_to?(:source_location) + result.source_location + else + result.method(result.name).source_location + end + "#{executable} #{relative_path_for(location)}:#{line}" end diff --git a/railties/lib/rails/test_unit/runner.rb b/railties/lib/rails/test_unit/runner.rb index 5c2f6451e2..de5744c662 100644 --- a/railties/lib/rails/test_unit/runner.rb +++ b/railties/lib/rails/test_unit/runner.rb @@ -13,7 +13,7 @@ module Rails class << self def attach_before_load_options(opts) opts.on("--warnings", "-w", "Run with Ruby warnings enabled") {} - opts.on("--environment", "-e", "Run tests in the ENV environment") {} + opts.on("-e", "--environment ENV", "Run tests in the ENV environment") {} end def parse_options(argv) |