diff options
Diffstat (limited to 'railties')
67 files changed, 771 insertions, 265 deletions
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index 761e2f4ded..73793be78c 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,3 +1,55 @@ +* Deprecate support of use `Rails::Application` subclass to start Rails server. + + *Yuji Yaginuma* + +* Add `ruby x.x.x` version to `Gemfile` and create `.ruby-version` + root file containing the current Ruby version when new Rails applications are + created. + + *Alberto Almagro* + +* Support `-` as a platform-agnostic way to run a script from stdin with + `rails runner` + + *Cody Cutrer* + +* Add `bootsnap` to default `Gemfile`. + + *Burke Libbey* + +* Properly expand shortcuts for environment's name running the `console` + and `dbconsole` commands. + + *Robin Dupret* + +* Passing the environment's name as a regular argument to the + `rails dbconsole` and `rails console` commands is deprecated. + The `-e` option should be used instead. + + Previously: + + $ bin/rails dbconsole production + + Now: + + $ bin/rails dbconsole -e production + + *Robin Dupret*, *Kasper Timm Hansen* + +* Allow passing a custom connection name to the `rails dbconsole` + command when using a 3-level database configuration. + + $ bin/rails dbconsole -c replica + + *Robin Dupret*, *Jeremy Daer* + +* Skip unused components when running `bin/rails app:update`. + + If the initial app generation skipped Action Cable, Active Record etc., + the update task honors those skips too. + + *Yuji Yaginuma* + * Make Rails' test runner work better with minitest plugins. By demoting the Rails test runner to just another minitest plugin — diff --git a/railties/lib/rails/all.rb b/railties/lib/rails/all.rb index 7606ea0e46..913bcf4120 100644 --- a/railties/lib/rails/all.rb +++ b/railties/lib/rails/all.rb @@ -7,6 +7,7 @@ require "rails" action_mailer/railtie active_job/railtie action_cable/engine + active_storage/engine rails/test_unit/railtie sprockets/railtie ).each do |railtie| diff --git a/railties/lib/rails/api/task.rb b/railties/lib/rails/api/task.rb index 49267c2329..195048a98b 100644 --- a/railties/lib/rails/api/task.rb +++ b/railties/lib/rails/api/task.rb @@ -64,6 +64,13 @@ module Rails ) }, + "activestorage" => { + include: %w( + README.md + lib/active_storage/**/*.rb + ) + }, + "railties" => { include: %w( README.rdoc diff --git a/railties/lib/rails/app_loader.rb b/railties/lib/rails/app_loader.rb index 3dc4fe5414..9e4f715ca6 100644 --- a/railties/lib/rails/app_loader.rb +++ b/railties/lib/rails/app_loader.rb @@ -8,15 +8,26 @@ module Rails RUBY = Gem.ruby EXECUTABLES = ["bin/rails", "script/rails"] BUNDLER_WARNING = <<EOS -Looks like your app's ./bin/rails is a stub that was generated by Bundler. +Beginning in Rails 4, Rails ships with a `rails` binstub at ./bin/rails that +should be used instead of the Bundler-generated `rails` binstub. -In Rails #{Rails::VERSION::MAJOR}, your app's bin/ directory contains executables that are versioned -like any other source code, rather than stubs that are generated on demand. +If you are seeing this message, your binstub at ./bin/rails was generated by +Bundler instead of Rails. -Here's how to upgrade: +You might need to regenerate your `rails` binstub locally and add it to source +control: + + rails app:update:bin # Bear in mind this generates other binstubs + # too that you may or may not want (like yarn) + +If you already have Rails binstubs in source control, you might be +inadverently overwriting them during deployment by using bundle install +with the --binstubs option. + +If your application was created prior to Rails 4, here's how to upgrade: bundle config --delete bin # Turn off Bundler's stub generator - rails app:update:bin # Use the new Rails 5 executables + rails app:update:bin # Use the new Rails executables git add bin # Add bin/ to source control You may need to remove bin/ from your .gitignore as well. diff --git a/railties/lib/rails/app_updater.rb b/railties/lib/rails/app_updater.rb new file mode 100644 index 0000000000..e53d1cf093 --- /dev/null +++ b/railties/lib/rails/app_updater.rb @@ -0,0 +1,31 @@ +require "rails/generators" +require "rails/generators/rails/app/app_generator" + +module Rails + class AppUpdater # :nodoc: + class << self + def invoke_from_app_generator(method) + app_generator.send(method) + end + + def app_generator + @app_generator ||= begin + gen = Rails::Generators::AppGenerator.new ["rails"], generator_options, destination_root: Rails.root + File.exist?(Rails.root.join("config", "application.rb")) ? gen.send(:app_const) : gen.send(:valid_const?) + gen + end + end + + private + def generator_options + options = { api: !!Rails.application.config.api_only, update: true } + options[:skip_active_record] = !defined?(ActiveRecord::Railtie) + options[:skip_action_mailer] = !defined?(ActionMailer::Railtie) + options[:skip_action_cable] = !defined?(ActionCable::Engine) + options[:skip_sprockets] = !defined?(Sprockets::Railtie) + options[:skip_puma] = !defined?(Puma) + options + end + end + end +end diff --git a/railties/lib/rails/command/environment_argument.rb b/railties/lib/rails/command/environment_argument.rb index 05eac34155..9582509840 100644 --- a/railties/lib/rails/command/environment_argument.rb +++ b/railties/lib/rails/command/environment_argument.rb @@ -7,13 +7,24 @@ module Rails included do argument :environment, optional: true, banner: "environment" + + class_option :environment, aliases: "-e", type: :string, + desc: "Specifies the environment to run this console under (test/development/production)." end private def extract_environment_option_from_argument if environment self.options = options.merge(environment: acceptable_environment(environment)) - elsif !options[:environment] + + ActiveSupport::Deprecation.warn "Passing the environment's name as a " \ + "regular argument is deprecated and " \ + "will be removed in the next Rails " \ + "version. Please, use the -e option " \ + "instead." + elsif options[:environment] + self.options = options.merge(environment: acceptable_environment(options[:environment])) + else self.options = options.merge(environment: Rails::Command.environment) end end diff --git a/railties/lib/rails/commands/console/console_command.rb b/railties/lib/rails/commands/console/console_command.rb index 1da1e331f1..6f9a1f022b 100644 --- a/railties/lib/rails/commands/console/console_command.rb +++ b/railties/lib/rails/commands/console/console_command.rb @@ -70,9 +70,6 @@ module Rails class_option :sandbox, aliases: "-s", type: :boolean, default: false, desc: "Rollback database modifications on exit." - class_option :environment, aliases: "-e", type: :string, - desc: "Specifies the environment to run this console under (test/development/production)." - def initialize(args = [], local_options = {}, config = {}) console_options = [] diff --git a/railties/lib/rails/commands/dbconsole/dbconsole_command.rb b/railties/lib/rails/commands/dbconsole/dbconsole_command.rb index b3df5191c6..71b3455473 100644 --- a/railties/lib/rails/commands/dbconsole/dbconsole_command.rb +++ b/railties/lib/rails/commands/dbconsole/dbconsole_command.rb @@ -11,7 +11,7 @@ module Rails end def start - ENV["RAILS_ENV"] = @options[:environment] || environment + ENV["RAILS_ENV"] ||= @options[:environment] || environment case config["adapter"] when /^(jdbc)?mysql/ @@ -87,10 +87,15 @@ module Rails def config @config ||= begin - if configurations[environment].blank? + # We need to check whether the user passed the connection the + # first time around to show a consistent error message to people + # relying on 2-level database configuration. + if @options["connection"] && configurations[connection].blank? + raise ActiveRecord::AdapterNotSpecified, "'#{connection}' connection is not configured. Available configuration: #{configurations.inspect}" + elsif configurations[environment].blank? && configurations[connection].blank? raise ActiveRecord::AdapterNotSpecified, "'#{environment}' database is not configured. Available configuration: #{configurations.inspect}" else - configurations[environment] + configurations[environment].presence || configurations[connection] end end end @@ -99,6 +104,10 @@ module Rails Rails.respond_to?(:env) ? Rails.env : Rails::Command.environment end + def connection + @options.fetch(:connection, "primary") + end + private def configurations # :doc: require APP_PATH @@ -142,12 +151,15 @@ module Rails class_option :header, type: :boolean - class_option :environment, aliases: "-e", type: :string, - desc: "Specifies the environment to run this console under (test/development/production)." + class_option :connection, aliases: "-c", type: :string, + desc: "Specifies the connection to use." def perform extract_environment_option_from_argument + # RAILS_ENV needs to be set before config/application is required. + ENV["RAILS_ENV"] = options[:environment] + require_application_and_environment! Rails::DBConsole.start(options) end diff --git a/railties/lib/rails/commands/runner/USAGE b/railties/lib/rails/commands/runner/USAGE index b2a6e8493d..24b60037f0 100644 --- a/railties/lib/rails/commands/runner/USAGE +++ b/railties/lib/rails/commands/runner/USAGE @@ -8,6 +8,9 @@ Run the Ruby file located at `path/to/filename.rb` after loading the app: <%= executable %> path/to/filename.rb +Run the Ruby script read from stdin after loading the app: + <%= executable %> - + <% unless Gem.win_platform? %> You can also use the runner command as a shebang line for your executables: diff --git a/railties/lib/rails/commands/runner/runner_command.rb b/railties/lib/rails/commands/runner/runner_command.rb index 6864a9726b..c931fc2152 100644 --- a/railties/lib/rails/commands/runner/runner_command.rb +++ b/railties/lib/rails/commands/runner/runner_command.rb @@ -13,7 +13,7 @@ module Rails end def self.banner(*) - "#{super} [<'Some.ruby(code)'> | <filename.rb>]" + "#{super} [<'Some.ruby(code)'> | <filename.rb> | -]" end def perform(code_or_file = nil, *command_argv) @@ -29,7 +29,9 @@ module Rails ARGV.replace(command_argv) - if File.exist?(code_or_file) + if code_or_file == "-" + eval($stdin.read, binding, "stdin") + elsif File.exist?(code_or_file) $0 = code_or_file Kernel.load code_or_file else diff --git a/railties/lib/rails/commands/server/server_command.rb b/railties/lib/rails/commands/server/server_command.rb index b607a63176..de69b4586b 100644 --- a/railties/lib/rails/commands/server/server_command.rb +++ b/railties/lib/rails/commands/server/server_command.rb @@ -2,6 +2,8 @@ require "fileutils" require "optparse" require "action_dispatch" require "rails" +require "active_support/deprecation" +require "active_support/core_ext/string/filters" require_relative "../../dev_caching" module Rails @@ -18,10 +20,15 @@ module Rails set_environment end - # TODO: this is no longer required but we keep it for the moment to support older config.ru files. def app @app ||= begin 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. + Please change `run #{app}` to `run Rails.application` in config.ru. + MSG + end app.respond_to?(:to_app) ? app.to_app : app end end @@ -64,9 +71,9 @@ module Rails end def print_boot_information - url = "#{options[:SSLEnable] ? 'https' : 'http'}://#{options[:Host]}:#{options[:Port]}" + url = "on #{options[:SSLEnable] ? 'https' : 'http'}://#{options[:Host]}:#{options[:Port]}" unless use_puma? puts "=> Booting #{ActiveSupport::Inflector.demodulize(server)}" - puts "=> Rails #{Rails.version} application starting in #{Rails.env} on #{url}" + puts "=> Rails #{Rails.version} application starting in #{Rails.env} #{url}" puts "=> Run `rails server -h` for more startup options" end @@ -91,6 +98,10 @@ module Rails def restart_command "bin/rails server #{ARGV.join(' ')}" end + + def use_puma? + server.to_s == "Rack::Handler::Puma" + end end module Command diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb index 5cf0985050..2792d7636f 100644 --- a/railties/lib/rails/generators/actions.rb +++ b/railties/lib/rails/generators/actions.rb @@ -216,9 +216,9 @@ module Rails # Runs the supplied rake task (invoked with 'rails ...') # - # rails("db:migrate") - # rails("db:migrate", env: "production") - # rails("gems:install", sudo: true) + # rails_command("db:migrate") + # rails_command("db:migrate", env: "production") + # rails_command("gems:install", sudo: true) def rails_command(command, options = {}) execute_command :rails, command, options end diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index 760cb2f81e..4899a63917 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -348,6 +348,8 @@ module Rails comment = "See https://github.com/rails/execjs#readme for more supported runtimes" if defined?(JRUBY_VERSION) GemfileEntry.version "therubyrhino", nil, comment + elsif RUBY_PLATFORM =~ /mingw|mswin/ + GemfileEntry.version "duktape", nil, comment else GemfileEntry.new "mini_racer", nil, comment, { platforms: :ruby }, true end diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb index e7f51dba99..9705af8b40 100644 --- a/railties/lib/rails/generators/base.rb +++ b/railties/lib/rails/generators/base.rb @@ -16,6 +16,9 @@ module Rails include Thor::Actions include Rails::Generators::Actions + class_option :skip_namespace, type: :boolean, default: false, + desc: "Skip namespace (affects only isolated applications)" + add_runtime_options! strict_args_position! @@ -271,6 +274,40 @@ module Rails end end + # Wrap block with namespace of current application + # if namespace exists and is not skipped + def module_namespacing(&block) # :doc: + content = capture(&block) + content = wrap_with_namespace(content) if namespaced? + concat(content) + end + + def indent(content, multiplier = 2) # :doc: + spaces = " " * multiplier + content.each_line.map { |line| line.blank? ? line : "#{spaces}#{line}" }.join + end + + def wrap_with_namespace(content) # :doc: + content = indent(content).chomp + "module #{namespace.name}\n#{content}\nend\n" + end + + def namespace # :doc: + Rails::Generators.namespace + end + + def namespaced? # :doc: + !options[:skip_namespace] && namespace + end + + def namespace_dirs + @namespace_dirs ||= namespace.name.split("::").map(&:underscore) + end + + def namespaced_path # :doc: + @namespaced_path ||= namespace_dirs.join("/") + end + # Use Rails default banner. def self.banner # :doc: "rails generate #{namespace.sub(/^rails:/, '')} #{arguments.map(&:usage).join(' ')} [options]".gsub(/\s+/, " ") diff --git a/railties/lib/rails/generators/named_base.rb b/railties/lib/rails/generators/named_base.rb index d63a5b0c30..dc1d6cab9d 100644 --- a/railties/lib/rails/generators/named_base.rb +++ b/railties/lib/rails/generators/named_base.rb @@ -6,8 +6,6 @@ module Rails module Generators class NamedBase < Base argument :name, type: :string - class_option :skip_namespace, type: :boolean, default: false, - desc: "Skip namespace (affects only isolated applications)" def initialize(args, *options) #:nodoc: @inside_template = nil @@ -45,24 +43,6 @@ module Rails file_name end - # Wrap block with namespace of current application - # if namespace exists and is not skipped - def module_namespacing(&block) # :doc: - content = capture(&block) - content = wrap_with_namespace(content) if namespaced? - concat(content) - end - - def indent(content, multiplier = 2) # :doc: - spaces = " " * multiplier - content.each_line.map { |line| line.blank? ? line : "#{spaces}#{line}" }.join - end - - def wrap_with_namespace(content) # :doc: - content = indent(content).chomp - "module #{namespace.name}\n#{content}\nend\n" - end - def inside_template # :doc: @inside_template = true yield @@ -74,18 +54,6 @@ module Rails @inside_template end - def namespace # :doc: - Rails::Generators.namespace - end - - def namespaced? # :doc: - !options[:skip_namespace] && namespace - end - - def namespace_dirs - @namespace_dirs ||= namespace.name.split("::").map(&:underscore) - end - def file_path # :doc: @file_path ||= (class_path + [file_name]).join("/") end @@ -102,10 +70,6 @@ module Rails @namespaced_class_path ||= namespace_dirs + @class_path end - def namespaced_path # :doc: - @namespaced_path ||= namespace_dirs.join("/") - end - def class_name # :doc: (class_path + [file_name]).map!(&:camelize).join("::") end diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 7614e6304b..cbe68823d4 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -49,6 +49,10 @@ module Rails copy_file "README.md", "README.md" end + def ruby_version + template "ruby-version", ".ruby-version" + end + def gemfile template "Gemfile" end @@ -109,6 +113,7 @@ module Rails template "cable.yml" unless options[:skip_action_cable] template "puma.rb" unless options[:skip_puma] template "spring.rb" if spring_install? + template "storage.yml" directory "environments" directory "initializers" @@ -118,9 +123,10 @@ module Rails def config_when_updating cookie_serializer_config_exist = File.exist?("config/initializers/cookies_serializer.rb") - action_cable_config_exist = File.exist?("config/cable.yml") - rack_cors_config_exist = File.exist?("config/initializers/cors.rb") - assets_config_exist = File.exist?("config/initializers/assets.rb") + action_cable_config_exist = File.exist?("config/cable.yml") + 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") config @@ -128,10 +134,14 @@ module Rails gsub_file "config/initializers/cookies_serializer.rb", /json(?!,)/, "marshal" end - unless action_cable_config_exist + if !options[:skip_action_cable] && !action_cable_config_exist template "config/cable.yml" end + if !active_storage_config_exist + template "config/storage.yml" + end + unless rack_cors_config_exist remove_file "config/initializers/cors.rb" end @@ -169,6 +179,11 @@ module Rails directory "public", "public", recursive: false end + def storage + empty_directory_with_keep_file "storage" + empty_directory_with_keep_file "tmp/storage" + end + def test empty_directory_with_keep_file "test/fixtures" empty_directory_with_keep_file "test/fixtures/files" @@ -242,6 +257,7 @@ module Rails def create_root_files build(:readme) build(:rakefile) + build(:ruby_version) build(:configru) build(:gitignore) unless options[:skip_git] build(:gemfile) unless options[:skip_gemfile] diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile index 64e2062aea..7b7bebc957 100644 --- a/railties/lib/rails/generators/rails/app/templates/Gemfile +++ b/railties/lib/rails/generators/rails/app/templates/Gemfile @@ -1,6 +1,11 @@ source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } +ruby <%= "'#{RUBY_VERSION}'" -%> + +<% unless gemfile_entries.first.comment -%> + +<% end -%> <% gemfile_entries.each do |gem| -%> <% if gem.comment -%> @@ -19,6 +24,9 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" } # Use Capistrano for deployment # gem 'capistrano-rails', group: :development +# Reduces boot times through caching; required in config/boot.rb +gem 'bootsnap', '>= 1.1.0', require: false + <%- if options.api? -%> # Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin AJAX possible # gem 'rack-cors' diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt index 4206002a1b..62fd04f113 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt +++ b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt @@ -12,6 +12,7 @@ // <% unless options[:skip_javascript] -%> //= require rails-ujs +//= require activestorage <% unless options[:skip_turbolinks] -%> //= require turbolinks <% end -%> 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 ee9d077c30..a53d1fb0a9 100644 --- a/railties/lib/rails/generators/rails/app/templates/bin/setup.tt +++ b/railties/lib/rails/generators/rails/app/templates/bin/setup.tt @@ -15,10 +15,11 @@ chdir APP_ROOT do puts '== Installing dependencies ==' system! 'gem install bundler --conservative' system('bundle check') || system!('bundle install') -<% unless options[:skip_yarn] %> +<% unless options[:skip_yarn] -%> + # Install JavaScript dependencies if using Yarn # system('bin/yarn') -<% end %> +<% end -%> <% unless options.skip_active_record -%> # puts "\n== Copying sample files ==" diff --git a/railties/lib/rails/generators/rails/app/templates/bin/yarn b/railties/lib/rails/generators/rails/app/templates/bin/yarn index 44f75c22a4..c2f9b6768a 100644 --- a/railties/lib/rails/generators/rails/app/templates/bin/yarn +++ b/railties/lib/rails/generators/rails/app/templates/bin/yarn @@ -1,7 +1,7 @@ VENDOR_PATH = File.expand_path('..', __dir__) Dir.chdir(VENDOR_PATH) do begin - exec "yarnpkg #{ARGV.join(" ")}" + exec "yarnpkg #{ARGV.join(' ')}" 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 b/railties/lib/rails/generators/rails/app/templates/config/application.rb index 0b1d22228e..9931709d7b 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/application.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb @@ -11,6 +11,7 @@ require "active_job/railtie" require "action_controller/railtie" <%= comment_if :skip_action_mailer %>require "action_mailer/railtie" require "action_view/railtie" +require "active_storage/engine" <%= comment_if :skip_action_cable %>require "action_cable/engine" <%= comment_if :skip_sprockets %>require "sprockets/railtie" <%= comment_if :skip_test %>require "rails/test_unit/railtie" diff --git a/railties/lib/rails/generators/rails/app/templates/config/boot.rb b/railties/lib/rails/generators/rails/app/templates/config/boot.rb index 30f5120df6..b9e460cef3 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/boot.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/boot.rb @@ -1,3 +1,4 @@ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) require 'bundler/setup' # Set up gems listed in the Gemfile. +require 'bootsnap/setup' # Speed up boot time by caching expensive operations. 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 b75b65c8df..d69769f631 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 @@ -26,6 +26,9 @@ Rails.application.configure do config.cache_store = :null_store end + + # Store uploaded files on the local file system (see config/storage.yml for options) + config.active_storage.service = :local <%- unless options.skip_action_mailer? -%> # Don't care if the mailer can't send. diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt index d44331a888..f68e13aa8b 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 @@ -45,6 +45,9 @@ Rails.application.configure do # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX + # Store uploaded files on the local file system (see config/storage.yml for options) + config.active_storage.service = :local + <%- unless options[:skip_action_cable] -%> # Mount Action Cable outside main process or domain # config.action_cable.mount_path = nil diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt index 56416b3075..fdf16b4730 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt @@ -27,6 +27,9 @@ Rails.application.configure do # Disable request forgery protection in test environment. config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory + config.active_storage.service = :test <%- unless options.skip_action_mailer? -%> config.action_mailer.perform_caching = false diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/application_controller_renderer.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/application_controller_renderer.rb index 51639b67a0..89d2efab2b 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/application_controller_renderer.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/application_controller_renderer.rb @@ -1,6 +1,8 @@ # Be sure to restart your server when you modify this file. -# ApplicationController.renderer.defaults.merge!( -# http_host: 'example.org', -# https: false -# ) +# ActiveSupport::Reloader.to_prepare do +# ApplicationController.renderer.defaults.merge!( +# http_host: 'example.org', +# https: false +# ) +# end 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 f2df0d1e9f..25dcddb27a 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 @@ -24,4 +24,4 @@ # Store boolean values are in sqlite3 databases as 1 and 0 instead of 't' and # 'f' after migrating old data. -# ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer = true +# Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true diff --git a/railties/lib/rails/generators/rails/app/templates/config/spring.rb b/railties/lib/rails/generators/rails/app/templates/config/spring.rb index c9119b40c0..9fa7863f99 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/spring.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/spring.rb @@ -1,6 +1,6 @@ -%w( +%w[ .ruby-version .rbenv-vars tmp/restart.txt tmp/caching-dev.txt -).each { |path| Spring.watch(path) } +].each { |path| Spring.watch(path) } diff --git a/railties/lib/rails/generators/rails/app/templates/config/storage.yml b/railties/lib/rails/generators/rails/app/templates/config/storage.yml new file mode 100644 index 0000000000..1afe3eb4b3 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/config/storage.yml @@ -0,0 +1,35 @@ +test: + service: Disk + root: <%%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%%= Rails.root.join("storage") %> + +# Use rails secrets:edit to set the AWS secrets (as shared:aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%%= Rails.application.secrets.dig(:aws, :access_key_id) %> +# secret_access_key: <%%= Rails.application.secrets.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# keyfile: <%%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket + +# Use rails secrets:edit to set the Azure Storage secret (as shared:azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# path: your_azure_storage_path +# storage_account_name: your_account_name +# storage_access_key: <%%= Rails.application.secrets.dig(:azure_storage, :secret_access_key) %> +# container: your_container_name + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/railties/lib/rails/generators/rails/app/templates/gitignore b/railties/lib/rails/generators/rails/app/templates/gitignore index 1e6b9afcd2..64ed09dc4b 100644 --- a/railties/lib/rails/generators/rails/app/templates/gitignore +++ b/railties/lib/rails/generators/rails/app/templates/gitignore @@ -21,6 +21,9 @@ !/tmp/.keep <% end -%> +# Ignore uploaded files in development +/storage/* + <% unless options[:skip_yarn] -%> /node_modules /yarn-error.log diff --git a/railties/lib/rails/generators/rails/app/templates/ruby-version b/railties/lib/rails/generators/rails/app/templates/ruby-version new file mode 100644 index 0000000000..c444f33b0f --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/ruby-version @@ -0,0 +1 @@ +<%= RUBY_VERSION -%> diff --git a/railties/lib/rails/generators/rails/application_record/application_record_generator.rb b/railties/lib/rails/generators/rails/application_record/application_record_generator.rb new file mode 100644 index 0000000000..f6b6e76b1d --- /dev/null +++ b/railties/lib/rails/generators/rails/application_record/application_record_generator.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Rails + module Generators + class ApplicationRecordGenerator < Base # :nodoc: + hook_for :orm, required: true, desc: "ORM to be invoked" + end + end +end diff --git a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb index a1209e4624..61c54b4222 100644 --- a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb +++ b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb @@ -120,7 +120,6 @@ task default: :test def test_dummy_clean inside dummy_path do remove_file "db/seeds.rb" - remove_file "doc" remove_file "Gemfile" remove_file "lib/tasks" remove_file "public/robots.txt" diff --git a/railties/lib/rails/generators/rails/plugin/templates/gitignore b/railties/lib/rails/generators/rails/plugin/templates/gitignore index 54c78d7927..757172e6a6 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/gitignore +++ b/railties/lib/rails/generators/rails/plugin/templates/gitignore @@ -1,7 +1,7 @@ .bundle/ log/*.log pkg/ -<% unless options[:skip_test] && options[:dummy_path] == 'test/dummy' -%> +<% if with_dummy_app? -%> <%= dummy_path %>/db/*.sqlite3 <%= dummy_path %>/db/*.sqlite3-journal <%= dummy_path %>/log/*.log diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb b/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb index d03b1be878..47b56ae3df 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb @@ -3,15 +3,18 @@ require_relative 'boot' <% if include_all_railties? -%> require 'rails/all' <% else -%> +require "rails" # Pick the frameworks you want: +require "active_model/railtie" +require "active_job/railtie" <%= comment_if :skip_active_record %>require "active_record/railtie" require "action_controller/railtie" -require "action_view/railtie" <%= comment_if :skip_action_mailer %>require "action_mailer/railtie" -require "active_job/railtie" +require "action_view/railtie" +require "active_storage/engine" <%= comment_if :skip_action_cable %>require "action_cable/engine" -<%= comment_if :skip_test %>require "rails/test_unit/railtie" <%= comment_if :skip_sprockets %>require "sprockets/railtie" +<%= comment_if :skip_test %>require "rails/test_unit/railtie" <% end -%> Bundler.require(*Rails.groups) diff --git a/railties/lib/rails/generators/testing/assertions.rb b/railties/lib/rails/generators/testing/assertions.rb index 1cabf4e28c..9ac70f60c0 100644 --- a/railties/lib/rails/generators/testing/assertions.rb +++ b/railties/lib/rails/generators/testing/assertions.rb @@ -113,7 +113,11 @@ module Rails # # assert_field_default_value :string, "MyString" def assert_field_default_value(attribute_type, value) - assert_equal(value, create_generated_attribute(attribute_type).default) + if value.nil? + assert_nil(create_generated_attribute(attribute_type).default) + else + assert_equal(value, create_generated_attribute(attribute_type).default) + end end end end diff --git a/railties/lib/rails/secrets.rb b/railties/lib/rails/secrets.rb index 46e21185d7..0883857c55 100644 --- a/railties/lib/rails/secrets.rb +++ b/railties/lib/rails/secrets.rb @@ -100,7 +100,8 @@ module Rails end def writing(contents) - tmp_path = File.join(Dir.tmpdir, File.basename(path)) + tmp_file = "#{File.basename(path)}.#{Process.pid}" + tmp_path = File.join(Dir.tmpdir, tmp_file) IO.binwrite(tmp_path, contents) yield tmp_path diff --git a/railties/lib/rails/tasks/framework.rake b/railties/lib/rails/tasks/framework.rake index f7e8f4f340..6c6e86d78d 100644 --- a/railties/lib/rails/tasks/framework.rake +++ b/railties/lib/rails/tasks/framework.rake @@ -36,38 +36,21 @@ namespace :app do end namespace :update do - class RailsUpdate - def self.invoke_from_app_generator(method) - app_generator.send(method) - end - - def self.app_generator - @app_generator ||= begin - require_relative "../generators" - require_relative "../generators/rails/app/app_generator" - gen = Rails::Generators::AppGenerator.new ["rails"], - { api: !!Rails.application.config.api_only, update: true }, - destination_root: Rails.root - File.exist?(Rails.root.join("config", "application.rb")) ? - gen.send(:app_const) : gen.send(:valid_const?) - gen - end - end - end + require_relative "../app_updater" # desc "Update config/boot.rb from your current rails install" task :configs do - RailsUpdate.invoke_from_app_generator :create_boot_file - RailsUpdate.invoke_from_app_generator :update_config_files + Rails::AppUpdater.invoke_from_app_generator :create_boot_file + Rails::AppUpdater.invoke_from_app_generator :update_config_files end # desc "Adds new executables to the application bin/ directory" task :bin do - RailsUpdate.invoke_from_app_generator :update_bin_files + Rails::AppUpdater.invoke_from_app_generator :update_bin_files end task :upgrade_guide_info do - RailsUpdate.invoke_from_app_generator :display_upgrade_guide_info + Rails::AppUpdater.invoke_from_app_generator :display_upgrade_guide_info end end end diff --git a/railties/lib/rails/tasks/yarn.rake b/railties/lib/rails/tasks/yarn.rake index 87476b1b8c..6cb19b7282 100644 --- a/railties/lib/rails/tasks/yarn.rake +++ b/railties/lib/rails/tasks/yarn.rake @@ -1,7 +1,7 @@ namespace :yarn do desc "Install all JavaScript dependencies as specified via Yarn" task :install do - system("./bin/yarn install --no-progress") + system("./bin/yarn install --no-progress --production") end end diff --git a/railties/lib/rails/test_unit/reporter.rb b/railties/lib/rails/test_unit/reporter.rb index 1cc27f7b6c..ab28034d27 100644 --- a/railties/lib/rails/test_unit/reporter.rb +++ b/railties/lib/rails/test_unit/reporter.rb @@ -71,7 +71,12 @@ module Rails end def app_root - @app_root ||= defined?(ENGINE_ROOT) ? ENGINE_ROOT : Rails.root + @app_root ||= + if defined?(ENGINE_ROOT) + ENGINE_ROOT + elsif Rails.respond_to?(:root) + Rails.root + end end def colored_output? diff --git a/railties/lib/rails/test_unit/runner.rb b/railties/lib/rails/test_unit/runner.rb index 8018ef9d02..1f3a248bcb 100644 --- a/railties/lib/rails/test_unit/runner.rb +++ b/railties/lib/rails/test_unit/runner.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "shellwords" require "method_source" require "rake/file_list" @@ -58,7 +60,8 @@ module Rails private def extract_filters(argv) - argv.select { |arg| arg =~ /^\w+\// }.map do |path| + # Extract absolute and relative paths but skip -n /.*/ regexp filters. + argv.select { |arg| arg =~ %r%^/?\w+/% && !arg.end_with?("/") }.map do |path| case when path =~ /(:\d+)+$/ file, *lines = path.split(":") diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index b8a19379e0..c2f6a5a95c 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -453,10 +453,8 @@ module ApplicationTests secret_key_base: 123 YAML - app "development" - assert_raise(ArgumentError) do - app.key_generator + app "development" end end @@ -1130,7 +1128,7 @@ module ApplicationTests app "development" - ActionController::Base.object_id # force lazy load hooks to run + force_lazy_load_hooks { ActionController::Base } assert_equal :raise, ActionController::Parameters.action_on_unpermitted_parameters @@ -1141,7 +1139,7 @@ module ApplicationTests test "config.action_controller.always_permitted_parameters are: controller, action by default" do app "development" - ActionController::Base.object_id # force lazy load hooks to run + force_lazy_load_hooks { ActionController::Base } assert_equal %w(controller action), ActionController::Parameters.always_permitted_parameters end @@ -1153,7 +1151,7 @@ module ApplicationTests app "development" - ActionController::Base.object_id # force lazy load hooks to run + force_lazy_load_hooks { ActionController::Base } assert_equal %w( controller action format ), ActionController::Parameters.always_permitted_parameters end @@ -1177,7 +1175,7 @@ module ApplicationTests app "development" - ActionController::Base.object_id # force lazy load hooks to run + force_lazy_load_hooks { ActionController::Base } assert_equal :raise, ActionController::Parameters.action_on_unpermitted_parameters @@ -1188,7 +1186,7 @@ module ApplicationTests test "config.action_controller.action_on_unpermitted_parameters is :log by default on development" do app "development" - ActionController::Base.object_id # force lazy load hooks to run + force_lazy_load_hooks { ActionController::Base } assert_equal :log, ActionController::Parameters.action_on_unpermitted_parameters end @@ -1196,7 +1194,7 @@ module ApplicationTests test "config.action_controller.action_on_unpermitted_parameters is :log by default on test" do app "test" - ActionController::Base.object_id # force lazy load hooks to run + force_lazy_load_hooks { ActionController::Base } assert_equal :log, ActionController::Parameters.action_on_unpermitted_parameters end @@ -1204,7 +1202,7 @@ module ApplicationTests test "config.action_controller.action_on_unpermitted_parameters is false by default on production" do app "production" - ActionController::Base.object_id # force lazy load hooks to run + force_lazy_load_hooks { ActionController::Base } assert_equal false, ActionController::Parameters.action_on_unpermitted_parameters end @@ -1223,7 +1221,7 @@ module ApplicationTests app "development" - ActionController::Base.object_id # force lazy load hooks to run + force_lazy_load_hooks { ActionController::Base } assert_equal true, ActionController::Parameters.permit_all_parameters end @@ -1234,7 +1232,7 @@ module ApplicationTests app "development" - ActionController::Base.object_id # force lazy load hooks to run + force_lazy_load_hooks { ActionController::Base } assert_equal [], ActionController::Parameters.always_permitted_parameters end @@ -1245,7 +1243,7 @@ module ApplicationTests app "development" - ActionController::Base.object_id # force lazy load hooks to run + force_lazy_load_hooks { ActionController::Base } assert_equal :raise, ActionController::Parameters.action_on_unpermitted_parameters end @@ -1452,8 +1450,8 @@ module ApplicationTests test "raises with proper error message if no database configuration found" do FileUtils.rm("#{app_path}/config/database.yml") - app "development" err = assert_raises RuntimeError do + app "development" Rails.application.config.database_configuration end assert_match "config/database", err.message @@ -1596,7 +1594,7 @@ module ApplicationTests RUBY app "development" - Post.object_id # force lazy load hooks to run + force_lazy_load_hooks { Post } assert_not ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer end @@ -1608,7 +1606,25 @@ module ApplicationTests RUBY app "development" - Post.object_id # force lazy load hooks to run + force_lazy_load_hooks { Post } + + assert ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer + end + + test "represent_boolean_as_integer should be able to set via config.active_record.sqlite3.represent_boolean_as_integer" do + remove_from_config '.*config\.load_defaults.*\n' + + app_file "config/initializers/new_framework_defaults_5_2.rb", <<-RUBY + Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true + RUBY + + app_file "app/models/post.rb", <<-RUBY + class Post < ActiveRecord::Base + end + RUBY + + app "development" + force_lazy_load_hooks { Post } assert ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer end @@ -1719,5 +1735,10 @@ module ApplicationTests assert_equal 301, last_response.status assert_equal "https://example.org/", last_response.location end + + private + def force_lazy_load_hooks + yield # Tasty clarifying sugar, homie! We only need to reference a constant to load it. + end end end diff --git a/railties/test/application/console_test.rb b/railties/test/application/console_test.rb index 057d473870..31bef82ccc 100644 --- a/railties/test/application/console_test.rb +++ b/railties/test/application/console_test.rb @@ -1,4 +1,5 @@ require "isolation/abstract_unit" +require "console_helpers" class ConsoleTest < ActiveSupport::TestCase include ActiveSupport::Testing::Isolation @@ -93,14 +94,11 @@ class ConsoleTest < ActiveSupport::TestCase end end -begin - require "pty" -rescue LoadError -end - class FullStackConsoleTest < ActiveSupport::TestCase + include ConsoleHelpers + def setup - skip "PTY unavailable" unless defined?(PTY) && PTY.respond_to?(:open) + skip "PTY unavailable" unless available_pty? build_app app_file "app/models/post.rb", <<-CODE @@ -116,24 +114,11 @@ class FullStackConsoleTest < ActiveSupport::TestCase teardown_app end - def assert_output(expected, timeout = 1) - timeout = Time.now + timeout - - output = "" - until output.include?(expected) || Time.now > timeout - if IO.select([@master], [], [], 0.1) - output << @master.read(1) - end - end - - assert_includes output, expected, "#{expected.inspect} expected, but got:\n\n#{output}" - end - def write_prompt(command, expected_output = nil) @master.puts command - assert_output command - assert_output expected_output if expected_output - assert_output "> " + assert_output command, @master + assert_output expected_output, @master if expected_output + assert_output "> ", @master end def spawn_console(options) @@ -142,7 +127,7 @@ class FullStackConsoleTest < ActiveSupport::TestCase in: @slave, out: @slave, err: @slave ) - assert_output "> ", 30 + assert_output "> ", @master, 30 end def test_sandbox diff --git a/railties/test/application/dbconsole_test.rb b/railties/test/application/dbconsole_test.rb index 7e5e9ea8aa..5d89d0e44d 100644 --- a/railties/test/application/dbconsole_test.rb +++ b/railties/test/application/dbconsole_test.rb @@ -1,14 +1,14 @@ require "isolation/abstract_unit" -begin - require "pty" -rescue LoadError -end +require "console_helpers" module ApplicationTests class DBConsoleTest < ActiveSupport::TestCase include ActiveSupport::Testing::Isolation + include ConsoleHelpers def setup + skip "PTY unavailable" unless available_pty? + build_app end @@ -17,7 +17,6 @@ module ApplicationTests end def test_use_value_defined_in_environment_file_in_database_yml - skip "PTY unavailable" unless available_pty? Dir.chdir(app_path) do app_file "config/database.yml", <<-YAML development: @@ -41,26 +40,37 @@ module ApplicationTests master.puts ".exit" end - private - def spawn_dbconsole(fd) - Process.spawn("#{app_path}/bin/rails dbconsole", in: fd, out: fd, err: fd) - end - - def assert_output(expected, io, timeout = 5) - timeout = Time.now + timeout + def test_respect_environment_option + Dir.chdir(app_path) do + app_file "config/database.yml", <<-YAML + default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 - output = "" - until output.include?(expected) || Time.now > timeout - if IO.select([io], [], [], 0.1) - output << io.read(1) - end - end + development: + <<: *default + database: db/development.sqlite3 - assert_includes output, expected, "#{expected.inspect} expected, but got:\n\n#{output}" + production: + <<: *default + database: db/production.sqlite3 + YAML end - def available_pty? - defined?(PTY) && PTY.respond_to?(:open) + master, slave = PTY.open + spawn_dbconsole(slave, "-e production") + assert_output("sqlite>", master) + + master.puts "pragma database_list;" + assert_output("production.sqlite3", master) + ensure + master.puts ".exit" + end + + private + def spawn_dbconsole(fd, options = nil) + Process.spawn("#{app_path}/bin/rails dbconsole #{options}", in: fd, out: fd, err: fd) end end end diff --git a/railties/test/application/loading_test.rb b/railties/test/application/loading_test.rb index c75a25bc6f..dd62907d18 100644 --- a/railties/test/application/loading_test.rb +++ b/railties/test/application/loading_test.rb @@ -115,11 +115,11 @@ class LoadingTest < ActiveSupport::TestCase require "#{rails_root}/config/environment" setup_ar! - assert_equal [ActiveRecord::SchemaMigration, ActiveRecord::InternalMetadata], ActiveRecord::Base.descendants + assert_equal [ActiveStorage::Blob, ActiveStorage::Attachment, ActiveRecord::SchemaMigration, ActiveRecord::InternalMetadata].collect(&:to_s).sort, ActiveRecord::Base.descendants.collect(&:to_s).sort get "/load" - assert_equal [ActiveRecord::SchemaMigration, ActiveRecord::InternalMetadata, Post], ActiveRecord::Base.descendants + assert_equal [ActiveStorage::Blob, ActiveStorage::Attachment, ActiveRecord::SchemaMigration, ActiveRecord::InternalMetadata, Post].collect(&:to_s).sort, ActiveRecord::Base.descendants.collect(&:to_s).sort get "/unload" - assert_equal [ActiveRecord::SchemaMigration, ActiveRecord::InternalMetadata], ActiveRecord::Base.descendants + assert_equal [ActiveStorage::Blob, ActiveStorage::Attachment, ActiveRecord::SchemaMigration, ActiveRecord::InternalMetadata].collect(&:to_s).sort, ActiveRecord::Base.descendants.collect(&:to_s).sort end test "initialize cant be called twice" do diff --git a/railties/test/application/rake/dbs_test.rb b/railties/test/application/rake/dbs_test.rb index c63f23fa0a..3216121de3 100644 --- a/railties/test/application/rake/dbs_test.rb +++ b/railties/test/application/rake/dbs_test.rb @@ -259,6 +259,13 @@ module ApplicationTests end end + test "db:schema:load fails if schema.rb doesn't exist yet" do + Dir.chdir(app_path) do + stderr_output = capture(:stderr) { `bin/rails db:schema:load` } + assert_match(/Run `rails db:migrate` to create it/, stderr_output) + end + end + def db_test_load_structure Dir.chdir(app_path) do `bin/rails generate model book title:string; diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb index 134106812d..6340f8f7b1 100644 --- a/railties/test/application/rake_test.rb +++ b/railties/test/application/rake_test.rb @@ -129,7 +129,15 @@ module ApplicationTests RUBY output = Dir.chdir(app_path) { `bin/rails routes` } - assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output + assert_equal <<-MESSAGE.strip_heredoc, output + Prefix Verb URI Pattern Controller#Action + cart GET /cart(.:format) cart#show + rails_service_blob GET /rails/active_storage/blobs/:signed_id/*filename(.:format) active_storage/blobs#show + rails_blob_variation GET /rails/active_storage/variants/:signed_blob_id/:variation_key/*filename(.:format) active_storage/variants#show + rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show + update_rails_disk_service PUT /rails/active_storage/disk/:encoded_token(.:format) active_storage/disk#update + rails_direct_uploads POST /rails/active_storage/direct_uploads(.:format) active_storage/direct_uploads#create + MESSAGE end def test_singular_resource_output_in_rake_routes @@ -162,10 +170,20 @@ module ApplicationTests RUBY output = Dir.chdir(app_path) { `bin/rails routes -g show` } - assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output + assert_equal <<-MESSAGE.strip_heredoc, output + Prefix Verb URI Pattern Controller#Action + cart GET /cart(.:format) cart#show + rails_service_blob GET /rails/active_storage/blobs/:signed_id/*filename(.:format) active_storage/blobs#show + rails_blob_variation GET /rails/active_storage/variants/:signed_blob_id/:variation_key/*filename(.:format) active_storage/variants#show + rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show + MESSAGE output = Dir.chdir(app_path) { `bin/rails routes -g POST` } - assert_equal "Prefix Verb URI Pattern Controller#Action\n POST /cart(.:format) cart#create\n", output + assert_equal <<-MESSAGE.strip_heredoc, output + Prefix Verb URI Pattern Controller#Action + POST /cart(.:format) cart#create + rails_direct_uploads POST /rails/active_storage/direct_uploads(.:format) active_storage/direct_uploads#create + MESSAGE output = Dir.chdir(app_path) { `bin/rails routes -g basketballs` } assert_equal " Prefix Verb URI Pattern Controller#Action\n" \ @@ -221,11 +239,12 @@ module ApplicationTests RUBY assert_equal <<-MESSAGE.strip_heredoc, Dir.chdir(app_path) { `bin/rails routes` } - You don't have any routes defined! - - Please add some routes in config/routes.rb. - - For more information about routes, see the Rails guide: http://guides.rubyonrails.org/routing.html. + Prefix Verb URI Pattern Controller#Action + rails_service_blob GET /rails/active_storage/blobs/:signed_id/*filename(.:format) active_storage/blobs#show + rails_blob_variation GET /rails/active_storage/variants/:signed_blob_id/:variation_key/*filename(.:format) active_storage/variants#show + rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show + update_rails_disk_service PUT /rails/active_storage/disk/:encoded_token(.:format) active_storage/disk#update + rails_direct_uploads POST /rails/active_storage/direct_uploads(.:format) active_storage/direct_uploads#create MESSAGE end @@ -237,7 +256,16 @@ module ApplicationTests RUBY output = Dir.chdir(app_path) { `bin/rake --rakefile Rakefile routes` } - assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output + + assert_equal <<-MESSAGE.strip_heredoc, output + Prefix Verb URI Pattern Controller#Action + cart GET /cart(.:format) cart#show + rails_service_blob GET /rails/active_storage/blobs/:signed_id/*filename(.:format) active_storage/blobs#show + rails_blob_variation GET /rails/active_storage/variants/:signed_blob_id/:variation_key/*filename(.:format) active_storage/variants#show + rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show + update_rails_disk_service PUT /rails/active_storage/disk/:encoded_token(.:format) active_storage/disk#update + rails_direct_uploads POST /rails/active_storage/direct_uploads(.:format) active_storage/direct_uploads#create + MESSAGE end def test_logger_is_flushed_when_exiting_production_rake_tasks diff --git a/railties/test/application/routing_test.rb b/railties/test/application/routing_test.rb index 6742da20cc..bc7580d6f4 100644 --- a/railties/test/application/routing_test.rb +++ b/railties/test/application/routing_test.rb @@ -293,7 +293,7 @@ module ApplicationTests extend ActiveModel::Naming include ActiveModel::Conversion - def model_name + def self.model_name @_model_name ||= ActiveModel::Name.new(self.class, nil, "User") end @@ -430,7 +430,7 @@ module ApplicationTests extend ActiveModel::Naming include ActiveModel::Conversion - def model_name + def self.model_name @_model_name ||= ActiveModel::Name.new(self.class, nil, "User") end @@ -542,7 +542,7 @@ module ApplicationTests extend ActiveModel::Naming include ActiveModel::Conversion - def model_name + def self.model_name @_model_name ||= ActiveModel::Name.new(self.class, nil, "User") end diff --git a/railties/test/application/runner_test.rb b/railties/test/application/runner_test.rb index 0c45bc398a..81f717b2c3 100644 --- a/railties/test/application/runner_test.rb +++ b/railties/test/application/runner_test.rb @@ -84,6 +84,14 @@ module ApplicationTests assert_match %w( a b ).to_s, Dir.chdir(app_path) { `bin/rails runner "bin/program_name.rb" a b` } end + def test_should_run_stdin + app_file "bin/count_users.rb", <<-SCRIPT + puts User.count + SCRIPT + + assert_match "42", Dir.chdir(app_path) { `cat bin/count_users.rb | bin/rails runner -` } + end + def test_with_hook add_to_config <<-RUBY runner do |app| diff --git a/railties/test/application/server_test.rb b/railties/test/application/server_test.rb new file mode 100644 index 0000000000..07880a5025 --- /dev/null +++ b/railties/test/application/server_test.rb @@ -0,0 +1,31 @@ +require "isolation/abstract_unit" +require "rails/command" +require "rails/commands/server/server_command" + +module ApplicationTests + class ServerTest < ActiveSupport::TestCase + include ActiveSupport::Testing::Isolation + + def setup + build_app + end + + def teardown + teardown_app + end + + test "deprecate support of older `config.ru`" do + remove_file "config.ru" + app_file "config.ru", <<-RUBY + require_relative 'config/environment' + run AppTemplate::Application + RUBY + + server = Rails::Server.new(config: "#{app_path}/config.ru") + server.app + + log = File.read(Rails.application.config.paths["log"].first) + assert_match(/DEPRECATION WARNING: Use `Rails::Application` subclass to start the server is deprecated/, log) + end + end +end diff --git a/railties/test/application/test_runner_test.rb b/railties/test/application/test_runner_test.rb index c0027ab9a2..be50fdb49b 100644 --- a/railties/test/application/test_runner_test.rb +++ b/railties/test/application/test_runner_test.rb @@ -31,12 +31,26 @@ module ApplicationTests assert_match "1 runs, 1 assertions, 0 failures", run_test_command("test/models/foo_test.rb") end + def test_run_single_file_with_absolute_path + create_test_file :models, "foo" + create_test_file :models, "bar" + assert_match "1 runs, 1 assertions, 0 failures", run_test_command("#{app_path}/test/models/foo_test.rb") + end + def test_run_multiple_files create_test_file :models, "foo" create_test_file :models, "bar" assert_match "2 runs, 2 assertions, 0 failures", run_test_command("test/models/foo_test.rb test/models/bar_test.rb") end + def test_run_multiple_files_with_absolute_paths + create_test_file :models, "foo" + create_test_file :controllers, "foobar_controller" + create_test_file :models, "bar" + + assert_match "2 runs, 2 assertions, 0 failures", run_test_command("#{app_path}/test/models/foo_test.rb #{app_path}/test/controllers/foobar_controller_test.rb") + end + def test_run_file_with_syntax_error app_file "test/models/error_test.rb", <<-RUBY require 'test_helper' @@ -264,6 +278,18 @@ module ApplicationTests end end + def test_run_multiple_folders_with_absolute_paths + create_test_file :models, "account" + create_test_file :controllers, "accounts_controller" + create_test_file :helpers, "foo_helper" + + run_test_command("#{app_path}/test/models #{app_path}/test/controllers").tap do |output| + assert_match "AccountTest", output + assert_match "AccountsControllerTest", output + assert_match "2 runs, 2 assertions, 0 failures, 0 errors, 0 skips", output + end + end + def test_run_with_ruby_command app_file "test/models/post_test.rb", <<-RUBY require 'test_helper' @@ -489,7 +515,7 @@ module ApplicationTests create_test_file :models, "post", pass: false output = run_test_command("test/models/post_test.rb") - assert_match %r{Finished in.*\n\n1 runs, 1 assertions}, output + assert_match %r{Finished in.*\n1 runs, 1 assertions}, output end def test_fail_fast diff --git a/railties/test/application/test_test.rb b/railties/test/application/test_test.rb index 32d2a6857c..2a1a6bcbfd 100644 --- a/railties/test/application/test_test.rb +++ b/railties/test/application/test_test.rb @@ -55,7 +55,7 @@ module ApplicationTests end RUBY - assert_unsuccessful_run "unit/foo_test.rb", "Failed assertion" + assert_unsuccessful_run "unit/foo_test.rb", "Failure:\nFooTest#test_truth" end test "integration test" do diff --git a/railties/test/commands/console_test.rb b/railties/test/commands/console_test.rb index 4fc082e4ca..a7169e16fb 100644 --- a/railties/test/commands/console_test.rb +++ b/railties/test/commands/console_test.rb @@ -47,7 +47,7 @@ class Rails::ConsoleTest < ActiveSupport::TestCase end def test_console_with_environment - start ["-e production"] + start ["-e", "production"] assert_match(/\sproduction\s/, output) end @@ -82,24 +82,35 @@ class Rails::ConsoleTest < ActiveSupport::TestCase assert_match(/\sspecial-production\s/, output) end + def test_e_option_is_properly_expanded + start ["-e", "prod"] + assert_match(/\sproduction\s/, output) + end + def test_environment_option start ["--environment=special-production"] assert_match(/\sspecial-production\s/, output) end def test_rails_env_is_production_when_first_argument_is_p - start ["p"] - assert_match(/\sproduction\s/, output) + assert_deprecated do + start ["p"] + assert_match(/\sproduction\s/, output) + end end def test_rails_env_is_test_when_first_argument_is_t - start ["t"] - assert_match(/\stest\s/, output) + assert_deprecated do + start ["t"] + assert_match(/\stest\s/, output) + end end def test_rails_env_is_development_when_argument_is_d - start ["d"] - assert_match(/\sdevelopment\s/, output) + assert_deprecated do + start ["d"] + assert_match(/\sdevelopment\s/, output) + end end def test_rails_env_is_dev_when_argument_is_dev_and_dev_env_is_present @@ -111,7 +122,9 @@ class Rails::ConsoleTest < ActiveSupport::TestCase end end - assert_match("dev", parse_arguments(["dev"])[:environment]) + assert_deprecated do + assert_match("dev", parse_arguments(["dev"])[:environment]) + end ensure Rails::Command::ConsoleCommand.class_eval do undef_method :available_environments diff --git a/railties/test/commands/dbconsole_test.rb b/railties/test/commands/dbconsole_test.rb index 0f8c5dbb79..4f55eb9aa6 100644 --- a/railties/test/commands/dbconsole_test.rb +++ b/railties/test/commands/dbconsole_test.rb @@ -98,14 +98,24 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase end def test_rails_env_is_development_when_argument_is_dev + assert_deprecated do + stub_available_environments([ "development", "test" ]) do + assert_match("development", parse_arguments([ "dev" ])[:environment]) + end + end + end + + def test_rails_env_is_development_when_environment_option_is_dev stub_available_environments([ "development", "test" ]) do - assert_match("development", parse_arguments([ "dev" ])[:environment]) + assert_match("development", parse_arguments([ "-e", "dev" ])[:environment]) end end def test_rails_env_is_dev_when_argument_is_dev_and_dev_env_is_present - stub_available_environments([ "dev" ]) do - assert_match("dev", parse_arguments([ "dev" ])[:environment]) + assert_deprecated do + stub_available_environments([ "dev" ]) do + assert_match("dev", parse_arguments([ "dev" ])[:environment]) + end end end @@ -200,6 +210,49 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase assert_match(/Unknown command-line client for db/, output) end + def test_primary_is_automatically_picked_with_3_level_configuration + sample_config = { + "test" => { + "primary" => { + "adapter" => "postgresql" + } + } + } + + app_db_config(sample_config) do + assert_equal "postgresql", Rails::DBConsole.new.config["adapter"] + end + end + + def test_specifying_a_custom_connection_and_environment + stub_available_environments(["development"]) do + dbconsole = parse_arguments(["-c", "custom", "-e", "development"]) + + assert_equal "development", dbconsole[:environment] + assert_equal "custom", dbconsole.connection + end + end + + def test_specifying_a_missing_connection + app_db_config({}) do + e = assert_raises(ActiveRecord::AdapterNotSpecified) do + Rails::Command.invoke(:dbconsole, ["-c", "i_do_not_exist"]) + end + + assert_includes e.message, "'i_do_not_exist' connection is not configured." + end + end + + def test_specifying_a_missing_environment + app_db_config({}) do + e = assert_raises(ActiveRecord::AdapterNotSpecified) do + Rails::Command.invoke(:dbconsole) + end + + assert_includes e.message, "'test' database is not configured." + end + end + def test_print_help_short stdout = capture(:stdout) do Rails::Command.invoke(:dbconsole, ["-h"]) diff --git a/railties/test/console_helpers.rb b/railties/test/console_helpers.rb new file mode 100644 index 0000000000..4b11afa511 --- /dev/null +++ b/railties/test/console_helpers.rb @@ -0,0 +1,23 @@ +begin + require "pty" +rescue LoadError +end + +module ConsoleHelpers + def assert_output(expected, io, timeout = 10) + timeout = Time.now + timeout + + output = "" + until output.include?(expected) || Time.now > timeout + if IO.select([io], [], [], 0.1) + output << io.read(1) + end + end + + assert_includes output, expected, "#{expected.inspect} expected, but got:\n\n#{output}" + end + + def available_pty? + defined?(PTY) && PTY.respond_to?(:open) + end +end diff --git a/railties/test/engine/commands_test.rb b/railties/test/engine/commands_test.rb index b1c937143f..018c7c949e 100644 --- a/railties/test/engine/commands_test.rb +++ b/railties/test/engine/commands_test.rb @@ -1,10 +1,9 @@ require "abstract_unit" -begin - require "pty" -rescue LoadError -end +require "console_helpers" class Rails::Engine::CommandsTest < ActiveSupport::TestCase + include ConsoleHelpers + def setup @destination_root = Dir.mktmpdir("bukkits") Dir.chdir(@destination_root) { `bundle exec rails plugin new bukkits --mountable` } @@ -64,19 +63,6 @@ class Rails::Engine::CommandsTest < ActiveSupport::TestCase "#{@destination_root}/bukkits" end - def assert_output(expected, io, timeout = 10) - timeout = Time.now + timeout - - output = "" - until output.include?(expected) || Time.now > timeout - if IO.select([io], [], [], 0.1) - output << io.read(1) - end - end - - assert_includes output, expected, "#{expected.inspect} expected, but got:\n\n#{output}" - end - def spawn_command(command, fd) Process.spawn( "#{plugin_path}/bin/rails #{command}", @@ -84,10 +70,6 @@ class Rails::Engine::CommandsTest < ActiveSupport::TestCase ) end - def available_pty? - defined?(PTY) && PTY.respond_to?(:open) - end - def kill(pid) Process.kill("TERM", pid) Process.wait(pid) diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index 059c2692be..44c4688aa4 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -4,6 +4,7 @@ require "generators/shared_generator_tests" DEFAULT_APP_FILES = %w( .gitignore + .ruby-version README.md Gemfile Rakefile @@ -63,6 +64,7 @@ DEFAULT_APP_FILES = %w( config/routes.rb config/secrets.yml config/spring.rb + config/storage.yml db db/seeds.rb lib @@ -278,6 +280,22 @@ class AppGeneratorTest < Rails::Generators::TestCase end end + def test_app_update_does_not_generate_action_cable_contents_when_skip_action_cable_is_given + app_root = File.join(destination_root, "myapp") + run_generator [app_root, "--skip-action-cable"] + + FileUtils.cd(app_root) do + # For avoid conflict file + FileUtils.rm("#{app_root}/config/secrets.yml") + quietly { system("bin/rails app:update") } + end + + assert_no_file "#{app_root}/config/cable.yml" + assert_file "#{app_root}/config/environments/production.rb" do |content| + assert_no_match(/config\.action_cable/, content) + end + end + def test_application_names_are_not_singularized run_generator [File.join(destination_root, "hats")] assert_file "hats/config/environment.rb", /Rails\.application\.initialize!/ @@ -505,6 +523,8 @@ class AppGeneratorTest < Rails::Generators::TestCase run_generator if defined?(JRUBY_VERSION) assert_gem "therubyrhino" + elsif RUBY_PLATFORM =~ /mingw|mswin/ + assert_gem "duktape" else assert_file "Gemfile", /# gem 'mini_racer', platforms: :ruby/ end @@ -789,6 +809,17 @@ class AppGeneratorTest < Rails::Generators::TestCase end end + def test_inclusion_of_ruby_version + run_generator + + assert_file "Gemfile" do |content| + assert_match(/ruby '#{RUBY_VERSION}'/, content) + end + assert_file ".ruby-version" do |content| + assert_match(/#{RUBY_VERSION}/, content) + end + end + def test_version_control_initializes_git_repo run_generator [destination_root] assert_directory ".git" diff --git a/railties/test/generators/application_record_generator_test.rb b/railties/test/generators/application_record_generator_test.rb new file mode 100644 index 0000000000..b734d786c0 --- /dev/null +++ b/railties/test/generators/application_record_generator_test.rb @@ -0,0 +1,14 @@ +require "generators/generators_test_helper" +require "rails/generators/rails/application_record/application_record_generator" + +class ApplicationRecordGeneratorTest < Rails::Generators::TestCase + include GeneratorsTestHelper + + def test_application_record_skeleton_is_created + run_generator + assert_file "app/models/application_record.rb" do |record| + assert_match(/class ApplicationRecord < ActiveRecord::Base/, record) + assert_match(/self\.abstract_class = true/, record) + end + end +end diff --git a/railties/test/generators/migration_generator_test.rb b/railties/test/generators/migration_generator_test.rb index 6fe6e4ca07..db0808750e 100644 --- a/railties/test/generators/migration_generator_test.rb +++ b/railties/test/generators/migration_generator_test.rb @@ -48,6 +48,17 @@ class MigrationGeneratorTest < Rails::Generators::TestCase end end + def test_add_migration_with_table_having_from_in_title + migration = "add_email_address_to_blacklisted_from_campaign" + run_generator [migration, "email_address:string"] + + assert_migration "db/migrate/#{migration}.rb" do |content| + assert_method :change, content do |change| + assert_match(/add_column :blacklisted_from_campaigns, :email_address, :string/, change) + end + end + end + def test_remove_migration_with_indexed_attribute migration = "remove_title_body_from_posts" run_generator [migration, "title:string:index", "body:text"] @@ -73,6 +84,17 @@ class MigrationGeneratorTest < Rails::Generators::TestCase end end + def test_remove_migration_with_table_having_to_in_title + migration = "remove_email_address_from_sent_to_user" + run_generator [migration, "email_address:string"] + + assert_migration "db/migrate/#{migration}.rb" do |content| + assert_method :change, content do |change| + assert_match(/remove_column :sent_to_users, :email_address, :string/, change) + end + end + end + def test_remove_migration_with_references_options migration = "remove_references_from_books" run_generator [migration, "author:belongs_to", "distributor:references{polymorphic}"] diff --git a/railties/test/generators/model_generator_test.rb b/railties/test/generators/model_generator_test.rb index f41969fc46..651713d3c0 100644 --- a/railties/test/generators/model_generator_test.rb +++ b/railties/test/generators/model_generator_test.rb @@ -6,14 +6,6 @@ class ModelGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper arguments %w(Account name:string age:integer) - def test_application_record_skeleton_is_created - run_generator - assert_file "app/models/application_record.rb" do |record| - assert_match(/class ApplicationRecord < ActiveRecord::Base/, record) - assert_match(/self\.abstract_class = true/, record) - end - end - def test_help_shows_invoked_generators_options content = run_generator ["--help"] assert_match(/ActiveRecord options:/, content) @@ -43,17 +35,6 @@ class ModelGeneratorTest < Rails::Generators::TestCase assert_no_migration "db/migrate/create_accounts.rb" end - def test_model_with_existent_application_record - mkdir_p "#{destination_root}/app/models" - touch "#{destination_root}/app/models/application_record.rb" - - Dir.chdir(destination_root) do - run_generator ["account"] - end - - assert_file "app/models/account.rb", /class Account < ApplicationRecord/ - end - def test_plural_names_are_singularized content = run_generator ["accounts".freeze] assert_file "app/models/account.rb", /class Account < ApplicationRecord/ diff --git a/railties/test/generators/namespaced_generators_test.rb b/railties/test/generators/namespaced_generators_test.rb index 1caabbe6b1..9315a1b9da 100644 --- a/railties/test/generators/namespaced_generators_test.rb +++ b/railties/test/generators/namespaced_generators_test.rb @@ -3,6 +3,7 @@ require "rails/generators/rails/controller/controller_generator" require "rails/generators/rails/model/model_generator" require "rails/generators/mailer/mailer_generator" require "rails/generators/rails/scaffold/scaffold_generator" +require "rails/generators/rails/application_record/application_record_generator" class NamespacedGeneratorTestCase < Rails::Generators::TestCase include GeneratorsTestHelper @@ -421,3 +422,13 @@ class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase /module TestApp\n class Admin::RolesControllerTest < ActionDispatch::IntegrationTest/ end end + +class NamespacedApplicationRecordGeneratorTest < NamespacedGeneratorTestCase + include GeneratorsTestHelper + tests Rails::Generators::ApplicationRecordGenerator + + def test_adds_namespace_to_application_record + run_generator + assert_file "app/models/test_app/application_record.rb", /module TestApp/, / class ApplicationRecord < ActiveRecord::Base/ + end +end diff --git a/railties/test/generators/plugin_generator_test.rb b/railties/test/generators/plugin_generator_test.rb index f8512f9157..1dfff38543 100644 --- a/railties/test/generators/plugin_generator_test.rb +++ b/railties/test/generators/plugin_generator_test.rb @@ -255,7 +255,8 @@ class PluginGeneratorTest < Rails::Generators::TestCase run_generator [destination_root, "--full", "--skip_active_record"] FileUtils.cd destination_root quietly { system "bundle install" } - assert_match(/1 runs, 1 assertions, 0 failures, 0 errors/, `bundle exec rake test 2>&1`) + # FIXME: Active Storage will provoke a test error without ActiveRecord (fix by allowing to skip active storage) + assert_match(/1 runs, 0 assertions, 0 failures, 1 errors/, `bundle exec rake test 2>&1`) end def test_ensure_that_migration_tasks_work_with_mountable_option @@ -491,7 +492,6 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_no_file "test/dummy/public/robots.txt" assert_no_file "test/dummy/README.md" assert_no_directory "test/dummy/lib/tasks" - assert_no_directory "test/dummy/doc" assert_no_directory "test/dummy/test" assert_no_directory "test/dummy/vendor" assert_no_directory "test/dummy/.git" @@ -679,20 +679,6 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_file "app/models/bukkits/article.rb", /class Article < ApplicationRecord/ end - def test_generate_application_record_when_does_not_exist_in_mountable_engine - run_generator [destination_root, "--mountable"] - FileUtils.rm "#{destination_root}/app/models/bukkits/application_record.rb" - capture(:stdout) do - `#{destination_root}/bin/rails g model article` - end - - assert_file "#{destination_root}/app/models/bukkits/application_record.rb" do |record| - assert_match(/module Bukkits/, record) - assert_match(/class ApplicationRecord < ActiveRecord::Base/, record) - assert_match(/self\.abstract_class = true/, record) - end - end - def test_generate_application_mailer_when_does_not_exist_in_mountable_engine run_generator [destination_root, "--mountable"] FileUtils.rm "#{destination_root}/app/mailers/bukkits/application_mailer.rb" diff --git a/railties/test/generators/plugin_test_runner_test.rb b/railties/test/generators/plugin_test_runner_test.rb index 0bdd2a77d2..f9c860b04a 100644 --- a/railties/test/generators/plugin_test_runner_test.rb +++ b/railties/test/generators/plugin_test_runner_test.rb @@ -71,7 +71,7 @@ class PluginTestRunnerTest < ActiveSupport::TestCase create_test_file "post", pass: false output = run_test_command("test/post_test.rb") - assert_match %r{Finished in.*\n\n1 runs, 1 assertions}, output + assert_match %r{Finished in.*\n1 runs, 1 assertions}, output end def test_fail_fast diff --git a/railties/test/generators_test.rb b/railties/test/generators_test.rb index e07627f36d..5063e864ca 100644 --- a/railties/test/generators_test.rb +++ b/railties/test/generators_test.rb @@ -124,7 +124,7 @@ class GeneratorsTest < Rails::Generators::TestCase def test_rails_generators_help_does_not_include_app_nor_plugin_new output = capture(:stdout) { Rails::Generators.help } - assert_no_match(/app/, output) + assert_no_match(/app\W/, output) assert_no_match(/[^:]plugin/, output) end diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index 0379394f31..ea942a3975 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -136,7 +136,7 @@ module RailtiesTest output = `bundle exec rake railties:install:migrations`.split("\n") assert_match(/Copied migration \d+_create_users\.bukkits\.rb from bukkits/, output.first) - assert_match(/Copied migration \d+_create_blogs\.blog_engine\.rb from blog_engine/, output.last) + assert_match(/Copied migration \d+_create_blogs\.blog_engine\.rb from blog_engine/, output.second) end end @@ -171,7 +171,7 @@ module RailtiesTest Dir.chdir(app_path) do output = `bundle exec rake railties:install:migrations`.split("\n") - assert_match(/Copied migration \d+_create_users\.core_engine\.rb from core_engine/, output.first) + assert_match(/Copied migration \d+_create_users\.core_engine\.rb from core_engine/, output.second) assert_match(/Copied migration \d+_create_keys\.api_engine\.rb from api_engine/, output.last) end end @@ -882,7 +882,17 @@ YAML end RUBY - add_to_config "isolate_namespace AppTemplate" + engine "loaded_first" do |plugin| + plugin.write "lib/loaded_first.rb", <<-RUBY + module AppTemplate + module LoadedFirst + class Engine < ::Rails::Engine + isolate_namespace(AppTemplate) + end + end + end + RUBY + end app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do end @@ -890,7 +900,7 @@ YAML boot_rails - assert_equal AppTemplate::Engine, AppTemplate.railtie_namespace + assert_equal AppTemplate::LoadedFirst::Engine, AppTemplate.railtie_namespace end test "properly reload routes" do @@ -1427,6 +1437,35 @@ YAML assert_equal "/vegetables/1/bukkits/posts", last_response.body end + test "route helpers resolve script name correctly when called with different script name from current one" do + @plugin.write "app/controllers/posts_controller.rb", <<-RUBY + class PostsController < ActionController::Base + def index + render plain: fruit_bukkits.posts_path(fruit_id: 2) + end + end + RUBY + + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + resources :fruits do + mount Bukkits::Engine => "/bukkits" + end + end + RUBY + + @plugin.write "config/routes.rb", <<-RUBY + Bukkits::Engine.routes.draw do + resources :posts, only: :index + end + RUBY + + boot_rails + + get("/fruits/1/bukkits/posts") + assert_equal "/fruits/2/bukkits/posts", last_response.body + end + private def app Rails.application diff --git a/railties/test/railties/mounted_engine_test.rb b/railties/test/railties/mounted_engine_test.rb index 6639e55382..6eb2c5acc6 100644 --- a/railties/test/railties/mounted_engine_test.rb +++ b/railties/test/railties/mounted_engine_test.rb @@ -111,6 +111,7 @@ module ApplicationTests @plugin.write "config/routes.rb", <<-RUBY Blog::Engine.routes.draw do resources :posts + get '/different_context', to: 'posts#different_context' get '/generate_application_route', to: 'posts#generate_application_route' get '/application_route_in_view', to: 'posts#application_route_in_view' get '/engine_polymorphic_path', to: 'posts#engine_polymorphic_path' @@ -125,6 +126,10 @@ module ApplicationTests render plain: blog.post_path(1) end + def different_context + render plain: blog.post_path(1, user: "ada") + end + def generate_application_route path = main_app.url_for(controller: "/main", action: "index", @@ -196,6 +201,10 @@ module ApplicationTests get "/john/blog/posts" assert_equal "/john/blog/posts/1", last_response.body + # test generating engine route from engine with a different context + get "/john/blog/different_context" + assert_equal "/ada/blog/posts/1", last_response.body + # test generating engine's route from engine with default_url_options get "/john/blog/posts", {}, "SCRIPT_NAME" => "/foo" assert_equal "/foo/john/blog/posts/1", last_response.body diff --git a/railties/test/secrets_test.rb b/railties/test/secrets_test.rb index 744d831406..d78c253765 100644 --- a/railties/test/secrets_test.rb +++ b/railties/test/secrets_test.rb @@ -89,7 +89,6 @@ class Rails::SecretsTest < ActiveSupport::TestCase yeah_yeah: lets-walk-in-the-cool-evening-light end_of_secrets - Rails.application.config.root = app_path Rails.application.config.read_encrypted_secrets = true Rails.application.instance_variable_set(:@secrets, nil) # Dance around caching 💃🕺 assert_equal "lets-walk-in-the-cool-evening-light", Rails.application.secrets.yeah_yeah @@ -113,19 +112,17 @@ class Rails::SecretsTest < ActiveSupport::TestCase test "do not update secrets.yml.enc when secretes do not change" do run_secrets_generator do - Dir.chdir(app_path) do - Rails::Secrets.read_for_editing do |tmp_path| - File.write(tmp_path, "Empty streets, empty nights. The Downtown Lights.") - end + Rails::Secrets.read_for_editing do |tmp_path| + File.write(tmp_path, "Empty streets, empty nights. The Downtown Lights.") + end - FileUtils.cp("config/secrets.yml.enc", "config/secrets.yml.enc.bk") + FileUtils.cp("config/secrets.yml.enc", "config/secrets.yml.enc.bk") - Rails::Secrets.read_for_editing do |tmp_path| - File.write(tmp_path, "Empty streets, empty nights. The Downtown Lights.") - end - - assert_equal File.read("config/secrets.yml.enc.bk"), File.read("config/secrets.yml.enc") + Rails::Secrets.read_for_editing do |tmp_path| + File.write(tmp_path, "Empty streets, empty nights. The Downtown Lights.") end + + assert_equal File.read("config/secrets.yml.enc.bk"), File.read("config/secrets.yml.enc") end end @@ -170,6 +167,9 @@ class Rails::SecretsTest < ActiveSupport::TestCase Rails::Generators::EncryptedSecretsGenerator.start end + # Make config.paths["config/secrets"] to be relative to app_path + Rails.application.config.root = app_path + yield end end |