diff options
Diffstat (limited to 'railties')
67 files changed, 711 insertions, 308 deletions
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index 8f4dc736a8..a4eaf0ab0f 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,3 +1,47 @@ +* The application generator writes a new file `config/spring.rb`, which tells + Spring to watch additional common files. + + *Xavier Noria* + +* The tasks in the rails task namespace is deprecated in favor of app namespace. + (e.g. `rails:update` and `rails:template` tasks is renamed to `app:update` and `app:template`.) + + *Ryo Hashimoto* + +* Enable HSTS with IncludeSudomains header for new applications. + + *Egor Homakov*, *Prathamesh Sonpatki* + +## Rails 5.0.0.beta3 (February 24, 2016) ## + +* Alias `rake` with `rails_command` in the Rails Application Templates API + following Rails 5 convention of preferring "rails" to "rake" to run tasks. + + *claudiob* + +* Generate applications with an option to log to STDOUT in production + using the environment variable `RAILS_LOG_TO_STDOUT`. + + *Richard Schneeman* + +* Change fail fast of `bin/rails test` interrupts run on error. + + *Yuji Yaginuma* + +* The application generator supports `--skip-listen` to opt-out of features + that depend on the listen gem. As of this writing they are the evented file + system monitor and the async plugin for spring. + +* The Gemfiles of new applications include spring-watcher-listen on Linux and + Mac OS X (unless --skip-spring). + + *Xavier Noria* + +* New applications are generated with the evented file system monitor enabled + on Linux and Mac OS X. + + *Xavier Noria* + * Add dummy files for apple-touch-icon.png and apple-touch-icon.png. GH#23427 *Alexey Zabelin* diff --git a/railties/lib/rails/app_loader.rb b/railties/lib/rails/app_loader.rb index a9fe21824e..af004d85bf 100644 --- a/railties/lib/rails/app_loader.rb +++ b/railties/lib/rails/app_loader.rb @@ -16,7 +16,7 @@ like any other source code, rather than stubs that are generated on demand. Here's how to upgrade: bundle config --delete bin # Turn off Bundler's stub generator - rake rails:update:bin # Use the new Rails 4 executables + rails app:update:bin # Use the new Rails 5 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/application.rb b/railties/lib/rails/application.rb index cac31e1eed..4729ddcf62 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -74,8 +74,7 @@ module Rails # the configuration. # # If you decide to define rake tasks, runners, or initializers in an - # application other than +Rails.application+, then you must run those - # these manually. + # application other than +Rails.application+, then you must run them manually. class Application < Engine autoload :Bootstrap, 'rails/application/bootstrap' autoload :Configuration, 'rails/application/configuration' @@ -113,7 +112,7 @@ module Rails attr_accessor :assets, :sandbox alias_method :sandbox?, :sandbox - attr_reader :reloaders + attr_reader :reloaders, :reloader, :executor delegate :default_url_options, :default_url_options=, to: :routes @@ -131,6 +130,10 @@ module Rails @message_verifiers = {} @ran_load_hooks = false + @executor = Class.new(ActiveSupport::Executor) + @reloader = Class.new(ActiveSupport::Reloader) + @reloader.executor = @executor + # are these actually used? @initial_variable_values = initial_variable_values @block = block @@ -214,7 +217,7 @@ module Rails # url: http://localhost:3001 # namespace: my_app_development # - # # config/production.rb + # # config/environments/production.rb # Rails.application.configure do # config.middleware.use ExceptionNotifier, config_for(:exception_notification) # end diff --git a/railties/lib/rails/application/default_middleware_stack.rb b/railties/lib/rails/application/default_middleware_stack.rb index 4f1cc0703d..381e548730 100644 --- a/railties/lib/rails/application/default_middleware_stack.rb +++ b/railties/lib/rails/application/default_middleware_stack.rb @@ -34,22 +34,10 @@ module Rails # handling: presumably their code is not threadsafe middleware.use ::Rack::Lock - - elsif config.allow_concurrency == :unsafe - # Do nothing, even if we know this is dangerous. This is the - # historical behaviour for true. - - else - # Default concurrency setting: enabled, but safe - - unless config.cache_classes && config.eager_load - # Without cache_classes + eager_load, the load interlock - # is required for proper operation - - middleware.use ::ActionDispatch::LoadInterlock - end end + middleware.use ::ActionDispatch::Executor, app.executor + middleware.use ::Rack::Runtime middleware.use ::Rack::MethodOverride unless config.api_only middleware.use ::ActionDispatch::RequestId @@ -61,7 +49,7 @@ module Rails middleware.use ::ActionDispatch::RemoteIp, config.action_dispatch.ip_spoofing_check, config.action_dispatch.trusted_proxies unless config.cache_classes - middleware.use ::ActionDispatch::Reloader, lambda { reload_dependencies? } + middleware.use ::ActionDispatch::Reloader, app.reloader end middleware.use ::ActionDispatch::Callbacks @@ -83,10 +71,6 @@ module Rails private - def reload_dependencies? - config.reload_classes_only_on_change != true || app.reloaders.map(&:updated?).any? - end - def load_rack_cache rack_cache = config.action_dispatch.rack_cache return unless rack_cache diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index 411cdbad19..34f2265108 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -22,10 +22,10 @@ module Rails initializer :add_builtin_route do |app| if Rails.env.development? app.routes.append do - get '/rails/info/properties' => "rails/info#properties" - get '/rails/info/routes' => "rails/info#routes" - get '/rails/info' => "rails/info#index" - get '/' => "rails/welcome#index" + get '/rails/info/properties' => "rails/info#properties", internal: true + get '/rails/info/routes' => "rails/info#routes", internal: true + get '/rails/info' => "rails/info#index", internal: true + get '/' => "rails/welcome#index", internal: true end end end @@ -38,16 +38,16 @@ module Rails app.routes.define_mounted_helper(:main_app) end - initializer :add_to_prepare_blocks do + initializer :add_to_prepare_blocks do |app| config.to_prepare_blocks.each do |block| - ActionDispatch::Reloader.to_prepare(&block) + app.reloader.to_prepare(&block) end end # This needs to happen before eager load so it happens # in exactly the same point regardless of config.cache_classes - initializer :run_prepare_callbacks do - ActionDispatch::Reloader.prepare! + initializer :run_prepare_callbacks do |app| + app.reloader.prepare! end initializer :eager_load! do @@ -62,13 +62,47 @@ module Rails ActiveSupport.run_load_hooks(:after_initialize, self) end + initializer :configure_executor_for_concurrency do |app| + if config.allow_concurrency == false + # User has explicitly opted out of concurrent request + # handling: presumably their code is not threadsafe + + mutex = Mutex.new + app.executor.to_run(prepend: true) do + mutex.lock + end + app.executor.to_complete(:after) do + mutex.unlock + end + + elsif config.allow_concurrency == :unsafe + # Do nothing, even if we know this is dangerous. This is the + # historical behaviour for true. + + else + # Default concurrency setting: enabled, but safe + + unless config.cache_classes && config.eager_load + # Without cache_classes + eager_load, the load interlock + # is required for proper operation + + app.executor.to_run(prepend: true) do + ActiveSupport::Dependencies.interlock.start_running + end + app.executor.to_complete(:after) do + ActiveSupport::Dependencies.interlock.done_running + end + end + end + end + # Set routes reload after the finisher hook to ensure routes added in # the hook are taken into account. - initializer :set_routes_reloader_hook do + initializer :set_routes_reloader_hook do |app| reloader = routes_reloader reloader.execute_if_updated self.reloaders << reloader - ActionDispatch::Reloader.to_prepare do + app.reloader.to_run do # We configure #execute rather than #execute_if_updated because if # autoloaded constants are cleared we need to reload routes also in # case any was used there, as in @@ -78,18 +112,27 @@ module Rails # This means routes are also reloaded if i18n is updated, which # might not be necessary, but in order to be more precise we need # some sort of reloaders dependency support, to be added. + require_unload_lock! reloader.execute end end # Set clearing dependencies after the finisher hook to ensure paths # added in the hook are taken into account. - initializer :set_clear_dependencies_hook, group: :all do + initializer :set_clear_dependencies_hook, group: :all do |app| callback = lambda do - ActiveSupport::Dependencies.interlock.unloading do - ActiveSupport::DescendantsTracker.clear - ActiveSupport::Dependencies.clear + ActiveSupport::DescendantsTracker.clear + ActiveSupport::Dependencies.clear + end + + if config.cache_classes + app.reloader.check = lambda { false } + elsif config.reload_classes_only_on_change + app.reloader.check = lambda do + app.reloaders.map(&:updated?).any? end + else + app.reloader.check = lambda { true } end if config.reload_classes_only_on_change @@ -99,15 +142,19 @@ module Rails # Prepend this callback to have autoloaded constants cleared before # any other possible reloading, in case they need to autoload fresh # constants. - ActionDispatch::Reloader.to_prepare(prepend: true) do + app.reloader.to_run(prepend: true) do # In addition to changes detected by the file watcher, if routes # or i18n have been updated we also need to clear constants, # that's why we run #execute rather than #execute_if_updated, this # callback has to clear autoloaded constants after any update. - reloader.execute + class_unload! do + reloader.execute + end end else - ActionDispatch::Reloader.to_cleanup(&callback) + app.reloader.to_complete do + class_unload!(&callback) + end end end diff --git a/railties/lib/rails/commands.rb b/railties/lib/rails/commands.rb index 7627fcf5a0..fa47c52b96 100644 --- a/railties/lib/rails/commands.rb +++ b/railties/lib/rails/commands.rb @@ -14,6 +14,5 @@ command = ARGV.shift command = aliases[command] || command require 'rails/command' -require 'rails/commands/dev_cache' Rails::Command.run(command, ARGV) diff --git a/railties/lib/rails/commands/dev_cache.rb b/railties/lib/rails/commands/dev_cache.rb deleted file mode 100644 index ec96e8f630..0000000000 --- a/railties/lib/rails/commands/dev_cache.rb +++ /dev/null @@ -1,21 +0,0 @@ -require 'rails/command' - -module Rails - module Commands - # This is a wrapper around the Rails dev:cache command - class DevCache < Command - set_banner :dev_cache, 'Toggle development mode caching on/off' - def dev_cache - if File.exist? 'tmp/caching-dev.txt' - File.delete 'tmp/caching-dev.txt' - puts 'Development mode is no longer being cached.' - else - FileUtils.touch 'tmp/caching-dev.txt' - puts 'Development mode is now being cached.' - end - - FileUtils.touch 'tmp/restart.txt' - end - end - end -end diff --git a/railties/lib/rails/commands/server.rb b/railties/lib/rails/commands/server.rb index 27cbaf360a..d7597a13e1 100644 --- a/railties/lib/rails/commands/server.rb +++ b/railties/lib/rails/commands/server.rb @@ -114,8 +114,6 @@ module Rails puts "=> Booting #{ActiveSupport::Inflector.demodulize(server)}" puts "=> Rails #{Rails.version} application starting in #{Rails.env} on #{url}" puts "=> Run `rails server -h` for more startup options" - - puts "=> Ctrl-C to shutdown server" unless options[:daemonize] end def create_cache_file diff --git a/railties/lib/rails/console/app.rb b/railties/lib/rails/console/app.rb index ac5836a588..9ad77e0a80 100644 --- a/railties/lib/rails/console/app.rb +++ b/railties/lib/rails/console/app.rb @@ -29,8 +29,7 @@ module Rails # reloads the environment def reload!(print=true) puts "Reloading..." if print - ActionDispatch::Reloader.cleanup! - ActionDispatch::Reloader.prepare! + Rails.application.reloader.reload! true end end diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb index 8cadbc3ddd..294d07446f 100644 --- a/railties/lib/rails/engine/configuration.rb +++ b/railties/lib/rails/engine/configuration.rb @@ -39,6 +39,7 @@ module Rails paths.add "app", eager_load: true, glob: "{*,*/concerns}" paths.add "app/assets", glob: "*" paths.add "app/controllers", eager_load: true + paths.add "app/channels", eager_load: true, glob: "**/*_channel.rb" paths.add "app/helpers", eager_load: true paths.add "app/models", eager_load: true paths.add "app/mailers", eager_load: true diff --git a/railties/lib/rails/gem_version.rb b/railties/lib/rails/gem_version.rb index 93e0151602..081222425c 100644 --- a/railties/lib/rails/gem_version.rb +++ b/railties/lib/rails/gem_version.rb @@ -8,7 +8,7 @@ module Rails MAJOR = 5 MINOR = 0 TINY = 0 - PRE = "beta2" + PRE = "beta3" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb index e3d79521e7..330bd7ec5d 100644 --- a/railties/lib/rails/generators.rb +++ b/railties/lib/rails/generators.rb @@ -105,7 +105,7 @@ module Rails # Configure generators for API only applications. It basically hides # everything that is usually browser related, such as assets and session - # migration generators, and completely disable views, helpers and assets + # migration generators, and completely disable helpers and assets # so generators such as scaffold won't create them. def self.api_only! hide_namespaces "assets", "helper", "css", "js" @@ -116,6 +116,10 @@ module Rails helper: false, template_engine: nil ) + + if ARGV.first == 'mailer' + options[:rails].merge!(template_engine: :erb) + end end # Remove the color from output. diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb index 9ca731347a..5fa487b78e 100644 --- a/railties/lib/rails/generators/actions.rb +++ b/railties/lib/rails/generators/actions.rb @@ -216,8 +216,9 @@ module Rails log :rake, command env = options[:env] || ENV["RAILS_ENV"] || 'development' sudo = options[:sudo] && RbConfig::CONFIG['host_os'] !~ /mswin|mingw/ ? 'sudo ' : '' - in_root { run("#{sudo}#{extify(:rake)} #{command} RAILS_ENV=#{env}", verbose: false) } + in_root { run("#{sudo}#{extify(:rails)} #{command} RAILS_ENV=#{env}", verbose: false) } end + alias :rails_command :rake # Just run the capify command in root # diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index 9b1e16a7a3..89341e6fa2 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -63,6 +63,9 @@ module Rails class_option :skip_spring, type: :boolean, default: false, desc: "Don't install Spring application preloader" + class_option :skip_listen, type: :boolean, default: false, + desc: "Don't generate configuration that depends on the listen gem" + class_option :skip_javascript, type: :boolean, aliases: '-J', default: false, desc: 'Skip JavaScript files' @@ -178,7 +181,7 @@ module Rails def webserver_gemfile_entry return [] if options[:skip_puma] comment = 'Use Puma as the app server' - GemfileEntry.new('puma', nil, comment) + GemfileEntry.new('puma', '~> 3.0', comment) end def include_all_railties? @@ -308,12 +311,7 @@ module Rails end def coffee_gemfile_entry - comment = 'Use CoffeeScript for .coffee assets and views' - if options.dev? || options.edge? - GemfileEntry.github 'coffee-rails', 'rails/coffee-rails', nil, comment - else - GemfileEntry.version 'coffee-rails', '~> 4.1.0', comment - end + GemfileEntry.version 'coffee-rails', '~> 4.1.0', 'Use CoffeeScript for .coffee assets and views' end def javascript_gemfile_entry @@ -325,8 +323,8 @@ module Rails "Use #{options[:javascript]} as the JavaScript library") unless options[:skip_turbolinks] - gems << GemfileEntry.version("turbolinks", nil, - "Turbolinks makes following links in your web application faster. Read more: https://github.com/turbolinks/turbolinks") + gems << GemfileEntry.version("turbolinks", "~> 5.x", + "Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks") end gems @@ -390,6 +388,14 @@ module Rails !options[:skip_spring] && !options.dev? && Process.respond_to?(:fork) && !RUBY_PLATFORM.include?("cygwin") end + def depend_on_listen? + !options[:skip_listen] && os_supports_listen_out_of_the_box? + end + + def os_supports_listen_out_of_the_box? + RbConfig::CONFIG['host_os'] =~ /darwin|linux/ + end + def run_bundle bundle_command('install') if bundle_install? end diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 248ad20019..e9435c946a 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -80,6 +80,7 @@ module Rails template "secrets.yml" template "cable.yml" unless options[:skip_action_cable] template "puma.rb" unless options[:skip_puma] + template "spring.rb" if spring_install? directory "environments" directory "initializers" @@ -91,6 +92,9 @@ module Rails cookie_serializer_config_exist = File.exist?('config/initializers/cookies_serializer.rb') callback_terminator_config_exist = File.exist?('config/initializers/callback_terminator.rb') active_record_belongs_to_required_by_default_config_exist = File.exist?('config/initializers/active_record_belongs_to_required_by_default.rb') + action_cable_config_exist = File.exist?('config/cable.yml') + ssl_options_exist = File.exist?('config/initializers/ssl_options.rb') + rack_cors_config_exist = File.exist?('config/initializers/cors.rb') config @@ -99,12 +103,24 @@ module Rails end unless cookie_serializer_config_exist - gsub_file 'config/initializers/cookies_serializer.rb', /json/, 'marshal' + gsub_file 'config/initializers/cookies_serializer.rb', /json(?!,)/, 'marshal' end unless active_record_belongs_to_required_by_default_config_exist remove_file 'config/initializers/active_record_belongs_to_required_by_default.rb' end + + unless action_cable_config_exist + template 'config/cable.yml' + end + + unless ssl_options_exist + remove_file 'config/initializers/ssl_options.rb' + end + + unless rack_cors_config_exist + remove_file 'config/initializers/cors.rb' + end end def database_yml @@ -276,9 +292,9 @@ module Rails end end - def delete_app_views_if_api_option + def delete_application_layout_file_if_api_option if options[:api] - remove_dir 'app/views' + remove_file 'app/views/layouts/application.html.erb' end end @@ -317,7 +333,7 @@ module Rails def delete_action_cable_files_skipping_action_cable if options[:skip_action_cable] remove_file 'config/cable.yml' - remove_file 'app/assets/javascripts/cable.coffee' + remove_file 'app/assets/javascripts/cable.js' remove_dir 'app/channels' end end diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile index 3825dc4e38..e8ec214b28 100644 --- a/railties/lib/rails/generators/rails/app/templates/Gemfile +++ b/railties/lib/rails/generators/rails/app/templates/Gemfile @@ -26,7 +26,7 @@ source 'https://rubygems.org' <% if RUBY_ENGINE == 'ruby' -%> group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console - gem 'byebug' + gem 'byebug', platform: :mri end group :development do @@ -38,9 +38,15 @@ group :development do gem 'web-console', '~> 3.0' <%- end -%> <%- end -%> +<% if depend_on_listen? -%> + gem 'listen', '~> 3.0.5' +<% end -%> <% if spring_install? -%> # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring' +<% if depend_on_listen? -%> + gem 'spring-watcher-listen', '~> 2.0.0' +<% end -%> <% end -%> end <% end -%> diff --git a/railties/lib/rails/generators/rails/app/templates/README.md b/railties/lib/rails/generators/rails/app/templates/README.md index 55e144da18..7db80e4ca1 100644 --- a/railties/lib/rails/generators/rails/app/templates/README.md +++ b/railties/lib/rails/generators/rails/app/templates/README.md @@ -1,4 +1,4 @@ -## README +# README This README would normally document whatever steps are necessary to get the application up and running. diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/cable.coffee b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/cable.coffee deleted file mode 100644 index 07934d026f..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/cable.coffee +++ /dev/null @@ -1,11 +0,0 @@ -# Action Cable provides the framework to deal with WebSockets in Rails. -# You can generate new channels where WebSocket features live using the rails generate channel command. -# -# Turn on the cable connection by removing the comments after the require statements (and ensure it's also on in config/routes.rb). -# -#= require action_cable -#= require_self -#= require_tree ./channels -# -# @App ||= {} -# App.cable = ActionCable.createConsumer() diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/cable.js b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/cable.js new file mode 100644 index 0000000000..71ee1e66de --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/cable.js @@ -0,0 +1,13 @@ +// Action Cable provides the framework to deal with WebSockets in Rails. +// You can generate new channels where WebSocket features live using the rails generate channel command. +// +//= require action_cable +//= require_self +//= require_tree ./channels + +(function() { + this.App || (this.App = {}); + + App.cable = ActionCable.createConsumer(); + +}).call(this); 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 68b5c051b2..72258cc96b 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,16 +3,13 @@ <head> <title><%= camelized %></title> <%%= csrf_meta_tags %> - <%- unless options[:skip_action_cable] -%> - <%%= action_cable_meta_tag %> - <%- end -%> <%- if options[:skip_javascript] -%> <%%= stylesheet_link_tag 'application', media: 'all' %> <%- else -%> <%- if gemfile_entries.any? { |m| m.name == 'turbolinks' } -%> - <%%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %> - <%%= javascript_include_tag 'application', 'data-turbolinks-track' => true %> + <%%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => 'reload' %> + <%%= javascript_include_tag 'application', 'data-turbolinks-track' => 'reload' %> <%- else -%> <%%= stylesheet_link_tag 'application', media: 'all' %> <%%= javascript_include_tag 'application' %> diff --git a/railties/lib/rails/generators/rails/app/templates/bin/rails b/railties/lib/rails/generators/rails/app/templates/bin/rails index 80ec8080ab..513a2e0183 100644 --- a/railties/lib/rails/generators/rails/app/templates/bin/rails +++ b/railties/lib/rails/generators/rails/app/templates/bin/rails @@ -1,3 +1,3 @@ -APP_PATH = File.expand_path('../../config/application', __FILE__) +APP_PATH = File.expand_path('../config/application', __dir__) require_relative '../config/boot' require 'rails/commands' diff --git a/railties/lib/rails/generators/rails/app/templates/config.ru.tt b/railties/lib/rails/generators/rails/app/templates/config.ru index 343c0833d7..bd83b25412 100644 --- a/railties/lib/rails/generators/rails/app/templates/config.ru.tt +++ b/railties/lib/rails/generators/rails/app/templates/config.ru @@ -1,10 +1,4 @@ # This file is used by Rack-based servers to start the application. require ::File.expand_path('../config/environment', __FILE__) -<%- unless options[:skip_action_cable] -%> - -# Action Cable requires that all classes are loaded in advance -Rails.application.eager_load! -<%- end -%> - run Rails.application diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml index d51b2ec199..bd5c0b10f6 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml @@ -19,7 +19,7 @@ default: &default encoding: unicode # For details on connection pooling, see rails configuration guide # http://guides.rubyonrails.org/configuring.html#database-pooling - pool: 5 + pool: <%%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> development: <<: *default 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 fd41372d9c..7a537610e9 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt @@ -15,18 +15,22 @@ Rails.application.configure do # Enable/disable caching. By default caching is disabled. if Rails.root.join('tmp/caching-dev.txt').exist? config.action_controller.perform_caching = true + config.cache_store = :memory_store config.public_file_server.headers = { 'Cache-Control' => 'public, max-age=172800' } else config.action_controller.perform_caching = false + config.cache_store = :null_store end <%- unless options.skip_action_mailer? -%> # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false + + config.action_mailer.perform_caching = false <%- end -%> # Print deprecation notices to the Rails logger. @@ -42,15 +46,6 @@ Rails.application.configure do # This option may cause significant delays in view rendering with a large # number of complex assets. config.assets.debug = true - - # Asset digests allow you to set far-future HTTP expiration dates on all assets, - # yet still be able to expire them through the digest params. - config.assets.digest = true - - # Adds additional error checking when serving assets at runtime. - # Checks for improperly declared sprockets dependencies. - # Raises helpful error messages. - config.assets.raise_runtime_errors = true <%- end -%> # Raises error for missing translations @@ -58,5 +53,5 @@ Rails.application.configure do # Use an evented file watcher to asynchronously detect changes in source code, # routes, locales, etc. This feature depends on the listen gem. - # config.file_watcher = ActiveSupport::EventedFileUpdateChecker + <%= '# ' unless depend_on_listen? %>config.file_watcher = ActiveSupport::EventedFileUpdateChecker end 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 82509f5ef5..d2d0529d98 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 @@ -26,10 +26,6 @@ Rails.application.configure do # Do not fallback to assets pipeline if a precompiled asset is missed. config.assets.compile = false - # Asset digests allow you to set far-future HTTP expiration dates on all assets, - # yet still be able to expire them through the digest params. - config.assets.digest = true - # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb <%- end -%> @@ -44,6 +40,9 @@ Rails.application.configure do # Action Cable endpoint configuration # config.action_cable.url = 'wss://example.com/cable' # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] + + # Don't mount Action Cable in the main server process. + # config.action_cable.mount_path = nil <%- end -%> # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. @@ -60,6 +59,10 @@ Rails.application.configure do # require 'syslog/logger' # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') + if ENV["RAILS_LOG_TO_STDOUT"].present? + config.logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT)) + end + # Use a different cache store in production. # config.cache_store = :mem_cache_store @@ -67,6 +70,7 @@ Rails.application.configure do # config.active_job.queue_adapter = :resque # config.active_job.queue_name_prefix = "<%= app_name %>_#{Rails.env}" <%- unless options.skip_action_mailer? -%> + config.action_mailer.perform_caching = false # Ignore bad email addresses and do not raise email delivery errors. # Set this to true and configure the email server for immediate delivery to raise delivery errors. 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 8133917591..42fee3b036 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt @@ -28,6 +28,7 @@ Rails.application.configure do # Disable request forgery protection in test environment. config.action_controller.allow_forgery_protection = false <%- unless options.skip_action_mailer? -%> + config.action_mailer.perform_caching = false # Tell Action Mailer not to deliver emails to the real world. # The :test delivery method accumulates sent emails in the @@ -35,9 +36,6 @@ Rails.application.configure do config.action_mailer.delivery_method = :test <%- end -%> - # Randomize the order test cases are executed. - config.active_support.test_order = :random - # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/ssl_options.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/ssl_options.rb new file mode 100644 index 0000000000..1775dea1e7 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/ssl_options.rb @@ -0,0 +1,4 @@ +# Be sure to restart your server when you modify this file. + +# Configure SSL options to enable HSTS with subdomains. +Rails.application.config.ssl_options = { hsts: { subdomains: true } } diff --git a/railties/lib/rails/generators/rails/app/templates/config/puma.rb b/railties/lib/rails/generators/rails/app/templates/config/puma.rb index 1bf274bc66..c7f311f811 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/puma.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/puma.rb @@ -42,3 +42,6 @@ environment ENV.fetch("RAILS_ENV") { "development" } # 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/routes.rb b/railties/lib/rails/generators/rails/app/templates/config/routes.rb index 8293c8a483..787824f888 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/routes.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/routes.rb @@ -1,6 +1,3 @@ Rails.application.routes.draw do # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html - - # Serve websocket cable requests in-process - # mount ActionCable.server => '/cable' end diff --git a/railties/lib/rails/generators/rails/app/templates/config/spring.rb b/railties/lib/rails/generators/rails/app/templates/config/spring.rb new file mode 100644 index 0000000000..c9119b40c0 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/config/spring.rb @@ -0,0 +1,6 @@ +%w( + .ruby-version + .rbenv-vars + tmp/restart.txt + tmp/caching-dev.txt +).each { |path| Spring.watch(path) } diff --git a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb index b5e836b584..56efd35a95 100644 --- a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb +++ b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb @@ -90,6 +90,7 @@ task default: :test opts[:force] = force opts[:skip_bundle] = true opts[:api] = options.api? + opts[:skip_listen] = true invoke Rails::Generators::AppGenerator, [ File.expand_path(dummy_path, destination_root) ], opts @@ -287,10 +288,6 @@ task default: :test protected - def app_templates_dir - "../../app/templates" - end - def create_dummy_app(path = nil) dummy_path(path) if path 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 83807f14b4..abbacd9bec 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,6 +1,6 @@ <%= wrap_in_modules <<-rb.strip_heredoc class ApplicationController < ActionController::#{api? ? "API" : "Base"} - #{ api? ? '# ' : '' }protect_from_forgery :with => :exception + #{ api? ? '# ' : '' }protect_from_forgery with: :exception end rb %> diff --git a/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml b/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml index 2656767eb4..0681780c97 100644 --- a/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml +++ b/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml @@ -6,7 +6,7 @@ <%- if attribute.password_digest? -%> password_digest: <%%= BCrypt::Password.create('secret') %> <%- elsif attribute.reference? -%> - <%= yaml_key_value(attribute.column_name.sub(/_id$/, ''), attribute.default) %> + <%= yaml_key_value(attribute.column_name.sub(/_id$/, ''), attribute.default || name) %> <%- else -%> <%= yaml_key_value(attribute.column_name, attribute.default) %> <%- end -%> diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb index 8c24d1d56d..99dd571a00 100644 --- a/railties/lib/rails/railtie.rb +++ b/railties/lib/rails/railtie.rb @@ -183,7 +183,7 @@ module Rails end protected - def generate_railtie_name(string) + def generate_railtie_name(string) #:nodoc: ActiveSupport::Inflector.underscore(string).tr("/", "_") end @@ -200,21 +200,24 @@ module Rails delegate :railtie_name, to: :class - def initialize + def initialize #:nodoc: if self.class.abstract_railtie? raise "#{self.class.name} is abstract, you cannot instantiate it directly." end end - def configure(&block) + def configure(&block) #:nodoc: instance_eval(&block) end + # This is used to create the <tt>config</tt> object on Railties, an instance of + # Railtie::Configuration, that is used by Railties and Application to store + # related configuration. def config @config ||= Railtie::Configuration.new end - def railtie_namespace + def railtie_namespace #:nodoc: @railtie_namespace ||= self.class.parents.detect { |n| n.respond_to?(:railtie_namespace) } end diff --git a/railties/lib/rails/tasks.rb b/railties/lib/rails/tasks.rb index d60eaf6f4f..d3e33584d7 100644 --- a/railties/lib/rails/tasks.rb +++ b/railties/lib/rails/tasks.rb @@ -3,6 +3,7 @@ require 'rake' # Load Rails Rakefile extensions %w( annotations + dev framework initializers log diff --git a/railties/lib/rails/tasks/dev.rake b/railties/lib/rails/tasks/dev.rake new file mode 100644 index 0000000000..ff2de264ce --- /dev/null +++ b/railties/lib/rails/tasks/dev.rake @@ -0,0 +1,16 @@ +namespace :dev do + desc 'Toggle development mode caching on/off' + task :cache do + FileUtils.mkdir_p('tmp') + + if File.exist? 'tmp/caching-dev.txt' + File.delete 'tmp/caching-dev.txt' + puts 'Development mode is no longer being cached.' + else + FileUtils.touch 'tmp/caching-dev.txt' + puts 'Development mode is now being cached.' + end + + FileUtils.touch 'tmp/restart.txt' + end +end diff --git a/railties/lib/rails/tasks/framework.rake b/railties/lib/rails/tasks/framework.rake index 7601836809..bf25b74627 100644 --- a/railties/lib/rails/tasks/framework.rake +++ b/railties/lib/rails/tasks/framework.rake @@ -1,4 +1,6 @@ -namespace :rails do +require 'active_support/deprecation' + +namespace :app do desc "Update configs and some other initially generated files (or use just update:configs or update:bin)" task update: [ "update:configs", "update:bin" ] @@ -66,3 +68,15 @@ namespace :rails do end end end + +namespace :rails do + %i(update template templates:copy update:configs update:bin).each do |task_name| + task "#{task_name}" do + ActiveSupport::Deprecation.warn(<<-MSG.squish) + Running #{task_name} with the rails: namespace is deprecated in favor of app: namespace. + Run bin/rails app:#{task_name} instead. + MSG + Rake.application.invoke_task("app:#{task_name}") + end + end +end diff --git a/railties/lib/rails/tasks/routes.rake b/railties/lib/rails/tasks/routes.rake index 939fa59c75..69103aa5d9 100644 --- a/railties/lib/rails/tasks/routes.rake +++ b/railties/lib/rails/tasks/routes.rake @@ -2,7 +2,7 @@ require 'active_support/deprecation' require 'active_support/core_ext/string/strip' # for strip_heredoc require 'optparse' -desc 'Print out all defined routes in match order, with names. Target specific controller with --controller option - or its -c shorthand.' +desc 'Print out all defined routes in match order, with names. Target specific controller with -c option, or grep routes using -g option' task routes: :environment do all_routes = Rails.application.routes.routes require 'action_dispatch/routing/inspector' @@ -19,11 +19,11 @@ task routes: :environment do OptionParser.new do |opts| opts.banner = "Usage: rails routes [options]" - opts.on("-c", "--controller [CONTROLLER]") do |controller| + opts.on("-c CONTROLLER") do |controller| routes_filter = { controller: controller } end - opts.on("-g", "--grep [PATTERN]") do |pattern| + opts.on("-g PATTERN") do |pattern| routes_filter = pattern end diff --git a/railties/lib/rails/test_unit/minitest_plugin.rb b/railties/lib/rails/test_unit/minitest_plugin.rb index 29a3d991b8..f22139490b 100644 --- a/railties/lib/rails/test_unit/minitest_plugin.rb +++ b/railties/lib/rails/test_unit/minitest_plugin.rb @@ -1,6 +1,7 @@ require "active_support/core_ext/module/attribute_accessors" require "rails/test_unit/reporter" require "rails/test_unit/test_requirer" +require 'shellwords' module Minitest class SuppressedSummaryReporter < SummaryReporter @@ -42,7 +43,7 @@ module Minitest end opts.on("-f", "--fail-fast", - "Abort test run on first failure") do + "Abort test run on first failure or error") do options[:fail_fast] = true end @@ -60,11 +61,13 @@ module Minitest # as the patterns would also contain the other Rake tasks. def self.rake_run(patterns) # :nodoc: @rake_patterns = patterns - passed = run + passed = run(Shellwords.split(ENV['TESTOPTS'] || '')) exit passed unless passed passed end + # Owes great inspiration to test runner trailblazers like RSpec, + # minitest-reporters, maxitest and others. def self.plugin_rails_init(options) self.run_with_rails_extension = true diff --git a/railties/lib/rails/test_unit/reporter.rb b/railties/lib/rails/test_unit/reporter.rb index 73b8d7d27b..4086d5b731 100644 --- a/railties/lib/rails/test_unit/reporter.rb +++ b/railties/lib/rails/test_unit/reporter.rb @@ -18,13 +18,13 @@ module Rails if output_inline? && result.failure && (!result.skipped? || options[:verbose]) io.puts io.puts - io.puts format_failures(result).map { |line| color_output(line, by: result) } + io.puts color_output(result, by: result) io.puts io.puts format_rerun_snippet(result) io.puts end - if fail_fast? && result.failure && !result.error? && !result.skipped? + if fail_fast? && result.failure && !result.skipped? raise Interrupt end end @@ -66,21 +66,9 @@ module Rails "%s#%s = %.2f s = %s" % [result.class, result.name, result.time, result.result_code] end - def format_failures(result) - result.failures.map do |failure| - "#{failure.result_label}:\n#{result.class}##{result.name}:\n#{failure.message}\n" - end - end - def format_rerun_snippet(result) - # Try to extract path to assertion from backtrace. - if result.location =~ /\[(.*)\]\z/ - assertion_path = $1 - else - assertion_path = result.method(result.name).source_location.join(':') - end - - "#{self.executable} #{relative_path_for(assertion_path)}" + location, line = result.method(result.name).source_location + "#{self.executable} #{relative_path_for(location)}:#{line}" end def app_root diff --git a/railties/test/abstract_unit.rb b/railties/test/abstract_unit.rb index 794d180e5d..2a5a731fe2 100644 --- a/railties/test/abstract_unit.rb +++ b/railties/test/abstract_unit.rb @@ -1,7 +1,5 @@ ENV["RAILS_ENV"] ||= "test" -require File.expand_path("../../../load_paths", __FILE__) - require 'stringio' require 'active_support/testing/autorun' require 'active_support/testing/stream' diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb index 2670fad618..11e19eec80 100644 --- a/railties/test/application/assets_test.rb +++ b/railties/test/application/assets_test.rb @@ -186,6 +186,26 @@ module ApplicationTests assert_file_exists("#{app_path}/public/assets/something-*.js") end + test 'sprockets cache is not shared between environments' do + app_file "app/assets/images/rails.png", "notactuallyapng" + app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>" + add_to_env_config 'production', 'config.assets.prefix = "production_assets"' + + precompile! + + assert_file_exists("#{app_path}/public/assets/application-*.css") + + file = Dir["#{app_path}/public/assets/application-*.css"].first + assert_match(/assets\/rails-([0-z]+)\.png/, File.read(file)) + + precompile! RAILS_ENV: 'production' + + assert_file_exists("#{app_path}/public/production_assets/application-*.css") + + file = Dir["#{app_path}/public/production_assets/application-*.css"].first + assert_match(/production_assets\/rails-([0-z]+)\.png/, File.read(file)) + end + test 'precompile use assets defined in app config and reassigned in app env config' do add_to_config 'config.assets.precompile = [ "something_manifest.js" ]' add_to_env_config 'production', 'config.assets.precompile += [ "another_manifest.js" ]' diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index 7bcfc86d03..d03dd1afcc 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -348,6 +348,17 @@ module ApplicationTests end end + test "In production mode, STDOUT logging is enabled when RAILS_LOG_TO_STDOUT is set" do + restore_default_config + + with_rails_env "production" do + switch_env "RAILS_LOG_TO_STDOUT", "1" do + app 'production' + assert ActiveSupport::Logger.logger_outputs_to?(app.config.logger, STDOUT) + end + end + end + test "In production mode, config.public_file_server.enabled is disabled when RAILS_SERVE_STATIC_FILES is blank" do restore_default_config @@ -988,7 +999,7 @@ module ApplicationTests app 'development' post "/posts.json", '{ "title": "foo", "name": "bar" }', "CONTENT_TYPE" => "application/json" - assert_equal '{"title"=>"foo"}', last_response.body + assert_equal '<ActionController::Parameters {"title"=>"foo"} permitted: false>', last_response.body end test "config.action_controller.permit_all_parameters = true" do @@ -1444,7 +1455,7 @@ module ApplicationTests assert Rails.configuration.api_only end - test "debug_exception_response_format is :api by default if only_api is enabled" do + test "debug_exception_response_format is :api by default if api_only is enabled" do add_to_config <<-RUBY config.api_only = true RUBY diff --git a/railties/test/application/console_test.rb b/railties/test/application/console_test.rb index 7bf123d12b..ea68e63f8f 100644 --- a/railties/test/application/console_test.rb +++ b/railties/test/application/console_test.rb @@ -52,12 +52,11 @@ class ConsoleTest < ActiveSupport::TestCase a = b = c = nil # TODO: These should be defined on the initializer - ActionDispatch::Reloader.to_cleanup { a = b = c = 1 } - ActionDispatch::Reloader.to_cleanup { b = c = 2 } - ActionDispatch::Reloader.to_prepare { c = 3 } + ActiveSupport::Reloader.to_complete { a = b = c = 1 } + ActiveSupport::Reloader.to_complete { b = c = 2 } + ActiveSupport::Reloader.to_prepare { c = 3 } - # Hide Reloading... output - silence_stream(STDOUT) { irb_context.reload! } + irb_context.reload!(false) assert_equal 1, a assert_equal 2, b @@ -81,7 +80,7 @@ class ConsoleTest < ActiveSupport::TestCase MODEL assert !User.new.respond_to?(:age) - silence_stream(STDOUT) { irb_context.reload! } + irb_context.reload!(false) assert User.new.respond_to?(:age) end diff --git a/railties/test/application/generators_test.rb b/railties/test/application/generators_test.rb index 84cc6e120b..644af0e737 100644 --- a/railties/test/application/generators_test.rb +++ b/railties/test/application/generators_test.rb @@ -160,5 +160,15 @@ module ApplicationTests assert Rails::Generators.options[:rails][:helper] assert_equal :my_template, Rails::Generators.options[:rails][:template_engine] end + + test "api only generator generate mailer views" do + add_to_config <<-RUBY + config.api_only = true + RUBY + + FileUtils.cd(rails_root){ `bin/rails generate mailer notifier foo` } + assert File.exist?(File.join(rails_root, "app/views/notifier_mailer/foo.text.erb")) + assert File.exist?(File.join(rails_root, "app/views/notifier_mailer/foo.html.erb")) + end end end diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb index 4c06b6324c..44209a52f7 100644 --- a/railties/test/application/initializers/frameworks_test.rb +++ b/railties/test/application/initializers/frameworks_test.rb @@ -16,7 +16,7 @@ module ApplicationTests # AC & AM test "set load paths set only if action controller or action mailer are in use" do - assert_nothing_raised NameError do + assert_nothing_raised do add_to_config <<-RUBY config.root = "#{app_path}" RUBY diff --git a/railties/test/application/integration_test_case_test.rb b/railties/test/application/integration_test_case_test.rb new file mode 100644 index 0000000000..d106d5159a --- /dev/null +++ b/railties/test/application/integration_test_case_test.rb @@ -0,0 +1,46 @@ +require 'isolation/abstract_unit' + +module ApplicationTests + class IntegrationTestCaseTest < ActiveSupport::TestCase + include ActiveSupport::Testing::Isolation + + setup do + build_app + boot_rails + end + + teardown do + teardown_app + end + + test "resets Action Mailer test deliveries" do + script('generate mailer BaseMailer welcome') + + app_file 'test/integration/mailer_integration_test.rb', <<-RUBY + require 'test_helper' + + class MailerIntegrationTest < ActionDispatch::IntegrationTest + setup do + @old_delivery_method = ActionMailer::Base.delivery_method + ActionMailer::Base.delivery_method = :test + end + + teardown do + ActionMailer::Base.delivery_method = @old_delivery_method + end + + 2.times do |i| + define_method "test_resets_deliveries_\#{i}" do + BaseMailer.welcome.deliver_now + assert_equal 1, ActionMailer::Base.deliveries.count + end + end + end + RUBY + + output = Dir.chdir(app_path) { `bin/rails test 2>&1` } + assert_equal 0, $?.to_i, output + assert_match(/0 failures, 0 errors/, output) + end + end +end diff --git a/railties/test/application/loading_test.rb b/railties/test/application/loading_test.rb index 40abaf860d..efb21ae473 100644 --- a/railties/test/application/loading_test.rb +++ b/railties/test/application/loading_test.rb @@ -56,10 +56,10 @@ class LoadingTest < ActiveSupport::TestCase require "#{rails_root}/config/environment" - assert_nothing_raised(NameError) { Trackable } - assert_nothing_raised(NameError) { EmailLoggable } - assert_nothing_raised(NameError) { Orderable } - assert_nothing_raised(NameError) { Matchable } + assert_nothing_raised { Trackable } + assert_nothing_raised { EmailLoggable } + assert_nothing_raised { Orderable } + assert_nothing_raised { Matchable } end test "models without table do not panic on scope definitions when loaded" do diff --git a/railties/test/application/middleware/exceptions_test.rb b/railties/test/application/middleware/exceptions_test.rb index 7b4babb13b..639b01b562 100644 --- a/railties/test/application/middleware/exceptions_test.rb +++ b/railties/test/application/middleware/exceptions_test.rb @@ -85,7 +85,7 @@ module ApplicationTests test "unspecified route when action_dispatch.show_exceptions is set shows 404" do app.config.action_dispatch.show_exceptions = true - assert_nothing_raised(ActionController::RoutingError) do + assert_nothing_raised do get '/foo' assert_match "The page you were looking for doesn't exist.", last_response.body end @@ -95,7 +95,7 @@ module ApplicationTests app.config.action_dispatch.show_exceptions = true app.config.consider_all_requests_local = true - assert_nothing_raised(ActionController::RoutingError) do + assert_nothing_raised do get '/foo' assert_match "No route matches", last_response.body end diff --git a/railties/test/application/middleware/remote_ip_test.rb b/railties/test/application/middleware/remote_ip_test.rb index 97d5b5c698..37bd8a25c1 100644 --- a/railties/test/application/middleware/remote_ip_test.rb +++ b/railties/test/application/middleware/remote_ip_test.rb @@ -36,10 +36,10 @@ module ApplicationTests test "works with both headers individually" do make_basic_app - assert_nothing_raised(ActionDispatch::RemoteIp::IpSpoofAttackError) do + assert_nothing_raised do assert_equal "1.1.1.1", remote_ip("HTTP_X_FORWARDED_FOR" => "1.1.1.1") end - assert_nothing_raised(ActionDispatch::RemoteIp::IpSpoofAttackError) do + assert_nothing_raised do assert_equal "1.1.1.2", remote_ip("HTTP_CLIENT_IP" => "1.1.1.2") end end @@ -49,7 +49,7 @@ module ApplicationTests app.config.action_dispatch.ip_spoofing_check = false end - assert_nothing_raised(ActionDispatch::RemoteIp::IpSpoofAttackError) do + assert_nothing_raised do assert_equal "1.1.1.1", remote_ip("HTTP_X_FORWARDED_FOR" => "1.1.1.1", "HTTP_CLIENT_IP" => "1.1.1.2") end end diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb index 1434522cce..5869ff64bc 100644 --- a/railties/test/application/middleware_test.rb +++ b/railties/test/application/middleware_test.rb @@ -26,7 +26,7 @@ module ApplicationTests assert_equal [ "Rack::Sendfile", "ActionDispatch::Static", - "ActionDispatch::LoadInterlock", + "ActionDispatch::Executor", "ActiveSupport::Cache::Strategy::LocalCache", "Rack::Runtime", "Rack::MethodOverride", @@ -38,8 +38,6 @@ module ApplicationTests "ActionDispatch::Reloader", "ActionDispatch::Callbacks", "ActiveRecord::Migration::CheckPending", - "ActiveRecord::ConnectionAdapters::ConnectionManagement", - "ActiveRecord::QueryCache", "ActionDispatch::Cookies", "ActionDispatch::Session::CookieStore", "ActionDispatch::Flash", @@ -57,7 +55,7 @@ module ApplicationTests assert_equal [ "Rack::Sendfile", "ActionDispatch::Static", - "ActionDispatch::LoadInterlock", + "ActionDispatch::Executor", "ActiveSupport::Cache::Strategy::LocalCache", "Rack::Runtime", "ActionDispatch::RequestId", @@ -67,8 +65,6 @@ module ApplicationTests "ActionDispatch::RemoteIp", "ActionDispatch::Reloader", "ActionDispatch::Callbacks", - "ActiveRecord::ConnectionAdapters::ConnectionManagement", - "ActiveRecord::QueryCache", "Rack::Head", "Rack::ConditionalGet", "Rack::ETag" @@ -114,23 +110,12 @@ module ApplicationTests test "removing Active Record omits its middleware" do use_frameworks [] boot! - assert !middleware.include?("ActiveRecord::ConnectionAdapters::ConnectionManagement") - assert !middleware.include?("ActiveRecord::QueryCache") assert !middleware.include?("ActiveRecord::Migration::CheckPending") end - test "includes interlock if cache_classes is set but eager_load is not" do - add_to_config "config.cache_classes = true" - boot! - assert_not_includes middleware, "Rack::Lock" - assert_includes middleware, "ActionDispatch::LoadInterlock" - end - - test "includes interlock if cache_classes is off" do - add_to_config "config.cache_classes = false" + test "includes executor" do boot! - assert_not_includes middleware, "Rack::Lock" - assert_includes middleware, "ActionDispatch::LoadInterlock" + assert_includes middleware, "ActionDispatch::Executor" end test "does not include lock if cache_classes is set and so is eager_load" do @@ -138,21 +123,18 @@ module ApplicationTests add_to_config "config.eager_load = true" boot! assert_not_includes middleware, "Rack::Lock" - assert_not_includes middleware, "ActionDispatch::LoadInterlock" end test "does not include lock if allow_concurrency is set to :unsafe" do add_to_config "config.allow_concurrency = :unsafe" boot! assert_not_includes middleware, "Rack::Lock" - assert_not_includes middleware, "ActionDispatch::LoadInterlock" end test "includes lock if allow_concurrency is disabled" do add_to_config "config.allow_concurrency = false" boot! assert_includes middleware, "Rack::Lock" - assert_not_includes middleware, "ActionDispatch::LoadInterlock" end test "removes static asset server if public_file_server.enabled is disabled" do diff --git a/railties/test/application/per_request_digest_cache_test.rb b/railties/test/application/per_request_digest_cache_test.rb index 3198e12662..dfe3fc9354 100644 --- a/railties/test/application/per_request_digest_cache_test.rb +++ b/railties/test/application/per_request_digest_cache_test.rb @@ -29,6 +29,8 @@ class PerRequestDigestCacheTest < ActiveSupport::TestCase app_file 'app/controllers/customers_controller.rb', <<-RUBY class CustomersController < ApplicationController + self.perform_caching = true + def index render [ Customer.new('david', 1), Customer.new('dingus', 2) ] end @@ -50,12 +52,13 @@ class PerRequestDigestCacheTest < ActiveSupport::TestCase get '/customers' assert_equal 200, last_response.status - assert_equal [ '8ba099b7749542fe765ff34a6824d548' ], ActionView::Digestor.cache.values + values = ActionView::LookupContext::DetailsKey.digest_caches.first.values + assert_equal [ '8ba099b7749542fe765ff34a6824d548' ], values assert_equal %w(david dingus), last_response.body.split.map(&:strip) end test "template digests are cleared before a request" do - assert_called(ActionView::Digestor.cache, :clear) do + assert_called(ActionView::LookupContext::DetailsKey, :clear) do get '/customers' assert_equal 200, last_response.status end diff --git a/railties/test/application/rake/dev_test.rb b/railties/test/application/rake/dev_test.rb new file mode 100644 index 0000000000..59b46c6e79 --- /dev/null +++ b/railties/test/application/rake/dev_test.rb @@ -0,0 +1,34 @@ +require 'isolation/abstract_unit' + +module ApplicationTests + module RakeTests + class RakeDevTest < ActiveSupport::TestCase + include ActiveSupport::Testing::Isolation + + def setup + build_app + end + + def teardown + teardown_app + end + + test 'dev:cache creates file and outputs message' do + Dir.chdir(app_path) do + output = `rails dev:cache` + assert File.exist?('tmp/caching-dev.txt') + assert_match(/Development mode is now being cached/, output) + end + end + + test 'dev:cache deletes file and outputs message' do + Dir.chdir(app_path) do + `rails dev:cache` # Create caching file. + output = `rails dev:cache` # Delete caching file. + assert_not File.exist?('tmp/caching-dev.txt') + assert_match(/Development mode is no longer being cached/, output) + end + end + end + end +end diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb index 745a3e3ec5..1a786a3fd3 100644 --- a/railties/test/application/rake_test.rb +++ b/railties/test/application/rake_test.rb @@ -24,7 +24,7 @@ module ApplicationTests assert $task_loaded end - def test_the_test_rake_task_is_protected_when_previous_migration_was_production + test "task is protected when previous migration was production" do Dir.chdir(app_path) do output = `bin/rails generate model product name:string; env RAILS_ENV=production bin/rails db:create db:migrate; @@ -118,11 +118,11 @@ module ApplicationTests end def test_code_statistics_sanity - assert_match "Code LOC: 14 Test LOC: 0 Code to Test Ratio: 1:0.0", + assert_match "Code LOC: 18 Test LOC: 0 Code to Test Ratio: 1:0.0", Dir.chdir(app_path){ `bin/rails stats` } end - def test_rake_routes_calls_the_route_inspector + def test_rails_routes_calls_the_route_inspector app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get '/cart', to: 'cart#show' @@ -133,7 +133,7 @@ module ApplicationTests assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output end - def test_rake_routes_with_controller_environment + def test_rails_routes_with_controller_environment app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get '/cart', to: 'cart#show' @@ -151,7 +151,7 @@ module ApplicationTests assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output end - def test_rake_routes_with_namespaced_controller_environment + def test_rails_routes_with_namespaced_controller_environment app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do namespace :admin do @@ -175,19 +175,27 @@ module ApplicationTests assert_equal expected_output, output end - def test_rake_routes_with_global_search_key + def test_rails_routes_with_global_search_key app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get '/cart', to: 'cart#show' - get '/basketball', to: 'basketball#index' + post '/cart', to: 'cart#create' + get '/basketballs', to: 'basketball#index' end 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 + + 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 + + output = Dir.chdir(app_path){ `bin/rails routes -g basketballs` } + assert_equal " Prefix Verb URI Pattern Controller#Action\n" \ + "basketballs GET /basketballs(.:format) basketball#index\n", output end - def test_rake_routes_with_controller_search_key + def test_rails_routes_with_controller_search_key app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get '/cart', to: 'cart#show' @@ -205,7 +213,7 @@ module ApplicationTests assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output end - def test_rake_routes_displays_message_when_no_routes_are_defined + def test_rails_routes_displays_message_when_no_routes_are_defined app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do end @@ -291,12 +299,11 @@ module ApplicationTests assert_no_match(/Errors running/, output) end - def test_scaffold_with_references_columns_tests_pass_when_belongs_to_is_optional - app_file "config/initializers/active_record_belongs_to_required_by_default.rb", - "Rails.application.config.active_record.belongs_to_required_by_default = false" - + def test_scaffold_with_references_columns_tests_pass_by_default output = Dir.chdir(app_path) do - `bin/rails generate scaffold LineItems product:references cart:belongs_to; + `bin/rails generate model Product; + bin/rails generate model Cart; + bin/rails generate scaffold LineItems product:references cart:belongs_to; RAILS_ENV=test bin/rails db:migrate test` end @@ -362,7 +369,7 @@ module ApplicationTests def test_copy_templates Dir.chdir(app_path) do - `bin/rails rails:templates:copy` + `bin/rails app:templates:copy` %w(controller mailer scaffold).each do |dir| assert File.exist?(File.join(app_path, 'lib', 'templates', 'erb', dir)) end @@ -377,7 +384,7 @@ module ApplicationTests app_file "template.rb", "" output = Dir.chdir(app_path) do - `bin/rails rails:template LOCATION=template.rb` + `bin/rails app:template LOCATION=template.rb` end assert_match(/Hello, World!/, output) diff --git a/railties/test/application/test_runner_test.rb b/railties/test/application/test_runner_test.rb index 7ecadb60ca..a1735db5b3 100644 --- a/railties/test/application/test_runner_test.rb +++ b/railties/test/application/test_runner_test.rb @@ -467,7 +467,7 @@ module ApplicationTests create_test_file :models, 'post', pass: false output = run_test_command('test/models/post_test.rb') - expect = %r{Running:\n\nPostTest\nF\n\nFailure:\nPostTest#test_truth:\nwups!\n\nbin/rails test test/models/post_test.rb:6\n\n\n\n} + expect = %r{Running:\n\nPostTest\nF\n\nFailure:\nPostTest#test_truth \[[^\]]+test/models/post_test.rb:6\]:\nwups!\n\nbin/rails test test/models/post_test.rb:4\n\n\n\n} assert_match expect, output end @@ -502,6 +502,32 @@ module ApplicationTests assert_match '1 runs, 1 assertions', output end + def test_rails_db_create_all_restores_db_connection + create_test_file :models, 'account' + output = Dir.chdir(app_path) { `bin/rails db:create:all db:migrate && echo ".tables" | rails dbconsole` } + assert_match "ar_internal_metadata", output, "tables should be dumped" + end + + def test_rails_db_create_all_restores_db_connection_after_drop + create_test_file :models, 'account' + Dir.chdir(app_path) { `bin/rails db:create:all` } # create all to avoid warnings + output = Dir.chdir(app_path) { `bin/rails db:drop:all db:create:all db:migrate && echo ".tables" | rails dbconsole` } + assert_match "ar_internal_metadata", output, "tables should be dumped" + end + + def test_rake_passes_TESTOPTS_to_minitest + create_test_file :models, 'account' + output = Dir.chdir(app_path) { `bin/rake test TESTOPTS=-v` } + assert_match "AccountTest#test_truth", output, "passing TEST= should run selected test" + end + + def test_rake_passes_multiple_TESTOPTS_to_minitest + create_test_file :models, 'account' + output = Dir.chdir(app_path) { `bin/rake test TESTOPTS='-v --seed=1234'` } + assert_match "AccountTest#test_truth", output, "passing TEST= should run selected test" + assert_match "seed=1234", output, "passing TEST= should run selected test" + end + private def run_test_command(arguments = 'test/unit/test_test.rb') Dir.chdir(app_path) { `bin/rails t #{arguments}` } diff --git a/railties/test/commands/dev_cache_test.rb b/railties/test/commands/dev_cache_test.rb deleted file mode 100644 index 1b7a72e7fc..0000000000 --- a/railties/test/commands/dev_cache_test.rb +++ /dev/null @@ -1,32 +0,0 @@ -require_relative '../isolation/abstract_unit' - -module CommandsTests - class DevCacheTest < ActiveSupport::TestCase - include ActiveSupport::Testing::Isolation - - def setup - build_app - end - - def teardown - teardown_app - end - - test 'dev:cache creates file and outputs message' do - Dir.chdir(app_path) do - output = `rails dev:cache` - assert File.exist?('tmp/caching-dev.txt') - assert_match(%r{Development mode is now being cached}, output) - end - end - - test 'dev:cache deletes file and outputs message' do - Dir.chdir(app_path) do - `rails dev:cache` # Create caching file. - output = `rails dev:cache` # Delete caching file. - assert_not File.exist?('tmp/caching-dev.txt') - assert_match(%r{Development mode is no longer being cached}, output) - end - end - end -end diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb index 3300850604..58394a11f0 100644 --- a/railties/test/generators/actions_test.rb +++ b/railties/test/generators/actions_test.rb @@ -201,44 +201,82 @@ class ActionsTest < Rails::Generators::TestCase end end - def test_rake_should_run_rake_command_with_default_env - assert_called_with(generator, :run, ["rake log:clear RAILS_ENV=development", verbose: false]) do + def test_rails_should_run_rake_command_with_default_env + assert_called_with(generator, :run, ["rails log:clear RAILS_ENV=development", verbose: false]) do with_rails_env nil do action :rake, 'log:clear' end end end - def test_rake_with_env_option_should_run_rake_command_in_env - assert_called_with(generator, :run, ['rake log:clear RAILS_ENV=production', verbose: false]) do + def test_rails_with_env_option_should_run_rake_command_in_env + assert_called_with(generator, :run, ['rails log:clear RAILS_ENV=production', verbose: false]) do action :rake, 'log:clear', env: 'production' end end - def test_rake_with_rails_env_variable_should_run_rake_command_in_env - assert_called_with(generator, :run, ['rake log:clear RAILS_ENV=production', verbose: false]) do + test "rails command with RAILS_ENV variable should run rake command in env" do + assert_called_with(generator, :run, ['rails log:clear RAILS_ENV=production', verbose: false]) do with_rails_env "production" do action :rake, 'log:clear' end end end - def test_env_option_should_win_over_rails_env_variable_when_running_rake - assert_called_with(generator, :run, ['rake log:clear RAILS_ENV=production', verbose: false]) do + test "env option should win over RAILS_ENV variable when running rake" do + assert_called_with(generator, :run, ['rails log:clear RAILS_ENV=production', verbose: false]) do with_rails_env "staging" do action :rake, 'log:clear', env: 'production' end end end - def test_rake_with_sudo_option_should_run_rake_command_with_sudo - assert_called_with(generator, :run, ["sudo rake log:clear RAILS_ENV=development", verbose: false]) do + test "rails command with sudo option should run rake command with sudo" do + assert_called_with(generator, :run, ["sudo rails log:clear RAILS_ENV=development", verbose: false]) do with_rails_env nil do action :rake, 'log:clear', sudo: true end end end + test "rails command should run rails_command with default env" do + assert_called_with(generator, :run, ["rails log:clear RAILS_ENV=development", verbose: false]) do + with_rails_env nil do + action :rails_command, 'log:clear' + end + end + end + + test "rails command with env option should run rails_command with same env" do + assert_called_with(generator, :run, ['rails log:clear RAILS_ENV=production', verbose: false]) do + action :rails_command, 'log:clear', env: 'production' + end + end + + test "rails command with RAILS_ENV variable should run rails_command in env" do + assert_called_with(generator, :run, ['rails log:clear RAILS_ENV=production', verbose: false]) do + with_rails_env "production" do + action :rails_command, 'log:clear' + end + end + end + + def test_env_option_should_win_over_rails_env_variable_when_running_rails + assert_called_with(generator, :run, ['rails log:clear RAILS_ENV=production', verbose: false]) do + with_rails_env "staging" do + action :rails_command, 'log:clear', env: 'production' + end + end + end + + test "rails command with sudo option should run rails_command with sudo" do + assert_called_with(generator, :run, ["sudo rails log:clear RAILS_ENV=development", verbose: false]) do + with_rails_env nil do + action :rails_command, 'log:clear', sudo: true + end + end + end + def test_capify_should_run_the_capify_command assert_called_with(generator, :run, ['capify .', verbose: false]) do action :capify! diff --git a/railties/test/generators/api_app_generator_test.rb b/railties/test/generators/api_app_generator_test.rb index 1ea5661006..8e1cd0891a 100644 --- a/railties/test/generators/api_app_generator_test.rb +++ b/railties/test/generators/api_app_generator_test.rb @@ -73,6 +73,8 @@ class ApiAppGeneratorTest < Rails::Generators::TestCase app/controllers app/mailers app/models + app/views/layouts/mailer.html.erb + app/views/layouts/mailer.text.erb config/environments config/initializers config/locales @@ -94,7 +96,7 @@ class ApiAppGeneratorTest < Rails::Generators::TestCase def skipped_files %w(app/assets app/helpers - app/views + app/views/layouts/application.html.erb config/initializers/assets.rb config/initializers/cookies_serializer.rb config/initializers/session_store.rb diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index f483a0bcbd..2cbce4bc5e 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -28,6 +28,7 @@ DEFAULT_APP_FILES = %w( config/locales config/cable.yml config/puma.rb + config/spring.rb db lib lib/tasks @@ -64,8 +65,8 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_assets run_generator - assert_file("app/views/layouts/application.html.erb", /stylesheet_link_tag\s+'application', media: 'all', 'data-turbolinks-track' => true/) - assert_file("app/views/layouts/application.html.erb", /javascript_include_tag\s+'application', 'data-turbolinks-track' => true/) + assert_file("app/views/layouts/application.html.erb", /stylesheet_link_tag\s+'application', media: 'all', 'data-turbolinks-track' => 'reload'/) + assert_file("app/views/layouts/application.html.erb", /javascript_include_tag\s+'application', 'data-turbolinks-track' => 'reload'/) assert_file("app/assets/stylesheets/application.css") assert_file("app/assets/javascripts/application.js") end @@ -199,7 +200,7 @@ class AppGeneratorTest < Rails::Generators::TestCase end end - def test_rails_update_set_the_cookie_serializer_to_marchal_if_it_is_not_already_configured + def test_rails_update_set_the_cookie_serializer_to_marshal_if_it_is_not_already_configured app_root = File.join(destination_root, 'myapp') run_generator [app_root] @@ -209,7 +210,8 @@ class AppGeneratorTest < Rails::Generators::TestCase generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: app_root, shell: @shell generator.send(:app_const) quietly { generator.send(:update_config_files) } - assert_file("#{app_root}/config/initializers/cookies_serializer.rb", /Rails\.application\.config\.action_dispatch\.cookies_serializer = :marshal/) + assert_file("#{app_root}/config/initializers/cookies_serializer.rb", + /Valid options are :json, :marshal, and :hybrid\.\nRails\.application\.config\.action_dispatch\.cookies_serializer = :marshal/) end end @@ -241,6 +243,60 @@ class AppGeneratorTest < Rails::Generators::TestCase end end + def test_rails_update_does_not_create_ssl_options_by_default + app_root = File.join(destination_root, 'myapp') + run_generator [app_root] + + FileUtils.rm("#{app_root}/config/initializers/ssl_options.rb") + + stub_rails_application(app_root) do + generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: app_root, shell: @shell + generator.send(:app_const) + quietly { generator.send(:update_config_files) } + assert_no_file "#{app_root}/config/initializers/ssl_options.rb" + end + end + + def test_rails_update_does_not_remove_ssl_options_if_already_present + app_root = File.join(destination_root, 'myapp') + run_generator [app_root] + + FileUtils.touch("#{app_root}/config/initializers/ssl_options.rb") + + stub_rails_application(app_root) do + generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: app_root, shell: @shell + generator.send(:app_const) + quietly { generator.send(:update_config_files) } + assert_file "#{app_root}/config/initializers/ssl_options.rb" + end + end + + def test_rails_update_does_not_create_rack_cors + app_root = File.join(destination_root, 'myapp') + run_generator [app_root] + + stub_rails_application(app_root) do + generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: app_root, shell: @shell + generator.send(:app_const) + quietly { generator.send(:update_config_files) } + assert_no_file "#{app_root}/config/initializers/cors.rb" + end + end + + def test_rails_update_does_not_remove_rack_cors_if_already_present + app_root = File.join(destination_root, 'myapp') + run_generator [app_root] + + FileUtils.touch("#{app_root}/config/initializers/cors.rb") + + stub_rails_application(app_root) do + generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: app_root, shell: @shell + generator.send(:app_const) + quietly { generator.send(:update_config_files) } + assert_file "#{app_root}/config/initializers/cors.rb" + 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!/ @@ -338,6 +394,11 @@ class AppGeneratorTest < Rails::Generators::TestCase end end + def test_generator_defaults_to_puma_version + run_generator [destination_root] + assert_gem "puma", "'~> 3.0'" + end + def test_generator_if_skip_puma_is_given run_generator [destination_root, "--skip-puma"] assert_no_file "config/puma.rb" @@ -404,11 +465,8 @@ class AppGeneratorTest < Rails::Generators::TestCase run_generator [destination_root, "--skip-action-cable"] assert_file "config/application.rb", /#\s+require\s+["']action_cable\/engine["']/ assert_no_file "config/cable.yml" - assert_no_file "app/assets/javascripts/cable.coffee" + assert_no_file "app/assets/javascripts/cable.js" assert_no_file "app/channels" - assert_file "app/views/layouts/application.html.erb" do |content| - assert_no_match(/action_cable_meta_tag/, content) - end assert_file "Gemfile" do |content| assert_no_match(/redis/, content) end @@ -479,6 +537,31 @@ class AppGeneratorTest < Rails::Generators::TestCase end end + def test_inclusion_of_listen_related_configuration_by_default + run_generator + if RbConfig::CONFIG['host_os'] =~ /darwin|linux/ + assert_listen_related_configuration + else + assert_no_listen_related_configuration + end + end + + def test_non_inclusion_of_listen_related_configuration_if_skip_listen + run_generator [destination_root, '--skip-listen'] + assert_no_listen_related_configuration + end + + def test_evented_file_update_checker_config + run_generator + assert_file 'config/environments/development.rb' do |content| + if RbConfig::CONFIG['host_os'] =~ /darwin|linux/ + assert_match(/^\s*config.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content) + else + assert_match(/^\s*# config.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content) + end + end + end + def test_template_from_dir_pwd FileUtils.cd(Rails.root) assert_match(/It works from file!/, run_generator([destination_root, "-m", "lib/template.rb"])) @@ -588,7 +671,7 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_spring_no_fork jruby_skip "spring doesn't run on JRuby" - assert_called_with(Process, :respond_to?, [:fork], returns: false) do + assert_called_with(Process, :respond_to?, [[:fork], [:fork]], returns: false) do run_generator assert_file "Gemfile" do |content| @@ -600,6 +683,7 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_skip_spring run_generator [destination_root, "--skip-spring"] + assert_no_file 'config/spring.rb' assert_file "Gemfile" do |content| assert_no_match(/spring/, content) end @@ -736,4 +820,23 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file "Gemfile", /^\s*gem\s+["']#{gem}["']$*/ end end + + def assert_listen_related_configuration + assert_gem 'listen' + assert_gem 'spring-watcher-listen' + + assert_file 'config/environments/development.rb' do |content| + assert_match(/^\s*config.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content) + end + end + + def assert_no_listen_related_configuration + assert_file 'Gemfile' do |content| + assert_no_match(/listen/, content) + end + + assert_file 'config/environments/development.rb' do |content| + assert_match(/^\s*# config.file_watcher = ActiveSupport::EventedFileUpdateChecker/, content) + end + end end diff --git a/railties/test/generators/channel_generator_test.rb b/railties/test/generators/channel_generator_test.rb index c1f0c03fbf..cda9e8b910 100644 --- a/railties/test/generators/channel_generator_test.rb +++ b/railties/test/generators/channel_generator_test.rb @@ -5,6 +5,18 @@ class ChannelGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper tests Rails::Generators::ChannelGenerator + def test_application_cable_skeleton_is_created + run_generator ['books'] + + assert_file "app/channels/application_cable/channel.rb" do |cable| + assert_match(/module ApplicationCable\n class Channel < ActionCable::Channel::Base\n/, cable) + end + + assert_file "app/channels/application_cable/connection.rb" do |cable| + assert_match(/module ApplicationCable\n class Connection < ActionCable::Connection::Base\n/, cable) + end + end + def test_channel_is_created run_generator ['chat'] diff --git a/railties/test/generators/model_generator_test.rb b/railties/test/generators/model_generator_test.rb index 814f4c050e..ed6846abc3 100644 --- a/railties/test/generators/model_generator_test.rb +++ b/railties/test/generators/model_generator_test.rb @@ -6,6 +6,14 @@ 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) @@ -298,18 +306,18 @@ class ModelGeneratorTest < Rails::Generators::TestCase def test_fixtures_use_the_references_ids run_generator ["LineItem", "product:references", "cart:belongs_to"] - assert_file "test/fixtures/line_items.yml", /product: \n cart: / + assert_file "test/fixtures/line_items.yml", /product: one\n cart: one/ assert_generated_fixture("test/fixtures/line_items.yml", - {"one"=>{"product"=>nil, "cart"=>nil}, "two"=>{"product"=>nil, "cart"=>nil}}) + {"one"=>{"product"=>"one", "cart"=>"one"}, "two"=>{"product"=>"two", "cart"=>"two"}}) end def test_fixtures_use_the_references_ids_and_type run_generator ["LineItem", "product:references{polymorphic}", "cart:belongs_to"] - assert_file "test/fixtures/line_items.yml", /product: \n product_type: Product\n cart: / + assert_file "test/fixtures/line_items.yml", /product: one\n product_type: Product\n cart: one/ assert_generated_fixture("test/fixtures/line_items.yml", - {"one"=>{"product"=>nil, "product_type"=>"Product", "cart"=>nil}, - "two"=>{"product"=>nil, "product_type"=>"Product", "cart"=>nil}}) + {"one"=>{"product"=>"one", "product_type"=>"Product", "cart"=>"one"}, + "two"=>{"product"=>"two", "product_type"=>"Product", "cart"=>"two"}}) end def test_fixtures_respect_reserved_yml_keywords diff --git a/railties/test/generators/plugin_generator_test.rb b/railties/test/generators/plugin_generator_test.rb index 6e5132e849..cf3ed8405d 100644 --- a/railties/test/generators/plugin_generator_test.rb +++ b/railties/test/generators/plugin_generator_test.rb @@ -335,7 +335,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_file "hyphenated-name/lib/hyphenated/name/engine.rb", /module Hyphenated\n module Name\n class Engine < ::Rails::Engine\n isolate_namespace Hyphenated::Name\n end\n end\nend/ assert_file "hyphenated-name/lib/hyphenated/name.rb", /require "hyphenated\/name\/engine"/ assert_file "hyphenated-name/test/dummy/config/routes.rb", /mount Hyphenated::Name::Engine => "\/hyphenated-name"/ - assert_file "hyphenated-name/app/controllers/hyphenated/name/application_controller.rb", /module Hyphenated\n module Name\n class ApplicationController < ActionController::Base\n protect_from_forgery :with => :exception\n end\n end\nend\n/ + assert_file "hyphenated-name/app/controllers/hyphenated/name/application_controller.rb", /module Hyphenated\n module Name\n class ApplicationController < ActionController::Base\n protect_from_forgery with: :exception\n end\n end\nend\n/ assert_file "hyphenated-name/app/models/hyphenated/name/application_record.rb", /module Hyphenated\n module Name\n class ApplicationRecord < ActiveRecord::Base\n self\.abstract_class = true\n end\n end\nend/ assert_file "hyphenated-name/app/jobs/hyphenated/name/application_job.rb", /module Hyphenated\n module Name\n class ApplicationJob < ActiveJob::Base/ assert_file "hyphenated-name/app/mailers/hyphenated/name/application_mailer.rb", /module Hyphenated\n module Name\n class ApplicationMailer < ActionMailer::Base\n default from: 'from@example.com'\n layout 'mailer'\n end\n end\nend/ @@ -357,7 +357,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_file "my_hyphenated-name/lib/my_hyphenated/name/engine.rb", /module MyHyphenated\n module Name\n class Engine < ::Rails::Engine\n isolate_namespace MyHyphenated::Name\n end\n end\nend/ assert_file "my_hyphenated-name/lib/my_hyphenated/name.rb", /require "my_hyphenated\/name\/engine"/ assert_file "my_hyphenated-name/test/dummy/config/routes.rb", /mount MyHyphenated::Name::Engine => "\/my_hyphenated-name"/ - assert_file "my_hyphenated-name/app/controllers/my_hyphenated/name/application_controller.rb", /module MyHyphenated\n module Name\n class ApplicationController < ActionController::Base\n protect_from_forgery :with => :exception\n end\n end\nend\n/ + assert_file "my_hyphenated-name/app/controllers/my_hyphenated/name/application_controller.rb", /module MyHyphenated\n module Name\n class ApplicationController < ActionController::Base\n protect_from_forgery with: :exception\n end\n end\nend\n/ assert_file "my_hyphenated-name/app/models/my_hyphenated/name/application_record.rb", /module MyHyphenated\n module Name\n class ApplicationRecord < ActiveRecord::Base\n self\.abstract_class = true\n end\n end\nend/ assert_file "my_hyphenated-name/app/jobs/my_hyphenated/name/application_job.rb", /module MyHyphenated\n module Name\n class ApplicationJob < ActiveJob::Base/ assert_file "my_hyphenated-name/app/mailers/my_hyphenated/name/application_mailer.rb", /module MyHyphenated\n module Name\n class ApplicationMailer < ActionMailer::Base\n default from: 'from@example.com'\n layout 'mailer'\n end\n end\nend/ @@ -379,7 +379,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_file "deep-hyphenated-name/lib/deep/hyphenated/name/engine.rb", /module Deep\n module Hyphenated\n module Name\n class Engine < ::Rails::Engine\n isolate_namespace Deep::Hyphenated::Name\n end\n end\n end\nend/ assert_file "deep-hyphenated-name/lib/deep/hyphenated/name.rb", /require "deep\/hyphenated\/name\/engine"/ assert_file "deep-hyphenated-name/test/dummy/config/routes.rb", /mount Deep::Hyphenated::Name::Engine => "\/deep-hyphenated-name"/ - assert_file "deep-hyphenated-name/app/controllers/deep/hyphenated/name/application_controller.rb", /module Deep\n module Hyphenated\n module Name\n class ApplicationController < ActionController::Base\n protect_from_forgery :with => :exception\n end\n end\n end\nend\n/ + assert_file "deep-hyphenated-name/app/controllers/deep/hyphenated/name/application_controller.rb", /module Deep\n module Hyphenated\n module Name\n class ApplicationController < ActionController::Base\n protect_from_forgery with: :exception\n end\n end\n end\nend\n/ assert_file "deep-hyphenated-name/app/models/deep/hyphenated/name/application_record.rb", /module Deep\n module Hyphenated\n module Name\n class ApplicationRecord < ActiveRecord::Base\n self\.abstract_class = true\n end\n end\n end\nend/ assert_file "deep-hyphenated-name/app/jobs/deep/hyphenated/name/application_job.rb", /module Deep\n module Hyphenated\n module Name\n class ApplicationJob < ActiveJob::Base/ assert_file "deep-hyphenated-name/app/mailers/deep/hyphenated/name/application_mailer.rb", /module Deep\n module Hyphenated\n module Name\n class ApplicationMailer < ActionMailer::Base\n default from: 'from@example.com'\n layout 'mailer'\n end\n end\n end\nend/ @@ -444,6 +444,14 @@ class PluginGeneratorTest < Rails::Generators::TestCase end end + def test_dummy_appplication_skip_listen_by_default + run_generator + + assert_file 'test/dummy/config/environments/development.rb' do |contents| + assert_match(/^\s*# config.file_watcher = ActiveSupport::EventedFileUpdateChecker/, contents) + end + end + def test_ensure_that_gitignore_can_be_generated_from_a_template_for_dummy_path FileUtils.cd(Rails.root) run_generator([destination_root, "--dummy_path", "spec/dummy", "--skip-test"]) @@ -634,6 +642,20 @@ 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_after_bundle_callback path = 'http://example.org/rails_template' template = %{ after_bundle { run 'echo ran after_bundle' } } diff --git a/railties/test/generators/plugin_test_runner_test.rb b/railties/test/generators/plugin_test_runner_test.rb index f492cd49ef..ef6359fece 100644 --- a/railties/test/generators/plugin_test_runner_test.rb +++ b/railties/test/generators/plugin_test_runner_test.rb @@ -63,7 +63,7 @@ class PluginTestRunnerTest < ActiveSupport::TestCase create_test_file 'post', pass: false output = run_test_command('test/post_test.rb') - expect = %r{Running:\n\nPostTest\nF\n\nFailure:\nPostTest#test_truth:\nwups!\n\nbin/test (/private)?#{plugin_path}/test/post_test.rb:6} + expect = %r{Running:\n\nPostTest\nF\n\nFailure:\nPostTest#test_truth \[[^\]]+test/post_test.rb:6\]:\nwups!\n\nbin/test (/private)?#{plugin_path}/test/post_test.rb:4} assert_match expect, output end diff --git a/railties/test/generators/test_runner_in_engine_test.rb b/railties/test/generators/test_runner_in_engine_test.rb index 69906b962b..d37e261fbb 100644 --- a/railties/test/generators/test_runner_in_engine_test.rb +++ b/railties/test/generators/test_runner_in_engine_test.rb @@ -17,7 +17,7 @@ class TestRunnerInEngineTest < ActiveSupport::TestCase create_test_file 'post', pass: false output = run_test_command('test/post_test.rb') - expect = %r{Running:\n\nPostTest\nF\n\nFailure:\nPostTest#test_truth:\nwups!\n\nbin/rails test test/post_test.rb:6} + expect = %r{Running:\n\nPostTest\nF\n\nFailure:\nPostTest#test_truth \[[^\]]+test/post_test.rb:6\]:\nwups!\n\nbin/rails test test/post_test.rb:4} assert_match expect, output end diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb index dddf8bd257..52e0277633 100644 --- a/railties/test/isolation/abstract_unit.rb +++ b/railties/test/isolation/abstract_unit.rb @@ -124,7 +124,7 @@ module TestHelpers routes = File.read("#{app_path}/config/routes.rb") if routes =~ /(\n\s*end\s*)\Z/ File.open("#{app_path}/config/routes.rb", 'w') do |f| - f.puts $` + "\nmatch ':controller(/:action(/:id))(.:format)', via: :all\n" + $1 + f.puts $` + "\nActiveSupport::Deprecation.silence { match ':controller(/:action(/:id))(.:format)', via: :all }\n" + $1 end end @@ -272,10 +272,17 @@ module TestHelpers end def remove_from_config(str) - file = "#{app_path}/config/application.rb" + remove_from_file("#{app_path}/config/application.rb", str) + end + + def remove_from_env_config(env, str) + remove_from_file("#{app_path}/config/environments/#{env}.rb", str) + end + + def remove_from_file(file, str) contents = File.read(file) - contents.sub!(/#{str}/, "") - File.open(file, "w+") { |f| f.puts contents } + contents.sub!(/#{str}/, '') + File.write(file, contents) end def app_file(path, contents, mode = 'w') @@ -304,10 +311,6 @@ module TestHelpers end def boot_rails - # FIXME: shush Sass warning spam, not relevant to testing Railties - Kernel.silence_warnings do - require File.expand_path('../../../../load_paths', __FILE__) - end end end end @@ -319,7 +322,6 @@ class ActiveSupport::TestCase include ActiveSupport::Testing::Stream self.test_order = :sorted - end # Create a scope and build a fixture rails app @@ -330,12 +332,8 @@ Module.new do FileUtils.rm_rf(app_template_path) FileUtils.mkdir(app_template_path) - environment = File.expand_path('../../../../load_paths', __FILE__) - require_environment = "-r #{environment}" - - `#{Gem.ruby} #{require_environment} #{RAILS_FRAMEWORK_ROOT}/railties/exe/rails new #{app_template_path} --skip-gemfile --no-rc` + `#{Gem.ruby} #{RAILS_FRAMEWORK_ROOT}/railties/exe/rails new #{app_template_path} --skip-gemfile --skip-listen --no-rc` File.open("#{app_template_path}/config/boot.rb", 'w') do |f| - f.puts "require '#{environment}'" f.puts "require 'rails/all'" end end unless defined?(RAILS_ISOLATED_ENGINE) diff --git a/railties/test/railties/generators_test.rb b/railties/test/railties/generators_test.rb index 5f4171d44b..b85e16c040 100644 --- a/railties/test/railties/generators_test.rb +++ b/railties/test/railties/generators_test.rb @@ -26,11 +26,7 @@ module RailtiesTests end def rails(cmd) - environment = File.expand_path('../../../../load_paths', __FILE__) - if File.exist?("#{environment}.rb") - require_environment = "-r #{environment}" - end - `#{Gem.ruby} #{require_environment} #{RAILS_FRAMEWORK_ROOT}/railties/exe/rails #{cmd}` + `#{Gem.ruby} #{RAILS_FRAMEWORK_ROOT}/railties/exe/rails #{cmd}` end def build_engine(is_mountable=false) diff --git a/railties/test/test_unit/reporter_test.rb b/railties/test/test_unit/reporter_test.rb index 2d08d4ec30..0d64b48550 100644 --- a/railties/test/test_unit/reporter_test.rb +++ b/railties/test/test_unit/reporter_test.rb @@ -62,7 +62,7 @@ class TestUnitReporterTest < ActiveSupport::TestCase @reporter.record(failed_test) @reporter.report - expect = %r{\AF\n\nFailure:\nTestUnitReporterTest::ExampleTest#woot:\nboo\n\nbin/rails test test/test_unit/reporter_test.rb:\d+\n\n\z} + expect = %r{\AF\n\nFailure:\nTestUnitReporterTest::ExampleTest#woot \[[^\]]+\]:\nboo\n\nbin/rails test test/test_unit/reporter_test.rb:\d+\n\n\z} assert_match expect, @output.string end @@ -79,7 +79,7 @@ class TestUnitReporterTest < ActiveSupport::TestCase verbose.record(skipped_test) verbose.report - expect = %r{\ATestUnitReporterTest::ExampleTest#woot = 10\.00 s = S\n\n\nSkipped:\nTestUnitReporterTest::ExampleTest#woot:\nskipchurches, misstemples\n\nbin/rails test test/test_unit/reporter_test.rb:\d+\n\n\z} + expect = %r{\ATestUnitReporterTest::ExampleTest#woot = 10\.00 s = S\n\n\nSkipped:\nTestUnitReporterTest::ExampleTest#woot \[[^\]]+\]:\nskipchurches, misstemples\n\nbin/rails test test/test_unit/reporter_test.rb:\d+\n\n\z} assert_match expect, @output.string end @@ -104,11 +104,22 @@ class TestUnitReporterTest < ActiveSupport::TestCase end end - test "fail fast does not interrupt run errors or skips" do + test "fail fast interrupts run on error" do fail_fast = Rails::TestUnitReporter.new @output, fail_fast: true + interrupt_raised = false - fail_fast.record(errored_test) - assert_no_match 'Failed tests:', @output.string + # Minitest passes through Interrupt, catch it manually. + begin + fail_fast.record(errored_test) + rescue Interrupt + interrupt_raised = true + ensure + assert interrupt_raised, 'Expected Interrupt to be raised.' + end + end + + test "fail fast does not interrupt run skips" do + fail_fast = Rails::TestUnitReporter.new @output, fail_fast: true fail_fast.record(skipped_test) assert_no_match 'Failed tests:', @output.string |