aboutsummaryrefslogtreecommitdiffstats
path: root/railties/lib
diff options
context:
space:
mode:
Diffstat (limited to 'railties/lib')
-rw-r--r--railties/lib/rails.rb3
-rw-r--r--railties/lib/rails/api/generator.rb28
-rw-r--r--railties/lib/rails/api/task.rb23
-rw-r--r--railties/lib/rails/application.rb22
-rw-r--r--railties/lib/rails/application/bootstrap.rb10
-rw-r--r--railties/lib/rails/application/configuration.rb44
-rw-r--r--railties/lib/rails/application/default_middleware_stack.rb4
-rw-r--r--railties/lib/rails/application/finisher.rb1
-rw-r--r--railties/lib/rails/application/routes_reloader.rb17
-rw-r--r--railties/lib/rails/application_controller.rb2
-rw-r--r--railties/lib/rails/command.rb40
-rw-r--r--railties/lib/rails/command/actions.rb16
-rw-r--r--railties/lib/rails/command/base.rb20
-rw-r--r--railties/lib/rails/command/behavior.rb12
-rw-r--r--railties/lib/rails/commands/dbconsole/dbconsole_command.rb6
-rw-r--r--railties/lib/rails/commands/generate/generate_command.rb5
-rw-r--r--railties/lib/rails/commands/help/USAGE16
-rw-r--r--railties/lib/rails/commands/plugin/plugin_command.rb2
-rw-r--r--railties/lib/rails/commands/rake/rake_command.rb4
-rw-r--r--railties/lib/rails/commands/secrets/USAGE52
-rw-r--r--railties/lib/rails/commands/secrets/secrets_command.rb36
-rw-r--r--railties/lib/rails/commands/server/server_command.rb162
-rw-r--r--railties/lib/rails/commands/test/test_command.rb2
-rw-r--r--railties/lib/rails/engine.rb39
-rw-r--r--railties/lib/rails/engine/commands.rb17
-rw-r--r--railties/lib/rails/gem_version.rb2
-rw-r--r--railties/lib/rails/generators.rb410
-rw-r--r--railties/lib/rails/generators/actions.rb12
-rw-r--r--railties/lib/rails/generators/actions/create_migration.rb10
-rw-r--r--railties/lib/rails/generators/app_base.rb58
-rw-r--r--railties/lib/rails/generators/base.rb30
-rw-r--r--railties/lib/rails/generators/erb.rb2
-rw-r--r--railties/lib/rails/generators/erb/mailer/mailer_generator.rb6
-rw-r--r--railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb2
-rw-r--r--railties/lib/rails/generators/migration.rb2
-rw-r--r--railties/lib/rails/generators/named_base.rb90
-rw-r--r--railties/lib/rails/generators/rails/app/app_generator.rb45
-rw-r--r--railties/lib/rails/generators/rails/app/templates/Gemfile7
-rw-r--r--railties/lib/rails/generators/rails/app/templates/bin/yarn2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/cable.yml1
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml25
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt7
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults.rb.tt3
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/locales/en.yml10
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/secrets.yml6
-rw-r--r--railties/lib/rails/generators/rails/app/templates/gitignore3
-rw-r--r--railties/lib/rails/generators/rails/app/templates/test/application_system_test_case.rb5
-rw-r--r--railties/lib/rails/generators/rails/assets/assets_generator.rb2
-rw-r--r--railties/lib/rails/generators/rails/controller/controller_generator.rb25
-rw-r--r--railties/lib/rails/generators/rails/encrypted_secrets/encrypted_secrets_generator.rb66
-rw-r--r--railties/lib/rails/generators/rails/encrypted_secrets/templates/config/secrets.yml.enc3
-rw-r--r--railties/lib/rails/generators/rails/generator/generator_generator.rb2
-rw-r--r--railties/lib/rails/generators/rails/plugin/plugin_generator.rb14
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt1
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/bin/test.tt12
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/test/application_system_test_case.rb5
-rw-r--r--railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb4
-rw-r--r--railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb6
-rw-r--r--railties/lib/rails/generators/rails/system_test/USAGE10
-rw-r--r--railties/lib/rails/generators/rails/system_test/system_test_generator.rb7
-rw-r--r--railties/lib/rails/generators/resource_helpers.rb6
-rw-r--r--railties/lib/rails/generators/test_unit/generator/generator_generator.rb2
-rw-r--r--railties/lib/rails/generators/test_unit/integration/templates/integration_test.rb2
-rw-r--r--railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb2
-rw-r--r--railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb2
-rw-r--r--railties/lib/rails/generators/test_unit/system/system_generator.rb17
-rw-r--r--railties/lib/rails/generators/test_unit/system/templates/application_system_test_case.rb5
-rw-r--r--railties/lib/rails/generators/test_unit/system/templates/system_test.rb9
-rw-r--r--railties/lib/rails/generators/testing/behaviour.rb10
-rw-r--r--railties/lib/rails/info.rb6
-rw-r--r--railties/lib/rails/mailers_controller.rb10
-rw-r--r--railties/lib/rails/paths.rb4
-rw-r--r--railties/lib/rails/plugin/test.rb7
-rw-r--r--railties/lib/rails/rack/debugger.rb3
-rw-r--r--railties/lib/rails/rack/logger.rb66
-rw-r--r--railties/lib/rails/railtie.rb5
-rw-r--r--railties/lib/rails/railtie/configurable.rb2
-rw-r--r--railties/lib/rails/secrets.rb111
-rw-r--r--railties/lib/rails/source_annotation_extractor.rb2
-rw-r--r--railties/lib/rails/tasks.rb1
-rw-r--r--railties/lib/rails/tasks/framework.rake14
-rw-r--r--railties/lib/rails/tasks/log.rake8
-rw-r--r--railties/lib/rails/tasks/routes.rake9
-rw-r--r--railties/lib/rails/tasks/statistics.rake2
-rw-r--r--railties/lib/rails/tasks/yarn.rake11
-rw-r--r--railties/lib/rails/test_help.rb25
-rw-r--r--railties/lib/rails/test_unit/minitest_plugin.rb47
-rw-r--r--railties/lib/rails/test_unit/railtie.rb1
-rw-r--r--railties/lib/rails/test_unit/testing.rake5
92 files changed, 1185 insertions, 693 deletions
diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb
index ee48043a50..00add5829d 100644
--- a/railties/lib/rails.rb
+++ b/railties/lib/rails.rb
@@ -7,6 +7,7 @@ require "active_support/dependencies/autoload"
require "active_support/core_ext/kernel/reporting"
require "active_support/core_ext/module/delegation"
require "active_support/core_ext/array/extract_options"
+require "active_support/core_ext/object/blank"
require "rails/application"
require "rails/version"
@@ -67,7 +68,7 @@ module Rails
# Rails.env.development? # => true
# Rails.env.production? # => false
def env
- @_env ||= ActiveSupport::StringInquirer.new(ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development")
+ @_env ||= ActiveSupport::StringInquirer.new(ENV["RAILS_ENV"].presence || ENV["RACK_ENV"].presence || "development")
end
# Sets the Rails environment.
diff --git a/railties/lib/rails/api/generator.rb b/railties/lib/rails/api/generator.rb
new file mode 100644
index 0000000000..dcc491783c
--- /dev/null
+++ b/railties/lib/rails/api/generator.rb
@@ -0,0 +1,28 @@
+require "sdoc"
+
+class RDoc::Generator::API < RDoc::Generator::SDoc # :nodoc:
+ RDoc::RDoc.add_generator self
+
+ def generate_class_tree_level(classes, visited = {})
+ # Only process core extensions on the first visit.
+ if visited.empty?
+ core_exts, classes = classes.partition { |klass| core_extension?(klass) }
+
+ super.unshift([ "Core extensions", "", "", build_core_ext_subtree(core_exts, visited) ])
+ else
+ super
+ end
+ end
+
+ private
+ def build_core_ext_subtree(classes, visited)
+ classes.map do |klass|
+ [ klass.name, klass.document_self_or_methods ? klass.path : "", "",
+ generate_class_tree_level(klass.classes_and_modules, visited) ]
+ end
+ end
+
+ def core_extension?(klass)
+ klass.name != "ActiveSupport" && klass.in_files.any? { |file| file.absolute_name.include?("core_ext") }
+ end
+end
diff --git a/railties/lib/rails/api/task.rb b/railties/lib/rails/api/task.rb
index bc670b1d75..49267c2329 100644
--- a/railties/lib/rails/api/task.rb
+++ b/railties/lib/rails/api/task.rb
@@ -1,4 +1,5 @@
require "rdoc/task"
+require_relative "generator"
module Rails
module API
@@ -8,8 +9,7 @@ module Rails
include: %w(
README.rdoc
lib/active_support/**/*.rb
- ),
- exclude: "lib/active_support/vendor/*"
+ )
},
"activerecord" => {
@@ -69,7 +69,11 @@ module Rails
README.rdoc
lib/**/*.rb
),
- exclude: "lib/rails/generators/rails/**/templates/**/*.rb"
+ exclude: %w(
+ lib/rails/generators/**/templates/**/*.rb
+ lib/rails/test_unit/*
+ lib/rails/api/generator.rb
+ )
}
}
@@ -80,7 +84,7 @@ module Rails
# Be lazy computing stuff to have as light impact as possible to
# the rest of tasks.
before_running_rdoc do
- load_and_configure_sdoc
+ configure_sdoc
configure_rdoc_files
setup_horo_variables
end
@@ -91,20 +95,15 @@ module Rails
# no-op
end
- def load_and_configure_sdoc
- require "sdoc"
-
+ def configure_sdoc
self.title = "Ruby on Rails API"
self.rdoc_dir = api_dir
options << "-m" << api_main
options << "-e" << "UTF-8"
- options << "-f" << "sdoc"
+ options << "-f" << "api"
options << "-T" << "rails"
- rescue LoadError
- $stderr.puts %(Unable to load SDoc, please add\n\n gem 'sdoc', require: false\n\nto the Gemfile.)
- exit 1
end
def configure_rdoc_files
@@ -147,7 +146,7 @@ module Rails
end
class RepoTask < Task
- def load_and_configure_sdoc
+ def configure_sdoc
super
options << "-g" # link to GitHub, SDoc flag
end
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index f96432c89f..89f7b5991f 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -4,6 +4,7 @@ require "active_support/core_ext/object/blank"
require "active_support/key_generator"
require "active_support/message_verifier"
require "rails/engine"
+require "rails/secrets"
module Rails
# An Engine with the responsibility of coordinating the whole boot process.
@@ -72,7 +73,7 @@ module Rails
# on one of the applications to create a copy of the application which shares
# the configuration.
#
- # If you decide to define rake tasks, runners, or initializers in an
+ # If you decide to define Rake tasks, runners, or initializers in an
# application other than +Rails.application+, then you must run them manually.
class Application < Engine
autoload :Bootstrap, "rails/application/bootstrap"
@@ -265,8 +266,8 @@ module Rails
end
end
- # If you try to define a set of rake tasks on the instance, these will get
- # passed up to the rake tasks defined on the application's class.
+ # If you try to define a set of Rake tasks on the instance, these will get
+ # passed up to the Rake tasks defined on the application's class.
def rake_tasks(&block)
self.class.rake_tasks(&block)
end
@@ -385,18 +386,7 @@ module Rails
def secrets
@secrets ||= begin
secrets = ActiveSupport::OrderedOptions.new
- yaml = config.paths["config/secrets"].first
-
- if File.exist?(yaml)
- require "erb"
-
- all_secrets = YAML.load(ERB.new(IO.read(yaml)).result) || {}
- shared_secrets = all_secrets["shared"]
- env_secrets = all_secrets[Rails.env]
-
- secrets.merge!(shared_secrets.deep_symbolize_keys) if shared_secrets
- secrets.merge!(env_secrets.deep_symbolize_keys) if env_secrets
- end
+ secrets.merge! Rails::Secrets.parse(config.paths["config/secrets"].existent, env: Rails.env)
# Fallback to config.secret_key_base if secrets.secret_key_base isn't set
secrets.secret_key_base ||= config.secret_key_base
@@ -511,7 +501,7 @@ module Rails
def validate_secret_key_config! #:nodoc:
if secrets.secret_key_base.blank?
- ActiveSupport::Deprecation.warn "You didn't set `secret_key_base`. " +
+ ActiveSupport::Deprecation.warn "You didn't set `secret_key_base`. " \
"Read the upgrade documentation to learn more about this new config option."
if secrets.secret_token.blank?
diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb
index 11da271501..4223c38146 100644
--- a/railties/lib/rails/application/bootstrap.rb
+++ b/railties/lib/rails/application/bootstrap.rb
@@ -2,6 +2,7 @@ require "fileutils"
require "active_support/notifications"
require "active_support/dependencies"
require "active_support/descendants_tracker"
+require "rails/secrets"
module Rails
class Application
@@ -48,8 +49,8 @@ INFO
logger = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new(STDERR))
logger.level = ActiveSupport::Logger::WARN
logger.warn(
- "Rails Error: Unable to access log file. Please ensure that #{path} exists and is writable " +
- "(ie, make it writable for user and group: chmod 0664 #{path}). " +
+ "Rails Error: Unable to access log file. Please ensure that #{path} exists and is writable " \
+ "(ie, make it writable for user and group: chmod 0664 #{path}). " \
"The log level has been raised to WARN and the output directed to STDERR until the problem is fixed."
)
logger
@@ -77,6 +78,11 @@ INFO
initializer :bootstrap_hook, group: :all do |app|
ActiveSupport.run_load_hooks(:before_initialize, app)
end
+
+ initializer :set_secrets_root, group: :all do
+ Rails::Secrets.root = root
+ Rails::Secrets.read_encrypted_secrets = config.read_encrypted_secrets
+ end
end
end
end
diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb
index 810750ed35..b0592151b7 100644
--- a/railties/lib/rails/application/configuration.rb
+++ b/railties/lib/rails/application/configuration.rb
@@ -3,9 +3,6 @@ require "active_support/file_update_checker"
require "rails/engine/configuration"
require "rails/source_annotation_extractor"
-require "active_support/deprecation"
-require "active_support/core_ext/string/strip" # for strip_heredoc
-
module Rails
class Application
class Configuration < ::Rails::Engine::Configuration
@@ -16,14 +13,15 @@ module Rails
:railties_order, :relative_url_root, :secret_key_base, :secret_token,
:ssl_options, :public_file_server,
:session_options, :time_zone, :reload_classes_only_on_change,
- :beginning_of_week, :filter_redirect, :x, :enable_dependency_loading
+ :beginning_of_week, :filter_redirect, :x, :enable_dependency_loading,
+ :read_encrypted_secrets
attr_writer :log_level
- attr_reader :encoding, :api_only, :static_cache_control
+ attr_reader :encoding, :api_only
def initialize(*)
super
- self.encoding = "utf-8"
+ self.encoding = Encoding::UTF_8
@allow_concurrency = nil
@consider_all_requests_local = false
@filter_parameters = []
@@ -54,35 +52,7 @@ module Rails
@debug_exception_response_format = nil
@x = Custom.new
@enable_dependency_loading = false
- end
-
- def static_cache_control=(value)
- ActiveSupport::Deprecation.warn <<-eow.strip_heredoc
- `config.static_cache_control` is deprecated and will be removed in Rails 5.1.
- Please use
- `config.public_file_server.headers = { 'Cache-Control' => '#{value}' }`
- instead.
- eow
-
- @static_cache_control = value
- end
-
- def serve_static_files
- ActiveSupport::Deprecation.warn <<-eow.strip_heredoc
- `config.serve_static_files` is deprecated and will be removed in Rails 5.1.
- Please use `config.public_file_server.enabled` instead.
- eow
-
- @public_file_server.enabled
- end
-
- def serve_static_files=(value)
- ActiveSupport::Deprecation.warn <<-eow.strip_heredoc
- `config.serve_static_files` is deprecated and will be removed in Rails 5.1.
- Please use `config.public_file_server.enabled = #{value}` instead.
- eow
-
- @public_file_server.enabled = value
+ @read_encrypted_secrets = false
end
def encoding=(value)
@@ -112,7 +82,7 @@ module Rails
@paths ||= begin
paths = super
paths.add "config/database", with: "config/database.yml"
- paths.add "config/secrets", with: "config/secrets.yml"
+ paths.add "config/secrets", with: "config", glob: "secrets.yml{,.enc}"
paths.add "config/environment", with: "config/environment.rb"
paths.add "lib/templates"
paths.add "log", with: "log/#{Rails.env}.log"
@@ -161,7 +131,7 @@ module Rails
def colorize_logging=(val)
ActiveSupport::LogSubscriber.colorize_logging = val
- self.generators.colorize_logging = val
+ generators.colorize_logging = val
end
def session_store(new_session_store = nil, **options)
diff --git a/railties/lib/rails/application/default_middleware_stack.rb b/railties/lib/rails/application/default_middleware_stack.rb
index 14c0a8cbe4..8fe48feefb 100644
--- a/railties/lib/rails/application/default_middleware_stack.rb
+++ b/railties/lib/rails/application/default_middleware_stack.rb
@@ -19,7 +19,6 @@ module Rails
if config.public_file_server.enabled
headers = config.public_file_server.headers || {}
- headers["Cache-Control".freeze] = config.static_cache_control if config.static_cache_control
middleware.use ::ActionDispatch::Static, paths["public"].first, index: config.public_file_server.index_name, headers: headers
end
@@ -41,12 +40,11 @@ module Rails
middleware.use ::Rack::Runtime
middleware.use ::Rack::MethodOverride unless config.api_only
middleware.use ::ActionDispatch::RequestId
+ middleware.use ::ActionDispatch::RemoteIp, config.action_dispatch.ip_spoofing_check, config.action_dispatch.trusted_proxies
- # Must come after Rack::MethodOverride to properly log overridden methods
middleware.use ::Rails::Rack::Logger, config.log_tags
middleware.use ::ActionDispatch::ShowExceptions, show_exceptions_app
middleware.use ::ActionDispatch::DebugExceptions, app, config.debug_exception_response_format
- middleware.use ::ActionDispatch::RemoteIp, config.action_dispatch.ip_spoofing_check, config.action_dispatch.trusted_proxies
unless config.cache_classes
middleware.use ::ActionDispatch::Reloader, app.reloader
diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb
index a855e8fab0..c027d06663 100644
--- a/railties/lib/rails/application/finisher.rb
+++ b/railties/lib/rails/application/finisher.rb
@@ -124,6 +124,7 @@ module Rails
# the hook are taken into account.
initializer :set_routes_reloader_hook do |app|
reloader = routes_reloader
+ reloader.eager_load = app.config.eager_load
reloader.execute_if_updated
reloaders << reloader
app.reloader.to_run do
diff --git a/railties/lib/rails/application/routes_reloader.rb b/railties/lib/rails/application/routes_reloader.rb
index cf0a4e128f..e02ef629f2 100644
--- a/railties/lib/rails/application/routes_reloader.rb
+++ b/railties/lib/rails/application/routes_reloader.rb
@@ -4,11 +4,13 @@ module Rails
class Application
class RoutesReloader
attr_reader :route_sets, :paths
- delegate :execute_if_updated, :execute, :updated?, to: :updater
+ attr_accessor :eager_load
+ delegate :updated?, to: :updater
def initialize
@paths = []
@route_sets = []
+ @eager_load = false
end
def reload!
@@ -19,6 +21,19 @@ module Rails
revert
end
+ def execute
+ ret = updater.execute
+ route_sets.each(&:eager_load!) if eager_load
+ ret
+ end
+
+ def execute_if_updated
+ if updated = updater.execute_if_updated
+ route_sets.each(&:eager_load!) if eager_load
+ end
+ updated
+ end
+
private
def updater
diff --git a/railties/lib/rails/application_controller.rb b/railties/lib/rails/application_controller.rb
index f8394b8e0a..a98e51fd28 100644
--- a/railties/lib/rails/application_controller.rb
+++ b/railties/lib/rails/application_controller.rb
@@ -2,7 +2,7 @@ class Rails::ApplicationController < ActionController::Base # :nodoc:
self.view_paths = File.expand_path("../templates", __FILE__)
layout "application"
- protected
+ private
def require_local!
unless local_request?
diff --git a/railties/lib/rails/command.rb b/railties/lib/rails/command.rb
index 6065e78fd1..0d4e6dc5a1 100644
--- a/railties/lib/rails/command.rb
+++ b/railties/lib/rails/command.rb
@@ -15,6 +15,8 @@ module Rails
include Behavior
+ HELP_MAPPINGS = %w(-h -? --help)
+
class << self
def hidden_commands # :nodoc:
@hidden_commands ||= []
@@ -25,19 +27,27 @@ module Rails
end
# Receives a namespace, arguments and the behavior to invoke the command.
- def invoke(namespace, args = [], **config)
- namespace = namespace.to_s
- namespace = "help" if namespace.blank? || Thor::HELP_MAPPINGS.include?(namespace)
- namespace = "version" if %w( -v --version ).include? namespace
+ def invoke(full_namespace, args = [], **config)
+ namespace = full_namespace = full_namespace.to_s
+
+ if char = namespace =~ /:(\w+)$/
+ command_name, namespace = $1, namespace.slice(0, char)
+ else
+ command_name = namespace
+ end
+
+ command_name, namespace = "help", "help" if command_name.blank? || HELP_MAPPINGS.include?(command_name)
+ command_name, namespace = "version", "version" if %w( -v --version ).include?(command_name)
- if command = find_by_namespace(namespace)
- command.perform(namespace, args, config)
+ command = find_by_namespace(namespace, command_name)
+ if command && command.all_commands[command_name]
+ command.perform(command_name, args, config)
else
- find_by_namespace("rake").perform(namespace, args, config)
+ find_by_namespace("rake").perform(full_namespace, args, config)
end
end
- # Rails finds namespaces similar to thor, it only adds one rule:
+ # Rails finds namespaces similar to Thor, it only adds one rule:
#
# Command names must end with "_command.rb". This is required because Rails
# looks in load paths and loads the command just before it's going to be used.
@@ -50,8 +60,10 @@ module Rails
#
# Notice that "rails:commands:webrat" could be loaded as well, what
# Rails looks for is the first and last parts of the namespace.
- def find_by_namespace(name) # :nodoc:
- lookups = [ name, "rails:#{name}" ]
+ def find_by_namespace(namespace, command_name = nil) # :nodoc:
+ lookups = [ namespace ]
+ lookups << "#{namespace}:#{command_name}" if command_name
+ lookups.concat lookups.map { |lookup| "rails:#{lookup}" }
lookup(lookups)
@@ -82,16 +94,16 @@ module Rails
[[ "rails", rails ]] + groups.sort.to_a
end
- protected
- def command_type
+ private
+ def command_type # :doc:
@command_type ||= "command"
end
- def lookup_paths
+ def lookup_paths # :doc:
@lookup_paths ||= %w( rails/commands commands )
end
- def file_lookup_paths
+ def file_lookup_paths # :doc:
@file_lookup_paths ||= [ "{#{lookup_paths.join(',')}}", "**", "*_command.rb" ]
end
end
diff --git a/railties/lib/rails/command/actions.rb b/railties/lib/rails/command/actions.rb
index 31b656ec31..8fda1c87c6 100644
--- a/railties/lib/rails/command/actions.rb
+++ b/railties/lib/rails/command/actions.rb
@@ -8,11 +8,16 @@ module Rails
Dir.chdir(File.expand_path("../../", APP_PATH)) unless File.exist?(File.expand_path("config.ru"))
end
- if defined?(ENGINE_PATH)
- def require_application_and_environment!
- require ENGINE_PATH
+ def require_application_and_environment!
+ require ENGINE_PATH if defined?(ENGINE_PATH)
+
+ if defined?(APP_PATH)
+ require APP_PATH
+ Rails.application.require_environment!
end
+ end
+ if defined?(ENGINE_PATH)
def load_tasks
Rake.application.init("rails")
Rake.application.load_rakefile
@@ -24,11 +29,6 @@ module Rails
engine.load_generators
end
else
- def require_application_and_environment!
- require APP_PATH
- Rails.application.require_environment!
- end
-
def load_tasks
Rails.application.load_tasks
end
diff --git a/railties/lib/rails/command/base.rb b/railties/lib/rails/command/base.rb
index 1efcd69e63..db20c71861 100644
--- a/railties/lib/rails/command/base.rb
+++ b/railties/lib/rails/command/base.rb
@@ -22,7 +22,7 @@ module Rails
# Tries to get the description from a USAGE file one folder above the command
# root.
- def desc(usage = nil, description = nil)
+ def desc(usage = nil, description = nil, options = {})
if usage
super
else
@@ -56,7 +56,9 @@ module Rails
end
def perform(command, args, config) # :nodoc:
- command = nil if Thor::HELP_MAPPINGS.include?(args.first)
+ if Rails::Command::HELP_MAPPINGS.include?(args.first)
+ command, args = "help", []
+ end
dispatch(command, args.dup, nil, config)
end
@@ -111,7 +113,7 @@ module Rails
# For a `Rails::Command::TestCommand` placed in `rails/command/test_command.rb`
# would return `rails/test`.
def default_command_root
- path = File.expand_path(File.join("../commands", command_name), __dir__)
+ path = File.expand_path(File.join("../commands", command_root_namespace), __dir__)
path if File.exist?(path)
end
@@ -129,6 +131,18 @@ module Rails
super
end
end
+
+ def command_root_namespace
+ (namespace.split(":") - %w( rails )).first
+ end
+ end
+
+ def help
+ if command_name = self.class.command_name
+ self.class.command_help(shell, command_name)
+ else
+ super
+ end
end
end
end
diff --git a/railties/lib/rails/command/behavior.rb b/railties/lib/rails/command/behavior.rb
index 2e8517070c..4a92f72f16 100644
--- a/railties/lib/rails/command/behavior.rb
+++ b/railties/lib/rails/command/behavior.rb
@@ -16,13 +16,13 @@ module Rails
@subclasses ||= []
end
- protected
+ private
# This code is based directly on the Text gem implementation.
# Copyright (c) 2006-2013 Paul Battley, Michael Neumann, Tim Fletcher.
#
# Returns a value representing the "cost" of transforming str1 into str2.
- def levenshtein_distance(str1, str2)
+ def levenshtein_distance(str1, str2) # :doc:
s = str1
t = str2
n = s.length
@@ -58,7 +58,7 @@ module Rails
end
# Prints a list of generators.
- def print_list(base, namespaces) #:nodoc:
+ def print_list(base, namespaces)
return if namespaces.empty?
puts "#{base.camelize}:"
@@ -71,7 +71,7 @@ module Rails
# Receives namespaces in an array and tries to find matching generators
# in the load path.
- def lookup(namespaces) #:nodoc:
+ def lookup(namespaces)
paths = namespaces_to_paths(namespaces)
paths.each do |raw_path|
@@ -91,7 +91,7 @@ module Rails
end
# This will try to load any command in the load path to show in help.
- def lookup! #:nodoc:
+ def lookup!
$LOAD_PATH.each do |base|
Dir[File.join(base, *file_lookup_paths)].each do |path|
begin
@@ -107,7 +107,7 @@ module Rails
# Convert namespaces to paths by replacing ":" for "/" and adding
# an extra lookup. For example, "rails:model" should be searched
# in both: "rails/model/model_generator" and "rails/model_generator".
- def namespaces_to_paths(namespaces) #:nodoc:
+ def namespaces_to_paths(namespaces)
paths = []
namespaces.each do |namespace|
pieces = namespace.split(":")
diff --git a/railties/lib/rails/commands/dbconsole/dbconsole_command.rb b/railties/lib/rails/commands/dbconsole/dbconsole_command.rb
index 35e8673215..588fb06b15 100644
--- a/railties/lib/rails/commands/dbconsole/dbconsole_command.rb
+++ b/railties/lib/rails/commands/dbconsole/dbconsole_command.rb
@@ -99,14 +99,14 @@ module Rails
Rails.respond_to?(:env) ? Rails.env : Rails::Command.environment
end
- protected
- def configurations
+ private
+ def configurations # :doc:
require APP_PATH
ActiveRecord::Base.configurations = Rails.application.config.database_configuration
ActiveRecord::Base.configurations
end
- def find_cmd_and_exec(commands, *args)
+ def find_cmd_and_exec(commands, *args) # :doc:
commands = Array(commands)
dirs_on_path = ENV["PATH"].to_s.split(File::PATH_SEPARATOR)
diff --git a/railties/lib/rails/commands/generate/generate_command.rb b/railties/lib/rails/commands/generate/generate_command.rb
index 59b2febc43..2718b453a8 100644
--- a/railties/lib/rails/commands/generate/generate_command.rb
+++ b/railties/lib/rails/commands/generate/generate_command.rb
@@ -4,6 +4,9 @@ module Rails
module Command
class GenerateCommand < Base # :nodoc:
def help
+ require_application_and_environment!
+ load_generators
+
Rails::Generators.help self.class.command_name
end
@@ -14,6 +17,8 @@ module Rails
require_application_and_environment!
load_generators
+ ARGV.shift
+
Rails::Generators.invoke generator, args, behavior: :invoke, destination_root: Rails::Command.root
end
end
diff --git a/railties/lib/rails/commands/help/USAGE b/railties/lib/rails/commands/help/USAGE
index 348f41861f..c5f8ab72bb 100644
--- a/railties/lib/rails/commands/help/USAGE
+++ b/railties/lib/rails/commands/help/USAGE
@@ -1,16 +1,3 @@
-Usage: bin/rails COMMAND [args] [options]
-<% if engine? %>
-The common Rails commands available for engines are:
- generate Generate new code (short-cut alias: "g")
- destroy Undo code generated with "generate" (short-cut alias: "d")
- test Run tests (short-cut alias: "t")
-
-All commands can be run with -h for more information.
-
-If you want to run any commands that need to be run in context
-of the application, like `bin/rails server` or `bin/rails console`,
-you should do it from the application's directory (typically test/dummy).
-<% else %>
The most common rails commands are:
generate Generate new code (short-cut alias: "g")
console Start the Rails console (short-cut alias: "c")
@@ -18,10 +5,11 @@ The most common rails commands are:
test Run tests (short-cut alias: "t")
dbconsole Start a console for the database specified in config/database.yml
(short-cut alias: "db")
+<% unless engine? %>
new Create a new Rails application. "rails new my_app" creates a
new application called MyApp in "./my_app"
+<% end %>
All commands can be run with -h (or --help) for more information.
-<% end %>
In addition to those commands, there are:
diff --git a/railties/lib/rails/commands/plugin/plugin_command.rb b/railties/lib/rails/commands/plugin/plugin_command.rb
index 16587ce067..b40ab006af 100644
--- a/railties/lib/rails/commands/plugin/plugin_command.rb
+++ b/railties/lib/rails/commands/plugin/plugin_command.rb
@@ -11,7 +11,7 @@ module Rails
"#{executable} new [options]"
end
- class_option :rc, type: :boolean, default: File.join("~", ".railsrc"),
+ class_option :rc, type: :string, default: File.join("~", ".railsrc"),
desc: "Initialize the plugin command with previous defaults. Uses .railsrc in your home directory by default."
class_option :no_rc, desc: "Skip evaluating .railsrc."
diff --git a/railties/lib/rails/commands/rake/rake_command.rb b/railties/lib/rails/commands/rake/rake_command.rb
index f03dc81117..075b1fd23d 100644
--- a/railties/lib/rails/commands/rake/rake_command.rb
+++ b/railties/lib/rails/commands/rake/rake_command.rb
@@ -28,9 +28,7 @@ module Rails
return @rake_tasks if defined?(@rake_tasks)
- ActiveSupport::Deprecation.silence do
- require_application_and_environment!
- end
+ require_application_and_environment!
Rake::TaskManager.record_task_metadata = true
Rake.application.instance_variable_set(:@name, "rails")
diff --git a/railties/lib/rails/commands/secrets/USAGE b/railties/lib/rails/commands/secrets/USAGE
new file mode 100644
index 0000000000..4b7deb4e2a
--- /dev/null
+++ b/railties/lib/rails/commands/secrets/USAGE
@@ -0,0 +1,52 @@
+=== Storing Encrypted Secrets in Source Control
+
+The Rails `secrets` commands helps encrypting secrets to slim a production
+environment's `ENV` hash. It's also useful for atomic deploys: no need to
+coordinate key changes to get everything working as the keys are shipped
+with the code.
+
+=== Setup
+
+Run `bin/rails secrets:setup` to opt in and generate the `config/secrets.yml.key`
+and `config/secrets.yml.enc` files.
+
+The latter contains all the keys to be encrypted while the former holds the
+encryption key.
+
+Don't lose the key! Put it in a password manager your team can access.
+Should you lose it no one, including you, will be able to access any encrypted
+secrets.
+Don't commit the key! Add `config/secrets.yml.key` to your source control's
+ignore file. If you use Git, Rails handles this for you.
+
+Rails also looks for the key in `ENV["RAILS_MASTER_KEY"]` if that's easier to
+manage.
+
+You could prepend that to your server's start command like this:
+
+ RAILS_MASTER_KEY="im-the-master-now-hahaha" server.start
+
+
+The `config/secrets.yml.enc` has much the same format as `config/secrets.yml`:
+
+ production:
+ secret_key_base: so-secret-very-hidden-wow
+ payment_processing_gateway_key: much-safe-very-gaedwey-wow
+
+But that's where the similarities between `secrets.yml` and `secrets.yml.enc`
+end, e.g. no keys from `secrets.yml` will be moved to `secrets.yml.enc` and
+be encrypted.
+
+A `shared:` top level key is also supported such that any keys there is merged
+into the other environments.
+
+=== Editing Secrets
+
+After `bin/rails secrets:setup`, run `bin/rails secrets:edit`.
+
+That command opens a temporary file in `$EDITOR` with the decrypted contents of
+`config/secrets.yml.enc` to edit the encrypted secrets.
+
+When the temporary file is next saved the contents are encrypted and written to
+`config/secrets.yml.enc` while the file itself is destroyed to prevent secrets
+from leaking.
diff --git a/railties/lib/rails/commands/secrets/secrets_command.rb b/railties/lib/rails/commands/secrets/secrets_command.rb
new file mode 100644
index 0000000000..3ba8c0c85b
--- /dev/null
+++ b/railties/lib/rails/commands/secrets/secrets_command.rb
@@ -0,0 +1,36 @@
+require "active_support"
+require "rails/secrets"
+
+module Rails
+ module Command
+ class SecretsCommand < Rails::Command::Base # :nodoc:
+ def help
+ say "Usage:\n #{self.class.banner}"
+ say ""
+ say self.class.desc
+ end
+
+ def setup
+ require "rails/generators"
+ require "rails/generators/rails/encrypted_secrets/encrypted_secrets_generator"
+
+ Rails::Generators::EncryptedSecretsGenerator.start
+ end
+
+ def edit
+ require_application_and_environment!
+
+ Rails::Secrets.read_for_editing do |tmp_path|
+ puts "Waiting for secrets file to be saved. Abort with Ctrl-C."
+ system("\$EDITOR #{tmp_path}")
+ end
+
+ puts "New secrets encrypted and saved."
+ rescue Interrupt
+ puts "Aborted changing encrypted secrets: nothing saved."
+ rescue Rails::Secrets::MissingKeyError => error
+ say error.message
+ end
+ end
+ end
+end
diff --git a/railties/lib/rails/commands/server/server_command.rb b/railties/lib/rails/commands/server/server_command.rb
index e9538b804c..1fa27a3155 100644
--- a/railties/lib/rails/commands/server/server_command.rb
+++ b/railties/lib/rails/commands/server/server_command.rb
@@ -7,51 +7,14 @@ require "rails/dev_caching"
module Rails
class Server < ::Rack::Server
class Options
- DEFAULT_PID_PATH = File.expand_path("tmp/pids/server.pid").freeze
-
def parse!(args)
- args, options = args.dup, {}
-
- option_parser(options).parse! args
-
- options[:log_stdout] = options[:daemonize].blank? && (options[:environment] || Rails.env) == "development"
- options[:server] = args.shift
- options
- end
-
- def option_parser(options) # :nodoc:
- OptionParser.new do |opts|
- opts.banner = "Usage: rails server [puma, thin etc] [options]"
-
- opts.separator ""
- opts.separator "Options:"
-
- opts.on("-p", "--port=port", Integer,
- "Runs Rails on the specified port.", "Default: 3000") { |v| options[:Port] = v }
- opts.on("-b", "--binding=IP", String,
- "Binds Rails to the specified IP.", "Default: localhost") { |v| options[:Host] = v }
- opts.on("-c", "--config=file", String,
- "Uses a custom rackup configuration.") { |v| options[:config] = v }
- opts.on("-d", "--daemon", "Runs server as a Daemon.") { options[:daemonize] = true }
- opts.on("-e", "--environment=name", String,
- "Specifies the environment to run this server under (test/development/production).",
- "Default: development") { |v| options[:environment] = v }
- opts.on("-P", "--pid=pid", String,
- "Specifies the PID file.",
- "Default: tmp/pids/server.pid") { |v| options[:pid] = v }
- opts.on("-C", "--[no-]dev-caching",
- "Specifies whether to perform caching in development.",
- "true or false") { |v| options[:caching] = v }
-
- opts.separator ""
-
- opts.on("-h", "--help", "Shows this help message.") { puts opts; exit }
- end
+ Rails::Command::ServerCommand.new([], args).server_options
end
end
- def initialize(*)
- super
+ def initialize(options = nil)
+ @default_options = options || {}
+ super(@default_options)
set_environment
end
@@ -90,15 +53,7 @@ module Rails
end
def default_options
- super.merge(
- Port: ENV.fetch("PORT", 3000).to_i,
- Host: ENV.fetch("HOST", "localhost").dup,
- DoNotReverseLookup: true,
- environment: (ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development").dup,
- daemonize: false,
- caching: nil,
- pid: Options::DEFAULT_PID_PATH,
- restart_cmd: restart_command)
+ super.merge(@default_options)
end
private
@@ -140,14 +95,34 @@ module Rails
module Command
class ServerCommand < Base # :nodoc:
- def help
- puts Rails::Server::Options.new.option_parser(Hash.new)
+ DEFAULT_PID_PATH = "tmp/pids/server.pid".freeze
+
+ class_option :port, aliases: "-p", type: :numeric,
+ desc: "Runs Rails on the specified port.", banner: :port, default: 3000
+ class_option :binding, aliases: "-b", type: :string,
+ desc: "Binds Rails to the specified IP - defaults to 'localhost' in development and '0.0.0.0' in other environments'.",
+ banner: :IP
+ class_option :config, aliases: "-c", type: :string, default: "config.ru",
+ desc: "Uses a custom rackup configuration.", banner: :file
+ class_option :daemon, aliases: "-d", type: :boolean, default: false,
+ desc: "Runs server as a Daemon."
+ class_option :environment, aliases: "-e", type: :string,
+ desc: "Specifies the environment to run this server under (development/test/production).", banner: :name
+ class_option :pid, aliases: "-P", type: :string, default: DEFAULT_PID_PATH,
+ desc: "Specifies the PID file."
+ class_option "dev-caching", aliases: "-C", type: :boolean, default: nil,
+ desc: "Specifies whether to perform caching in development."
+
+ def initialize(args = [], local_options = {}, config = {})
+ @original_options = local_options
+ super
+ @server = self.args.shift
+ @log_stdout = options[:daemon].blank? && (options[:environment] || Rails.env) == "development"
end
def perform
set_application_directory!
-
- Rails::Server.new.tap do |server|
+ Rails::Server.new(server_options).tap do |server|
# Require application after server sets environment to propagate
# the --environment option.
require APP_PATH
@@ -155,6 +130,85 @@ module Rails
server.start
end
end
+
+ no_commands do
+ def server_options
+ {
+ user_supplied_options: user_supplied_options,
+ server: @server,
+ log_stdout: @log_stdout,
+ Port: port,
+ Host: host,
+ DoNotReverseLookup: true,
+ config: options[:config],
+ environment: environment,
+ daemonize: options[:daemon],
+ pid: pid,
+ caching: options["dev-caching"],
+ restart_cmd: restart_command
+ }
+ end
+ end
+
+ private
+ def user_supplied_options
+ @user_supplied_options ||= begin
+ # Convert incoming options array to a hash of flags
+ # ["-p", "3001", "-c", "foo"] # => {"-p" => true, "-c" => true}
+ user_flag = {}
+ @original_options.each_with_index { |command, i| user_flag[command] = true if i.even? }
+
+ # Collect all options that the user has explicitly defined so we can
+ # differentiate them from defaults
+ user_supplied_options = []
+ self.class.class_options.select do |key, option|
+ if option.aliases.any? { |name| user_flag[name] } || user_flag["--#{option.name}"]
+ name = option.name.to_sym
+ case name
+ when :port
+ name = :Port
+ when :binding
+ name = :Host
+ when :"dev-caching"
+ name = :caching
+ when :daemonize
+ name = :daemon
+ end
+ user_supplied_options << name
+ end
+ end
+ user_supplied_options << :Host if ENV["Host"]
+ user_supplied_options << :Port if ENV["PORT"]
+ user_supplied_options.uniq
+ end
+ end
+
+ def port
+ ENV.fetch("PORT", options[:port]).to_i
+ end
+
+ def host
+ unless (default_host = options[:binding])
+ default_host = environment == "development" ? "localhost" : "0.0.0.0"
+ end
+ ENV.fetch("HOST", default_host)
+ end
+
+ def environment
+ options[:environment] || Rails::Command.environment
+ end
+
+ def restart_command
+ "bin/rails server #{@server} #{@original_options.join(" ")}"
+ end
+
+ def pid
+ File.expand_path(options[:pid])
+ end
+
+ def self.banner(*)
+ "rails server [puma, thin etc] [options]"
+ end
end
end
end
diff --git a/railties/lib/rails/commands/test/test_command.rb b/railties/lib/rails/commands/test/test_command.rb
index 7bf8f61137..629fb5b425 100644
--- a/railties/lib/rails/commands/test/test_command.rb
+++ b/railties/lib/rails/commands/test/test_command.rb
@@ -11,7 +11,7 @@ module Rails
def perform(*)
$LOAD_PATH << Rails::Command.root.join("test")
- Minitest.run_via[:rails] = true
+ Minitest.run_via = :rails
require "active_support/testing/autorun"
end
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index e56f6159ad..dc0b158bd4 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -109,7 +109,7 @@ module Rails
#
# == Endpoint
#
- # An engine can also be a rack application. It can be useful if you have a rack application that
+ # An engine can also be a Rack application. It can be useful if you have a Rack application that
# you would like to wrap with +Engine+ and provide with some of the +Engine+'s features.
#
# To do that, use the +endpoint+ method:
@@ -128,7 +128,7 @@ module Rails
#
# == Middleware stack
#
- # As an engine can now be a rack endpoint, it can also have a middleware
+ # As an engine can now be a Rack endpoint, it can also have a middleware
# stack. The usage is exactly the same as in <tt>Application</tt>:
#
# module MyEngine
@@ -380,7 +380,7 @@ module Rails
def isolate_namespace(mod)
engine_name(generate_railtie_name(mod.name))
- self.routes.default_scope = { module: ActiveSupport::Inflector.underscore(mod.name) }
+ routes.default_scope = { module: ActiveSupport::Inflector.underscore(mod.name) }
self.isolated = true
unless mod.respond_to?(:railtie_namespace)
@@ -499,7 +499,7 @@ module Rails
paths["app/helpers"].existent
end
- # Returns the underlying rack application for this engine.
+ # Returns the underlying Rack application for this engine.
def app
@app || @app_build_lock.synchronize {
@app ||= begin
@@ -549,7 +549,7 @@ module Rails
load(seed_file) if seed_file
end
- # Add configured load paths to ruby load paths and remove duplicates.
+ # Add configured load paths to Ruby's load path, and remove duplicate entries.
initializer :set_load_path, before: :bootstrap_hook do
_all_load_paths.reverse_each do |path|
$LOAD_PATH.unshift(path) if File.directory?(path)
@@ -573,7 +573,7 @@ module Rails
end
initializer :add_routing_paths do |app|
- routing_paths = self.paths["config/routes.rb"].existent
+ routing_paths = paths["config/routes.rb"].existent
if routes? || routing_paths.any?
app.routes_reloader.paths.unshift(*routing_paths)
@@ -643,23 +643,24 @@ module Rails
protected
- def load_config_initializer(initializer)
- ActiveSupport::Notifications.instrument("load_config_initializer.railties", initializer: initializer) do
- load(initializer)
- end
- end
-
def run_tasks_blocks(*) #:nodoc:
super
paths["lib/tasks"].existent.sort.each { |ext| load(ext) }
end
- def has_migrations? #:nodoc:
+ private
+
+ def load_config_initializer(initializer) # :doc:
+ ActiveSupport::Notifications.instrument("load_config_initializer.railties", initializer: initializer) do
+ load(initializer)
+ end
+ end
+
+ def has_migrations?
paths["db/migrate"].existent.any?
end
def self.find_root_with_flag(flag, root_path, default = nil) #:nodoc:
-
while root_path && File.directory?(root_path) && !File.exist?("#{root_path}/#{flag}")
parent = File.dirname(root_path)
root_path = parent != root_path && parent
@@ -671,24 +672,22 @@ module Rails
Pathname.new File.realpath root
end
- def default_middleware_stack #:nodoc:
+ def default_middleware_stack
ActionDispatch::MiddlewareStack.new
end
- def _all_autoload_once_paths #:nodoc:
+ def _all_autoload_once_paths
config.autoload_once_paths
end
- def _all_autoload_paths #:nodoc:
+ def _all_autoload_paths
@_all_autoload_paths ||= (config.autoload_paths + config.eager_load_paths + config.autoload_once_paths).uniq
end
- def _all_load_paths #:nodoc:
+ def _all_load_paths
@_all_load_paths ||= (config.paths.load_paths + _all_autoload_paths).uniq
end
- private
-
def build_request(env)
env.merge!(env_config)
req = ActionDispatch::Request.new env
diff --git a/railties/lib/rails/engine/commands.rb b/railties/lib/rails/engine/commands.rb
index a23ae44b0b..b9ef63243a 100644
--- a/railties/lib/rails/engine/commands.rb
+++ b/railties/lib/rails/engine/commands.rb
@@ -1,12 +1,7 @@
-require "rails/command"
+unless defined?(APP_PATH)
+ if File.exist?(File.expand_path("test/dummy/config/application.rb", ENGINE_ROOT))
+ APP_PATH = File.expand_path("test/dummy/config/application", ENGINE_ROOT)
+ end
+end
-aliases = {
- "g" => "generate",
- "d" => "destroy",
- "t" => "test"
-}
-
-command = ARGV.shift
-command = aliases[command] || command
-
-Rails::Command.invoke command, ARGV
+require "rails/commands"
diff --git a/railties/lib/rails/gem_version.rb b/railties/lib/rails/gem_version.rb
index 9c49e0655a..3174ffb0dc 100644
--- a/railties/lib/rails/gem_version.rb
+++ b/railties/lib/rails/gem_version.rb
@@ -8,7 +8,7 @@ module Rails
MAJOR = 5
MINOR = 1
TINY = 0
- PRE = "alpha"
+ PRE = "beta1"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end
diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb
index 67037106e5..3f1bf6a5bb 100644
--- a/railties/lib/rails/generators.rb
+++ b/railties/lib/rails/generators.rb
@@ -62,251 +62,255 @@ module Rails
stylesheets: true,
stylesheet_engine: :css,
scaffold_stylesheet: true,
+ system_tests: nil,
test_framework: false,
template_engine: :erb
}
}
- def self.configure!(config) #:nodoc:
- api_only! if config.api_only
- no_color! unless config.colorize_logging
- aliases.deep_merge! config.aliases
- options.deep_merge! config.options
- fallbacks.merge! config.fallbacks
- templates_path.concat config.templates
- templates_path.uniq!
- hide_namespaces(*config.hidden_namespaces)
- end
+ class << self
+ def configure!(config) #:nodoc:
+ api_only! if config.api_only
+ no_color! unless config.colorize_logging
+ aliases.deep_merge! config.aliases
+ options.deep_merge! config.options
+ fallbacks.merge! config.fallbacks
+ templates_path.concat config.templates
+ templates_path.uniq!
+ hide_namespaces(*config.hidden_namespaces)
+ end
- def self.templates_path #:nodoc:
- @templates_path ||= []
- end
+ def templates_path #:nodoc:
+ @templates_path ||= []
+ end
- def self.aliases #:nodoc:
- @aliases ||= DEFAULT_ALIASES.dup
- end
+ def aliases #:nodoc:
+ @aliases ||= DEFAULT_ALIASES.dup
+ end
- def self.options #:nodoc:
- @options ||= DEFAULT_OPTIONS.dup
- end
+ def options #:nodoc:
+ @options ||= DEFAULT_OPTIONS.dup
+ end
- # Hold configured generators fallbacks. If a plugin developer wants a
- # generator group to fallback to another group in case of missing generators,
- # they can add a fallback.
- #
- # For example, shoulda is considered a test_framework and is an extension
- # of test_unit. However, most part of shoulda generators are similar to
- # test_unit ones.
- #
- # Shoulda then can tell generators to search for test_unit generators when
- # some of them are not available by adding a fallback:
- #
- # Rails::Generators.fallbacks[:shoulda] = :test_unit
- def self.fallbacks
- @fallbacks ||= {}
- end
+ # Hold configured generators fallbacks. If a plugin developer wants a
+ # generator group to fallback to another group in case of missing generators,
+ # they can add a fallback.
+ #
+ # For example, shoulda is considered a test_framework and is an extension
+ # of test_unit. However, most part of shoulda generators are similar to
+ # test_unit ones.
+ #
+ # Shoulda then can tell generators to search for test_unit generators when
+ # some of them are not available by adding a fallback:
+ #
+ # Rails::Generators.fallbacks[:shoulda] = :test_unit
+ def fallbacks
+ @fallbacks ||= {}
+ end
- # 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 helpers and assets
- # so generators such as scaffold won't create them.
- def self.api_only!
- hide_namespaces "assets", "helper", "css", "js"
-
- options[:rails].merge!(
- api: true,
- assets: false,
- helper: false,
- template_engine: nil
- )
-
- if ARGV.first == "mailer"
- options[:rails].merge!(template_engine: :erb)
+ # 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 helpers and assets
+ # so generators such as scaffold won't create them.
+ def api_only!
+ hide_namespaces "assets", "helper", "css", "js"
+
+ options[:rails].merge!(
+ api: true,
+ assets: false,
+ helper: false,
+ template_engine: nil
+ )
+
+ if ARGV.first == "mailer"
+ options[:rails].merge!(template_engine: :erb)
+ end
end
- end
- # Remove the color from output.
- def self.no_color!
- Thor::Base.shell = Thor::Shell::Basic
- end
+ # Remove the color from output.
+ def no_color!
+ Thor::Base.shell = Thor::Shell::Basic
+ end
- # Returns an array of generator namespaces that are hidden.
- # Generator namespaces may be hidden for a variety of reasons.
- # Some are aliased such as "rails:migration" and can be
- # invoked with the shorter "migration", others are private to other generators
- # such as "css:scaffold".
- def self.hidden_namespaces
- @hidden_namespaces ||= begin
- orm = options[:rails][:orm]
- test = options[:rails][:test_framework]
- template = options[:rails][:template_engine]
- css = options[:rails][:stylesheet_engine]
-
- [
- "rails",
- "resource_route",
- "#{orm}:migration",
- "#{orm}:model",
- "#{test}:controller",
- "#{test}:helper",
- "#{test}:integration",
- "#{test}:mailer",
- "#{test}:model",
- "#{test}:scaffold",
- "#{test}:view",
- "#{test}:job",
- "#{template}:controller",
- "#{template}:scaffold",
- "#{template}:mailer",
- "#{css}:scaffold",
- "#{css}:assets",
- "css:assets",
- "css:scaffold"
- ]
+ # Returns an array of generator namespaces that are hidden.
+ # Generator namespaces may be hidden for a variety of reasons.
+ # Some are aliased such as "rails:migration" and can be
+ # invoked with the shorter "migration", others are private to other generators
+ # such as "css:scaffold".
+ def hidden_namespaces
+ @hidden_namespaces ||= begin
+ orm = options[:rails][:orm]
+ test = options[:rails][:test_framework]
+ template = options[:rails][:template_engine]
+ css = options[:rails][:stylesheet_engine]
+
+ [
+ "rails",
+ "resource_route",
+ "#{orm}:migration",
+ "#{orm}:model",
+ "#{test}:controller",
+ "#{test}:helper",
+ "#{test}:integration",
+ "#{test}:system",
+ "#{test}:mailer",
+ "#{test}:model",
+ "#{test}:scaffold",
+ "#{test}:view",
+ "#{test}:job",
+ "#{template}:controller",
+ "#{template}:scaffold",
+ "#{template}:mailer",
+ "#{css}:scaffold",
+ "#{css}:assets",
+ "css:assets",
+ "css:scaffold"
+ ]
+ end
end
- end
- class << self
def hide_namespaces(*namespaces)
hidden_namespaces.concat(namespaces)
end
alias hide_namespace hide_namespaces
- end
- # Show help message with available generators.
- def self.help(command = "generate")
- puts "Usage: rails #{command} GENERATOR [args] [options]"
- puts
- puts "General options:"
- puts " -h, [--help] # Print generator's options and usage"
- puts " -p, [--pretend] # Run but do not make any changes"
- puts " -f, [--force] # Overwrite files that already exist"
- puts " -s, [--skip] # Skip files that already exist"
- puts " -q, [--quiet] # Suppress status output"
- puts
- puts "Please choose a generator below."
- puts
-
- print_generators
- end
-
- def self.public_namespaces
- lookup!
- subclasses.map(&:namespace)
- end
-
- def self.print_generators
- sorted_groups.each { |b, n| print_list(b, n) }
- end
+ # Show help message with available generators.
+ def help(command = "generate")
+ puts "Usage: rails #{command} GENERATOR [args] [options]"
+ puts
+ puts "General options:"
+ puts " -h, [--help] # Print generator's options and usage"
+ puts " -p, [--pretend] # Run but do not make any changes"
+ puts " -f, [--force] # Overwrite files that already exist"
+ puts " -s, [--skip] # Skip files that already exist"
+ puts " -q, [--quiet] # Suppress status output"
+ puts
+ puts "Please choose a generator below."
+ puts
+
+ print_generators
+ end
- def self.sorted_groups
- namespaces = public_namespaces
- namespaces.sort!
+ def public_namespaces
+ lookup!
+ subclasses.map(&:namespace)
+ end
- groups = Hash.new { |h, k| h[k] = [] }
- namespaces.each do |namespace|
- base = namespace.split(":").first
- groups[base] << namespace
+ def print_generators
+ sorted_groups.each { |b, n| print_list(b, n) }
end
- rails = groups.delete("rails")
- rails.map! { |n| n.sub(/^rails:/, "") }
- rails.delete("app")
- rails.delete("plugin")
+ def sorted_groups
+ namespaces = public_namespaces
+ namespaces.sort!
- hidden_namespaces.each { |n| groups.delete(n.to_s) }
+ groups = Hash.new { |h, k| h[k] = [] }
+ namespaces.each do |namespace|
+ base = namespace.split(":").first
+ groups[base] << namespace
+ end
- [[ "rails", rails ]] + groups.sort.to_a
- end
+ rails = groups.delete("rails")
+ rails.map! { |n| n.sub(/^rails:/, "") }
+ rails.delete("app")
+ rails.delete("plugin")
+ rails.delete("encrypted_secrets")
- # Rails finds namespaces similar to thor, it only adds one rule:
- #
- # Generators names must end with "_generator.rb". This is required because Rails
- # looks in load paths and loads the generator just before it's going to be used.
- #
- # find_by_namespace :webrat, :rails, :integration
- #
- # Will search for the following generators:
- #
- # "rails:webrat", "webrat:integration", "webrat"
- #
- # Notice that "rails:generators:webrat" could be loaded as well, what
- # Rails looks for is the first and last parts of the namespace.
- def self.find_by_namespace(name, base = nil, context = nil) #:nodoc:
- lookups = []
- lookups << "#{base}:#{name}" if base
- lookups << "#{name}:#{context}" if context
-
- unless base || context
- unless name.to_s.include?(?:)
- lookups << "#{name}:#{name}"
- lookups << "rails:#{name}"
- end
- lookups << "#{name}"
+ hidden_namespaces.each { |n| groups.delete(n.to_s) }
+
+ [[ "rails", rails ]] + groups.sort.to_a
end
- lookup(lookups)
+ # Rails finds namespaces similar to Thor, it only adds one rule:
+ #
+ # Generators names must end with "_generator.rb". This is required because Rails
+ # looks in load paths and loads the generator just before it's going to be used.
+ #
+ # find_by_namespace :webrat, :rails, :integration
+ #
+ # Will search for the following generators:
+ #
+ # "rails:webrat", "webrat:integration", "webrat"
+ #
+ # Notice that "rails:generators:webrat" could be loaded as well, what
+ # Rails looks for is the first and last parts of the namespace.
+ def find_by_namespace(name, base = nil, context = nil) #:nodoc:
+ lookups = []
+ lookups << "#{base}:#{name}" if base
+ lookups << "#{name}:#{context}" if context
+
+ unless base || context
+ unless name.to_s.include?(?:)
+ lookups << "#{name}:#{name}"
+ lookups << "rails:#{name}"
+ end
+ lookups << "#{name}"
+ end
- namespaces = Hash[subclasses.map { |klass| [klass.namespace, klass] }]
- lookups.each do |namespace|
+ lookup(lookups)
- klass = namespaces[namespace]
- return klass if klass
- end
+ namespaces = Hash[subclasses.map { |klass| [klass.namespace, klass] }]
+ lookups.each do |namespace|
- invoke_fallbacks_for(name, base) || invoke_fallbacks_for(context, name)
- end
+ klass = namespaces[namespace]
+ return klass if klass
+ end
- # Receives a namespace, arguments and the behavior to invoke the generator.
- # It's used as the default entry point for generate, destroy and update
- # commands.
- def self.invoke(namespace, args = ARGV, config = {})
- names = namespace.to_s.split(":")
- if klass = find_by_namespace(names.pop, names.any? && names.join(":"))
- args << "--help" if args.empty? && klass.arguments.any?(&:required?)
- klass.start(args, config)
- else
- options = sorted_groups.flat_map(&:last)
- suggestions = options.sort_by { |suggested| levenshtein_distance(namespace.to_s, suggested) }.first(3)
- msg = "Could not find generator '#{namespace}'. "
- msg << "Maybe you meant #{ suggestions.map { |s| "'#{s}'" }.to_sentence(last_word_connector: " or ", locale: :en) }\n"
- msg << "Run `rails generate --help` for more options."
- puts msg
+ invoke_fallbacks_for(name, base) || invoke_fallbacks_for(context, name)
end
- end
- protected
- def self.print_list(base, namespaces)
- namespaces = namespaces.reject { |n| hidden_namespaces.include?(n) }
- super
+ # Receives a namespace, arguments and the behavior to invoke the generator.
+ # It's used as the default entry point for generate, destroy and update
+ # commands.
+ def invoke(namespace, args = ARGV, config = {})
+ names = namespace.to_s.split(":")
+ if klass = find_by_namespace(names.pop, names.any? && names.join(":"))
+ args << "--help" if args.empty? && klass.arguments.any?(&:required?)
+ klass.start(args, config)
+ else
+ options = sorted_groups.flat_map(&:last)
+ suggestions = options.sort_by { |suggested| levenshtein_distance(namespace.to_s, suggested) }.first(3)
+ msg = "Could not find generator '#{namespace}'. "
+ msg << "Maybe you meant #{ suggestions.map { |s| "'#{s}'" }.to_sentence(last_word_connector: " or ", locale: :en) }\n"
+ msg << "Run `rails generate --help` for more options."
+ puts msg
+ end
end
- # Try fallbacks for the given base.
- def self.invoke_fallbacks_for(name, base) #:nodoc:
- return nil unless base && fallbacks[base.to_sym]
- invoked_fallbacks = []
-
- Array(fallbacks[base.to_sym]).each do |fallback|
- next if invoked_fallbacks.include?(fallback)
- invoked_fallbacks << fallback
+ private
- klass = find_by_namespace(name, fallback)
- return klass if klass
+ def print_list(base, namespaces) # :doc:
+ namespaces = namespaces.reject { |n| hidden_namespaces.include?(n) }
+ super
end
- nil
- end
+ # Try fallbacks for the given base.
+ def invoke_fallbacks_for(name, base)
+ return nil unless base && fallbacks[base.to_sym]
+ invoked_fallbacks = []
- def self.command_type
- @command_type ||= "generator"
- end
+ Array(fallbacks[base.to_sym]).each do |fallback|
+ next if invoked_fallbacks.include?(fallback)
+ invoked_fallbacks << fallback
- def self.lookup_paths
- @lookup_paths ||= %w( rails/generators generators )
- end
+ klass = find_by_namespace(name, fallback)
+ return klass if klass
+ end
- def self.file_lookup_paths
- @file_lookup_paths ||= [ "{#{lookup_paths.join(',')}}", "**", "*_generator.rb" ]
- end
+ nil
+ end
+
+ def command_type # :doc:
+ @command_type ||= "generator"
+ end
+
+ def lookup_paths # :doc:
+ @lookup_paths ||= %w( rails/generators generators )
+ end
+
+ def file_lookup_paths # :doc:
+ @file_lookup_paths ||= [ "{#{lookup_paths.join(',')}}", "**", "*_generator.rb" ]
+ end
+ end
end
end
diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb
index 8a60560f86..0bd0615b7e 100644
--- a/railties/lib/rails/generators/actions.rb
+++ b/railties/lib/rails/generators/actions.rb
@@ -260,23 +260,23 @@ module Rails
@after_bundle_callbacks << block
end
- protected
+ private
# Define log for backwards compatibility. If just one argument is sent,
# invoke say, otherwise invoke say_status. Differently from say and
# similarly to say_status, this method respects the quiet? option given.
- def log(*args)
+ def log(*args) # :doc:
if args.size == 1
say args.first.to_s unless options.quiet?
else
- args << (self.behavior == :invoke ? :green : :red)
+ args << (behavior == :invoke ? :green : :red)
say_status(*args)
end
end
# Runs the supplied command using either "rake ..." or "rails ..."
# based on the executor parameter provided.
- def execute_command(executor, command, options = {})
+ def execute_command(executor, command, options = {}) # :doc:
log executor, command
env = options[:env] || ENV["RAILS_ENV"] || "development"
sudo = options[:sudo] && !Gem.win_platform? ? "sudo " : ""
@@ -284,7 +284,7 @@ module Rails
end
# Add an extension to the given name based on the platform.
- def extify(name)
+ def extify(name) # :doc:
if Gem.win_platform?
"#{name}.bat"
else
@@ -294,7 +294,7 @@ module Rails
# Surround string with single quotes if there is no quotes.
# Otherwise fall back to double quotes
- def quote(value)
+ def quote(value) # :doc:
return value.inspect unless value.is_a? String
if value.include?("'")
diff --git a/railties/lib/rails/generators/actions/create_migration.rb b/railties/lib/rails/generators/actions/create_migration.rb
index 587c61fd42..d06609e91e 100644
--- a/railties/lib/rails/generators/actions/create_migration.rb
+++ b/railties/lib/rails/generators/actions/create_migration.rb
@@ -37,9 +37,9 @@ module Rails
end
alias :exists? :existing_migration
- protected
+ private
- def on_conflict_behavior
+ def on_conflict_behavior # :doc:
options = base.options.merge(config)
if identical?
say_status :identical, :blue, relative_existing_migration
@@ -54,13 +54,13 @@ module Rails
say_status :skip, :yellow
else
say_status :conflict, :red
- raise Error, "Another migration is already named #{migration_file_name}: " +
- "#{existing_migration}. Use --force to replace this migration " +
+ raise Error, "Another migration is already named #{migration_file_name}: " \
+ "#{existing_migration}. Use --force to replace this migration " \
"or --skip to ignore conflicted file."
end
end
- def say_status(status, color, message = relative_destination)
+ def say_status(status, color, message = relative_destination) # :doc:
base.shell.say_status(status, message, color) if config[:verbose]
end
end
diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb
index 576c36fc86..56e286f259 100644
--- a/railties/lib/rails/generators/app_base.rb
+++ b/railties/lib/rails/generators/app_base.rb
@@ -33,7 +33,7 @@ module Rails
class_option :javascript, type: :string, aliases: "-j",
desc: "Preconfigure for selected JavaScript library"
- class_option :webpack, type: :boolean, default: false,
+ class_option :webpack, type: :string, default: nil,
desc: "Preconfigure for app-like JavaScript with Webpack"
class_option :skip_yarn, type: :boolean, default: false,
@@ -42,9 +42,6 @@ module Rails
class_option :skip_gemfile, type: :boolean, default: false,
desc: "Don't create a Gemfile"
- class_option :skip_bundle, type: :boolean, aliases: "-B", default: false,
- desc: "Don't run bundle install"
-
class_option :skip_git, type: :boolean, aliases: "-G", default: false,
desc: "Skip .gitignore file"
@@ -85,6 +82,9 @@ module Rails
class_option :skip_test, type: :boolean, aliases: "-T", default: false,
desc: "Skip test files"
+ class_option :skip_system_test, type: :boolean, default: false,
+ desc: "Skip system test files"
+
class_option :dev, type: :boolean, default: false,
desc: "Setup the #{name} with Gemfile pointing to your Rails checkout"
@@ -108,9 +108,9 @@ module Rails
convert_database_option_for_jruby
end
- protected
+ private
- def gemfile_entry(name, *args)
+ def gemfile_entry(name, *args) # :doc:
options = args.extract_options!
version = args.first
github = options[:github]
@@ -126,7 +126,7 @@ module Rails
self
end
- def gemfile_entries
+ def gemfile_entries # :doc:
[rails_gemfile_entry,
database_gemfile_entry,
webserver_gemfile_entry,
@@ -139,13 +139,13 @@ module Rails
@extra_entries].flatten.find_all(&@gem_filter)
end
- def add_gem_entry_filter
+ def add_gem_entry_filter # :doc:
@gem_filter = lambda { |next_filter, entry|
yield(entry) && next_filter.call(entry)
}.curry[@gem_filter]
end
- def builder
+ def builder # :doc:
@builder ||= begin
builder_class = get_builder_class
builder_class.include(ActionMethods)
@@ -153,24 +153,24 @@ module Rails
end
end
- def build(meth, *args)
+ def build(meth, *args) # :doc:
builder.send(meth, *args) if builder.respond_to?(meth)
end
- def create_root
+ def create_root # :doc:
valid_const?
empty_directory "."
FileUtils.cd(destination_root) unless options[:pretend]
end
- def apply_rails_template
+ def apply_rails_template # :doc:
apply rails_template if rails_template
rescue Thor::Error, LoadError, Errno::ENOENT => e
raise Error, "The template [#{rails_template}] could not be loaded. Error: #{e}"
end
- def set_default_accessors!
+ def set_default_accessors! # :doc:
self.destination_root = File.expand_path(app_path, destination_root)
self.rails_template = \
case options[:template]
@@ -183,32 +183,32 @@ module Rails
end
end
- def database_gemfile_entry
+ def database_gemfile_entry # :doc:
return [] if options[:skip_active_record]
gem_name, gem_version = gem_for_database
GemfileEntry.version gem_name, gem_version,
"Use #{options[:database]} as the database for Active Record"
end
- def webserver_gemfile_entry
+ def webserver_gemfile_entry # :doc:
return [] if options[:skip_puma]
comment = "Use Puma as the app server"
- GemfileEntry.new("puma", "~> 3.0", comment)
+ GemfileEntry.new("puma", "~> 3.7", comment)
end
- def include_all_railties?
+ def include_all_railties? # :doc:
options.values_at(:skip_active_record, :skip_action_mailer, :skip_test, :skip_sprockets, :skip_action_cable).none?
end
- def comment_if(value)
+ def comment_if(value) # :doc:
options[value] ? "# " : ""
end
- def keeps?
+ def keeps? # :doc:
!options[:skip_keeps]
end
- def sqlite3?
+ def sqlite3? # :doc:
!options[:skip_active_record] && options[:database] == "sqlite3"
end
@@ -263,14 +263,13 @@ module Rails
end
def rails_version_specifier(gem_version = Rails.gem_version)
- if gem_version.prerelease?
- next_series = gem_version
- next_series = next_series.bump while next_series.segments.size > 2
-
- [">= #{gem_version}", "< #{next_series}"]
- elsif gem_version.segments.size == 3
+ if gem_version.segments.size == 3 || gem_version.release.segments.size == 3
+ # ~> 1.2.3
+ # ~> 1.2.3.pre4
"~> #{gem_version}"
else
+ # ~> 1.2.3, >= 1.2.3.4
+ # ~> 1.2.3, >= 1.2.3.4.pre5
patch = gem_version.segments[0, 3].join(".")
["~> #{patch}", ">= #{gem_version}"]
end
@@ -323,7 +322,7 @@ module Rails
return [] unless options[:webpack]
comment = "Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker"
- GemfileEntry.github "webpacker", "rails/webpacker", nil, comment
+ GemfileEntry.new "webpacker", nil, comment
end
def jbuilder_gemfile_entry
@@ -426,7 +425,10 @@ module Rails
end
def run_webpack
- rails_command "webpacker:install" if options[:webpack]
+ if !(webpack = options[:webpack]).nil?
+ rails_command "webpacker:install"
+ rails_command "webpacker:install:#{webpack}" unless webpack == "webpack"
+ end
end
def generate_spring_binstubs
diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb
index c707bbfcbf..a650c52626 100644
--- a/railties/lib/rails/generators/base.rb
+++ b/railties/lib/rails/generators/base.rb
@@ -239,11 +239,11 @@ module Rails
end
end
- protected
+ private
# Check whether the given class names are already taken by user
# application or Ruby on Rails.
- def class_collisions(*class_names) #:nodoc:
+ def class_collisions(*class_names)
return unless behavior == :invoke
class_names.flatten.each do |class_name|
@@ -256,15 +256,15 @@ module Rails
last = extract_last_module(nesting)
if last && last.const_defined?(last_name.camelize, false)
- raise Error, "The name '#{class_name}' is either already used in your application " <<
- "or reserved by Ruby on Rails. Please choose an alternative and run " <<
+ raise Error, "The name '#{class_name}' is either already used in your application " \
+ "or reserved by Ruby on Rails. Please choose an alternative and run " \
"this generator again."
end
end
end
# Takes in an array of nested modules and extracts the last module
- def extract_last_module(nesting)
+ def extract_last_module(nesting) # :doc:
nesting.inject(Object) do |last_module, nest|
break unless last_module.const_defined?(nest, false)
last_module.const_get(nest)
@@ -272,12 +272,12 @@ module Rails
end
# Use Rails default banner.
- def self.banner
+ def self.banner # :doc:
"rails generate #{namespace.sub(/^rails:/, '')} #{arguments.map(&:usage).join(' ')} [options]".gsub(/\s+/, " ")
end
# Sets the base_name taking into account the current class namespace.
- def self.base_name
+ def self.base_name # :doc:
@base_name ||= begin
if base = name.to_s.split("::").first
base.underscore
@@ -287,7 +287,7 @@ module Rails
# Removes the namespaces and get the generator name. For example,
# Rails::Generators::ModelGenerator will return "model" as generator name.
- def self.generator_name
+ def self.generator_name # :doc:
@generator_name ||= begin
if generator = name.to_s.split("::").last
generator.sub!(/Generator$/, "")
@@ -298,18 +298,18 @@ module Rails
# Returns the default value for the option name given doing a lookup in
# Rails::Generators.options.
- def self.default_value_for_option(name, options)
+ def self.default_value_for_option(name, options) # :doc:
default_for_option(Rails::Generators.options, name, options, options[:default])
end
# Returns default aliases for the option name given doing a lookup in
# Rails::Generators.aliases.
- def self.default_aliases_for_option(name, options)
+ def self.default_aliases_for_option(name, options) # :doc:
default_for_option(Rails::Generators.aliases, name, options, options[:aliases])
end
# Returns default for the option name given doing a lookup in config.
- def self.default_for_option(config, name, options, default)
+ def self.default_for_option(config, name, options, default) # :doc:
if generator_name && (c = config[generator_name.to_sym]) && c.key?(name)
c[name]
elsif base_name && (c = config[base_name.to_sym]) && c.key?(name)
@@ -331,7 +331,7 @@ module Rails
def self.prepare_for_invocation(name, value) #:nodoc:
return super unless value.is_a?(String) || value.is_a?(Symbol)
- if value && constants = self.hooks[name]
+ if value && constants = hooks[name]
value = name if TrueClass === value
Rails::Generators.find_by_namespace(value, *constants)
elsif klass = Rails::Generators.find_by_namespace(value)
@@ -343,7 +343,7 @@ module Rails
# Small macro to add ruby as an option to the generator with proper
# default value plus an instance helper method called shebang.
- def self.add_shebang_option!
+ def self.add_shebang_option! # :doc:
class_option :ruby, type: :string, aliases: "-r", default: Thor::Util.ruby_command,
desc: "Path to the Ruby binary of your choice", banner: "PATH"
@@ -361,7 +361,7 @@ module Rails
}
end
- def self.usage_path
+ def self.usage_path # :doc:
paths = [
source_root && File.expand_path("../USAGE", source_root),
default_generator_root && File.join(default_generator_root, "USAGE")
@@ -369,7 +369,7 @@ module Rails
paths.compact.detect { |path| File.exist? path }
end
- def self.default_generator_root
+ def self.default_generator_root # :doc:
path = File.expand_path(File.join(base_name, generator_name), base_root)
path if File.exist?(path)
end
diff --git a/railties/lib/rails/generators/erb.rb b/railties/lib/rails/generators/erb.rb
index d01502002f..d5e326d6ee 100644
--- a/railties/lib/rails/generators/erb.rb
+++ b/railties/lib/rails/generators/erb.rb
@@ -3,7 +3,7 @@ require "rails/generators/named_base"
module Erb # :nodoc:
module Generators # :nodoc:
class Base < Rails::Generators::NamedBase #:nodoc:
- protected
+ private
def formats
[format]
diff --git a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb
index f150240908..3f1d9932f6 100644
--- a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb
+++ b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb
@@ -9,10 +9,10 @@ module Erb # :nodoc:
view_base_path = File.join("app/views", class_path, file_name + "_mailer")
empty_directory view_base_path
- if self.behavior == :invoke
+ if behavior == :invoke
formats.each do |format|
layout_path = File.join("app/views/layouts", class_path, filename_with_extensions("mailer", format))
- template filename_with_extensions(:layout, format), layout_path
+ template filename_with_extensions(:layout, format), layout_path unless File.exist?(layout_path)
end
end
@@ -26,7 +26,7 @@ module Erb # :nodoc:
end
end
- protected
+ private
def formats
[:text, :html]
diff --git a/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb
index 154d85f381..0d77ef21da 100644
--- a/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb
+++ b/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb
@@ -21,7 +21,7 @@ module Erb # :nodoc:
end
end
- protected
+ private
def available_views
%w(index edit show new _form)
diff --git a/railties/lib/rails/generators/migration.rb b/railties/lib/rails/generators/migration.rb
index 0d63b9a5c9..82481169c3 100644
--- a/railties/lib/rails/generators/migration.rb
+++ b/railties/lib/rails/generators/migration.rb
@@ -35,7 +35,7 @@ module Rails
end
def set_migration_assigns!(destination)
- destination = File.expand_path(destination, self.destination_root)
+ destination = File.expand_path(destination, destination_root)
migration_dir = File.dirname(destination)
@migration_number = self.class.next_migration_number(migration_dir)
diff --git a/railties/lib/rails/generators/named_base.rb b/railties/lib/rails/generators/named_base.rb
index 45f2fba5b9..02557b098a 100644
--- a/railties/lib/rails/generators/named_base.rb
+++ b/railties/lib/rails/generators/named_base.rb
@@ -32,145 +32,149 @@ module Rails
end
end
+ # TODO Change this to private once we've dropped Ruby 2.2 support.
+ # Workaround for Ruby 2.2 "private attribute?" warning.
protected
attr_reader :file_name
+ private
+
# FIXME: We are avoiding to use alias because a bug on thor that make
# this method public and add it to the task list.
- def singular_name
+ def singular_name # :doc:
file_name
end
# Wrap block with namespace of current application
# if namespace exists and is not skipped
- def module_namespacing(&block)
+ def module_namespacing(&block) # :doc:
content = capture(&block)
content = wrap_with_namespace(content) if namespaced?
concat(content)
end
- def indent(content, multiplier = 2)
+ 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)
+ def wrap_with_namespace(content) # :doc:
content = indent(content).chomp
"module #{namespace.name}\n#{content}\nend\n"
end
- def inside_template
+ def inside_template # :doc:
@inside_template = true
yield
ensure
@inside_template = false
end
- def inside_template?
+ def inside_template? # :doc:
@inside_template
end
- def namespace
+ def namespace # :doc:
Rails::Generators.namespace
end
- def namespaced?
+ def namespaced? # :doc:
!options[:skip_namespace] && namespace
end
- def file_path
+ def namespace_dirs
+ @namespace_dirs ||= namespace.name.split("::").map(&:underscore)
+ end
+
+ def file_path # :doc:
@file_path ||= (class_path + [file_name]).join("/")
end
- def class_path
+ def class_path # :doc:
inside_template? || !namespaced? ? regular_class_path : namespaced_class_path
end
- def regular_class_path
+ def regular_class_path # :doc:
@class_path
end
- def namespaced_file_path
- @namespaced_file_path ||= namespaced_class_path.join("/")
- end
-
- def namespaced_class_path
- @namespaced_class_path ||= [namespaced_path] + @class_path
+ def namespaced_class_path # :doc:
+ @namespaced_class_path ||= namespace_dirs + @class_path
end
- def namespaced_path
- @namespaced_path ||= namespace.name.split("::").first.underscore
+ def namespaced_path # :doc:
+ @namespaced_path ||= namespace_dirs.join("/")
end
- def class_name
+ def class_name # :doc:
(class_path + [file_name]).map!(&:camelize).join("::")
end
- def human_name
+ def human_name # :doc:
@human_name ||= singular_name.humanize
end
- def plural_name
+ def plural_name # :doc:
@plural_name ||= singular_name.pluralize
end
- def i18n_scope
+ def i18n_scope # :doc:
@i18n_scope ||= file_path.tr("/", ".")
end
- def table_name
+ def table_name # :doc:
@table_name ||= begin
base = pluralize_table_names? ? plural_name : singular_name
(class_path + [base]).join("_")
end
end
- def uncountable?
+ def uncountable? # :doc:
singular_name == plural_name
end
- def index_helper
+ def index_helper # :doc:
uncountable? ? "#{plural_table_name}_index" : plural_table_name
end
- def show_helper
+ def show_helper # :doc:
"#{singular_table_name}_url(@#{singular_table_name})"
end
- def edit_helper
+ def edit_helper # :doc:
"edit_#{show_helper}"
end
- def new_helper
+ def new_helper # :doc:
"new_#{singular_table_name}_url"
end
- def singular_table_name
+ def singular_table_name # :doc:
@singular_table_name ||= (pluralize_table_names? ? table_name.singularize : table_name)
end
- def plural_table_name
+ def plural_table_name # :doc:
@plural_table_name ||= (pluralize_table_names? ? table_name : table_name.pluralize)
end
- def plural_file_name
+ def plural_file_name # :doc:
@plural_file_name ||= file_name.pluralize
end
- def fixture_file_name
+ def fixture_file_name # :doc:
@fixture_file_name ||= (pluralize_table_names? ? plural_file_name : file_name)
end
- def route_url
+ def route_url # :doc:
@route_url ||= class_path.collect { |dname| "/" + dname }.join + "/" + plural_file_name
end
- def url_helper_prefix
+ def url_helper_prefix # :doc:
@url_helper_prefix ||= (class_path + [file_name]).join("_")
end
# Tries to retrieve the application name or simply return application.
- def application_name
+ def application_name # :doc:
if defined?(Rails) && Rails.application
Rails.application.class.name.split("::").first.underscore
else
@@ -178,20 +182,20 @@ module Rails
end
end
- def assign_names!(name) #:nodoc:
+ def assign_names!(name)
@class_path = name.include?("/") ? name.split("/") : name.split("::")
@class_path.map!(&:underscore)
@file_name = @class_path.pop
end
# Convert attributes array into GeneratedAttribute objects.
- def parse_attributes! #:nodoc:
+ def parse_attributes!
self.attributes = (attributes || []).map do |attr|
Rails::Generators::GeneratedAttribute.parse(attr)
end
end
- def attributes_names
+ def attributes_names # :doc:
@attributes_names ||= attributes.each_with_object([]) do |a, names|
names << a.column_name
names << "password_confirmation" if a.password_digest?
@@ -199,11 +203,11 @@ module Rails
end
end
- def pluralize_table_names?
+ def pluralize_table_names? # :doc:
!defined?(ActiveRecord::Base) || ActiveRecord::Base.pluralize_table_names
end
- def mountable_engine?
+ def mountable_engine? # :doc:
defined?(ENGINE_ROOT) && namespaced?
end
@@ -217,9 +221,9 @@ module Rails
# If the generator is invoked with class name Admin, it will check for
# the presence of "AdminDecorator".
#
- def self.check_class_collision(options = {})
+ def self.check_class_collision(options = {}) # :doc:
define_method :check_class_collision do
- name = if self.respond_to?(:controller_class_name) # for ScaffoldBase
+ name = if respond_to?(:controller_class_name) # for ScaffoldBase
controller_class_name
else
class_name
diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb
index 19d3ba2f0f..442258c9d1 100644
--- a/railties/lib/rails/generators/rails/app/app_generator.rb
+++ b/railties/lib/rails/generators/rails/app/app_generator.rb
@@ -32,6 +32,14 @@ module Rails
# This allows you to override entire operations, like the creation of the
# Gemfile, README, or JavaScript files, without needing to know exactly
# what those operations do so you can create another template action.
+ #
+ # class CustomAppBuilder < Rails::AppBuilder
+ # def test
+ # @generator.gem "rspec-rails", group: [:development, :test]
+ # run "bundle install"
+ # generate "rspec:install"
+ # end
+ # end
class AppBuilder
def rakefile
template "Rakefile"
@@ -53,6 +61,12 @@ module Rails
template "gitignore", ".gitignore"
end
+ def version_control
+ if !options[:skip_git] && !options[:pretend]
+ run "git init"
+ end
+ end
+
def app
directory "app"
@@ -144,6 +158,12 @@ module Rails
template "test/test_helper.rb"
end
+ def system_test
+ empty_directory_with_keep_file "test/system"
+
+ template "test/application_system_test_case.rb"
+ end
+
def tmp
empty_directory_with_keep_file "tmp"
empty_directory "tmp/cache"
@@ -154,7 +174,7 @@ module Rails
empty_directory_with_keep_file "vendor"
unless options[:skip_yarn]
- template "package.json", "vendor/package.json"
+ template "package.json"
end
end
end
@@ -175,13 +195,12 @@ module Rails
class_option :api, type: :boolean,
desc: "Preconfigure smaller stack for API only apps"
+ class_option :skip_bundle, type: :boolean, aliases: "-B", default: false,
+ desc: "Don't run bundle install"
+
def initialize(*args)
super
- unless app_path
- raise Error, "Application name should be provided in arguments. For details run: rails --help"
- end
-
if !options[:skip_active_record] && !DATABASES.include?(options[:database])
raise Error, "Invalid value for --database option. Supported for preconfiguration are: #{DATABASES.join(", ")}."
end
@@ -202,6 +221,7 @@ module Rails
build(:configru)
build(:gitignore) unless options[:skip_git]
build(:gemfile) unless options[:skip_gemfile]
+ build(:version_control)
end
def create_app_files
@@ -256,6 +276,10 @@ module Rails
build(:test) unless options[:skip_test]
end
+ def create_system_test_files
+ build(:system_test) unless options[:skip_system_test] || options[:skip_test] || options[:api]
+ end
+
def create_tmp_files
build(:tmp)
end
@@ -264,7 +288,7 @@ module Rails
build(:vendor)
if options[:skip_yarn]
- remove_file "vendor/package.json"
+ remove_file "package.json"
end
end
@@ -320,7 +344,6 @@ module Rails
def delete_action_mailer_files_skipping_action_mailer
if options[:skip_action_mailer]
- remove_file "app/mailers/application_mailer.rb"
remove_file "app/views/layouts/mailer.html.erb"
remove_file "app/views/layouts/mailer.text.erb"
remove_dir "app/mailers"
@@ -348,8 +371,8 @@ module Rails
end
end
- def delete_bin_yarn_if_api_option
- remove_file "bin/yarn" if options[:api]
+ def delete_bin_yarn_if_skip_yarn_option
+ remove_file "bin/yarn" if options[:skip_yarn]
end
def finish_template
@@ -363,12 +386,12 @@ module Rails
@after_bundle_callbacks.each(&:call)
end
- protected
-
def self.banner
"rails new #{arguments.map(&:usage).join(' ')} [options]"
end
+ private
+
# Define file as an alias to create_file for backwards compatibility.
def file(*args, &block)
create_file(*args, &block)
diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile
index f1015b16d5..b082d70cba 100644
--- a/railties/lib/rails/generators/rails/app/templates/Gemfile
+++ b/railties/lib/rails/generators/rails/app/templates/Gemfile
@@ -31,7 +31,12 @@ end
<% if RUBY_ENGINE == 'ruby' -%>
group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
- gem 'byebug', platform: :mri
+ gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
+ <%- unless options.skip_system_test? || options.api? -%>
+ # Adds support for Capybara system testing and selenium driver
+ gem 'capybara', '~> 2.7.0'
+ gem 'selenium-webdriver'
+ <%- end -%>
end
group :development do
diff --git a/railties/lib/rails/generators/rails/app/templates/bin/yarn b/railties/lib/rails/generators/rails/app/templates/bin/yarn
index 872438cecb..4ae896a8d3 100644
--- a/railties/lib/rails/generators/rails/app/templates/bin/yarn
+++ b/railties/lib/rails/generators/rails/app/templates/bin/yarn
@@ -1,4 +1,4 @@
-VENDOR_PATH = File.expand_path('../vendor', __dir__)
+VENDOR_PATH = File.expand_path('..', __dir__)
Dir.chdir(VENDOR_PATH) do
begin
exec "yarnpkg #{ARGV.join(" ")}"
diff --git a/railties/lib/rails/generators/rails/app/templates/config/cable.yml b/railties/lib/rails/generators/rails/app/templates/config/cable.yml
index 0bbde6f74f..1da4913082 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/cable.yml
+++ b/railties/lib/rails/generators/rails/app/templates/config/cable.yml
@@ -7,3 +7,4 @@ test:
production:
adapter: redis
url: redis://localhost:6379/1
+ channel_prefix: <%= app_name %>_production
diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml
index a2b2a64ba6..8bc8735a8e 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml
+++ b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml
@@ -1,4 +1,4 @@
-# MySQL. Versions 5.0 and up are supported.
+# MySQL. Versions 5.1.10 and up are supported.
#
# Install the MySQL driver:
# gem install activerecord-jdbcmysql-adapter
diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml
index d987cf303b..269af1470d 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml
+++ b/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml
@@ -1,4 +1,4 @@
-# MySQL. Versions 5.0 and up are supported.
+# MySQL. Versions 5.1.10 and up are supported.
#
# Install the MySQL driver
# gem install mysql2
diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml
index c223d6bc62..a21555e573 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml
+++ b/railties/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml
@@ -1,4 +1,4 @@
-# SQL Server (2005 or higher recommended)
+# SQL Server (2012 or higher recommended)
#
# Install the adapters and driver
# gem install tiny_tds
@@ -8,29 +8,12 @@
# gem 'tiny_tds'
# gem 'activerecord-sqlserver-adapter'
#
-# You should make sure freetds is configured correctly first.
-# freetds.conf contains host/port/protocol_versions settings.
-# http://freetds.schemamania.org/userguide/freetdsconf.htm
-#
-# A typical Microsoft server
-# [mssql]
-# host = mssqlserver.yourdomain.com
-# port = 1433
-# tds version = 7.1
-
-# If you can connect with "tsql -S servername", your basic FreeTDS installation is working.
-# 'man tsql' for more info
-# Set timeout to a larger number if valid queries against a live db fail
-#
default: &default
adapter: sqlserver
encoding: utf8
- pool: <%%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
- reconnect: false
- username: <%= app_name %>
- password:
- timeout: 25
- dataserver: from_freetds.conf
+ username: sa
+ password: <%= ENV['SA_PASSWORD'] %>
+ host: localhost
development:
<<: *default
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 7deab5dbb1..9c4a77fd1d 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
@@ -14,6 +14,11 @@ Rails.application.configure do
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
+ # Attempt to read encrypted secrets from `config/secrets.yml.enc`.
+ # Requires an encryption key in `ENV["RAILS_MASTER_KEY"]` or
+ # `config/secrets.yml.key`.
+ config.read_encrypted_secrets = true
+
# Disable serving static files from the `/public` folder by default since
# Apache or NGINX already handles this.
config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
@@ -88,7 +93,7 @@ Rails.application.configure do
if ENV["RAILS_LOG_TO_STDOUT"].present?
logger = ActiveSupport::Logger.new(STDOUT)
logger.formatter = config.log_formatter
- config.logger = ActiveSupport::TaggedLogging.new(logger)
+ config.logger = ActiveSupport::TaggedLogging.new(logger)
end
<%- unless options.skip_active_record? -%>
diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt
index f5d03fb117..51196ae743 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt
@@ -7,7 +7,7 @@ Rails.application.config.assets.version = '1.0'
# Rails.application.config.assets.paths << Emoji.images_path
<%- unless options[:skip_yarn] -%>
# Add Yarn node_modules folder to the asset load path.
-Rails.application.config.assets.paths << Rails.root.join('vendor/node_modules')
+Rails.application.config.assets.paths << Rails.root.join('node_modules')
<%- end -%>
# Precompile additional assets.
diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults.rb.tt
index 3ad3eba98a..bd844f0503 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults.rb.tt
@@ -24,9 +24,6 @@ ActiveSupport.to_time_preserves_timezone = <%= options[:update] ? false : true %
# Require `belongs_to` associations by default. Previous versions had false.
Rails.application.config.active_record.belongs_to_required_by_default = <%= options[:update] ? false : true %>
<%- end -%>
-
-# Do not halt callback chains when a callback returns false. Previous versions had true.
-ActiveSupport.halt_callback_chains_on_return_false = <%= options[:update] ? true : false %>
<%- unless options[:update] -%>
# Configure SSL options to enable HSTS with subdomains. Previous versions had false.
diff --git a/railties/lib/rails/generators/rails/app/templates/config/locales/en.yml b/railties/lib/rails/generators/rails/app/templates/config/locales/en.yml
index 0653957166..decc5a8573 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/locales/en.yml
+++ b/railties/lib/rails/generators/rails/app/templates/config/locales/en.yml
@@ -16,6 +16,16 @@
#
# This would use the information in config/locales/es.yml.
#
+# The following keys must be escaped otherwise they will not be retrieved by
+# the default I18n backend:
+#
+# true, false, on, off, yes, no
+#
+# Instead, surround them with single quotes.
+#
+# en:
+# 'true': 'foo'
+#
# To learn more, please read the Rails Internationalization guide
# available at http://guides.rubyonrails.org/i18n.html.
diff --git a/railties/lib/rails/generators/rails/app/templates/config/secrets.yml b/railties/lib/rails/generators/rails/app/templates/config/secrets.yml
index 8e995a5df1..816efcc5b1 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/secrets.yml
+++ b/railties/lib/rails/generators/rails/app/templates/config/secrets.yml
@@ -23,8 +23,10 @@ development:
test:
secret_key_base: <%= app_secret %>
-# Do not keep production secrets in the repository,
-# instead read values from the environment.
+# Do not keep production secrets in the unencrypted secrets file.
+# Instead, either read values from the environment.
+# Or, use `bin/rails secrets:setup` to configure encrypted secrets
+# and move the `production:` environment over there.
production:
secret_key_base: <%%= ENV["SECRET_KEY_BASE"] %>
diff --git a/railties/lib/rails/generators/rails/app/templates/gitignore b/railties/lib/rails/generators/rails/app/templates/gitignore
index 709b341387..7221c26729 100644
--- a/railties/lib/rails/generators/rails/app/templates/gitignore
+++ b/railties/lib/rails/generators/rails/app/templates/gitignore
@@ -22,7 +22,8 @@
<% end -%>
<% unless options[:skip_yarn] -%>
-/vendor/node_modules
+/node_modules
+/yarn-error.log
<% end -%>
.byebug_history
diff --git a/railties/lib/rails/generators/rails/app/templates/test/application_system_test_case.rb b/railties/lib/rails/generators/rails/app/templates/test/application_system_test_case.rb
new file mode 100644
index 0000000000..d19212abd5
--- /dev/null
+++ b/railties/lib/rails/generators/rails/app/templates/test/application_system_test_case.rb
@@ -0,0 +1,5 @@
+require "test_helper"
+
+class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
+ driven_by :selenium, using: :chrome, screen_size: [1400, 1400]
+end
diff --git a/railties/lib/rails/generators/rails/assets/assets_generator.rb b/railties/lib/rails/generators/rails/assets/assets_generator.rb
index 265dada2ca..95d00c2d39 100644
--- a/railties/lib/rails/generators/rails/assets/assets_generator.rb
+++ b/railties/lib/rails/generators/rails/assets/assets_generator.rb
@@ -7,7 +7,7 @@ module Rails
class_option :javascript_engine, desc: "Engine for JavaScripts"
class_option :stylesheet_engine, desc: "Engine for Stylesheets"
- protected
+ private
def asset_name
file_name
diff --git a/railties/lib/rails/generators/rails/controller/controller_generator.rb b/railties/lib/rails/generators/rails/controller/controller_generator.rb
index ced3c85c00..06bdb8b5ce 100644
--- a/railties/lib/rails/generators/rails/controller/controller_generator.rb
+++ b/railties/lib/rails/generators/rails/controller/controller_generator.rb
@@ -16,7 +16,7 @@ module Rails
unless options[:skip_routes]
actions.reverse_each do |action|
# route prepends two spaces onto the front of the string that is passed, this corrects that.
- route generate_routing_code(action)[2..-1]
+ route indent(generate_routing_code(action), 2)[2..-1]
end
end
end
@@ -34,27 +34,30 @@ module Rails
# end
# end
def generate_routing_code(action)
- depth = regular_class_path.length
+ depth = 0
+ lines = []
+
# Create 'namespace' ladder
# namespace :foo do
# namespace :bar do
- namespace_ladder = regular_class_path.each_with_index.map do |ns, i|
- indent(" namespace :#{ns} do\n", i * 2)
- end.join
+ regular_class_path.each do |ns|
+ lines << indent("namespace :#{ns} do\n", depth * 2)
+ depth += 1
+ end
# Create route
# get 'baz/index'
- route = indent(%{ get '#{file_name}/#{action}'\n}, depth * 2)
+ lines << indent(%{get '#{file_name}/#{action}'\n}, depth * 2)
# Create `end` ladder
# end
# end
- end_ladder = (1..depth).reverse_each.map do |i|
- indent("end\n", i * 2)
- end.join
+ until depth.zero?
+ depth -= 1
+ lines << indent("end\n", depth * 2)
+ end
- # Combine the 3 parts to generate complete route entry
- namespace_ladder + route + end_ladder
+ lines.join
end
end
end
diff --git a/railties/lib/rails/generators/rails/encrypted_secrets/encrypted_secrets_generator.rb b/railties/lib/rails/generators/rails/encrypted_secrets/encrypted_secrets_generator.rb
new file mode 100644
index 0000000000..8b29213610
--- /dev/null
+++ b/railties/lib/rails/generators/rails/encrypted_secrets/encrypted_secrets_generator.rb
@@ -0,0 +1,66 @@
+require "rails/generators/base"
+require "rails/secrets"
+
+module Rails
+ module Generators
+ class EncryptedSecretsGenerator < Base
+ def add_secrets_key_file
+ unless File.exist?("config/secrets.yml.key") || File.exist?("config/secrets.yml.enc")
+ key = Rails::Secrets.generate_key
+
+ say "Adding config/secrets.yml.key to store the encryption key: #{key}"
+ say ""
+ say "Save this in a password manager your team can access."
+ say ""
+ say "If you lose the key, no one, including you, can access any encrypted secrets."
+
+ say ""
+ create_file "config/secrets.yml.key", key
+ say ""
+ end
+ end
+
+ def ignore_key_file
+ if File.exist?(".gitignore")
+ unless File.read(".gitignore").include?(key_ignore)
+ say "Ignoring config/secrets.yml.key so it won't end up in Git history:"
+ say ""
+ append_to_file ".gitignore", key_ignore
+ say ""
+ end
+ else
+ say "IMPORTANT: Don't commit config/secrets.yml.key. Add this to your ignore file:"
+ say key_ignore, :on_green
+ say ""
+ end
+ end
+
+ def add_encrypted_secrets_file
+ unless File.exist?("config/secrets.yml.enc")
+ say "Adding config/secrets.yml.enc to store secrets that needs to be encrypted."
+ say ""
+
+ template "config/secrets.yml.enc" do |prefill|
+ say ""
+ say "For now the file contains this but it's been encrypted with the generated key:"
+ say ""
+ say prefill, :on_green
+ say ""
+
+ Secrets.encrypt(prefill)
+ end
+
+ say "You can edit encrypted secrets with `bin/rails secrets:edit`."
+
+ say "Add this to your config/environments/production.rb:"
+ say "config.read_encrypted_secrets = true"
+ end
+ end
+
+ private
+ def key_ignore
+ [ "", "# Ignore encrypted secrets key file.", "config/secrets.yml.key", "" ].join("\n")
+ end
+ end
+ end
+end
diff --git a/railties/lib/rails/generators/rails/encrypted_secrets/templates/config/secrets.yml.enc b/railties/lib/rails/generators/rails/encrypted_secrets/templates/config/secrets.yml.enc
new file mode 100644
index 0000000000..70426a66a5
--- /dev/null
+++ b/railties/lib/rails/generators/rails/encrypted_secrets/templates/config/secrets.yml.enc
@@ -0,0 +1,3 @@
+# See `secrets.yml` for tips on generating suitable keys.
+# production:
+# external_api_key: 1466aac22e6a869134be3d09b9e89232fc2c2289…
diff --git a/railties/lib/rails/generators/rails/generator/generator_generator.rb b/railties/lib/rails/generators/rails/generator/generator_generator.rb
index 8040ec5e7b..299a7da5f1 100644
--- a/railties/lib/rails/generators/rails/generator/generator_generator.rb
+++ b/railties/lib/rails/generators/rails/generator/generator_generator.rb
@@ -12,7 +12,7 @@ module Rails
hook_for :test_framework
- protected
+ private
def generator_dir
if options[:namespace]
diff --git a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb
index 2186fa4ded..ca48919f9a 100644
--- a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb
+++ b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb
@@ -91,6 +91,8 @@ task default: :test
opts[:skip_bundle] = true
opts[:api] = options.api?
opts[:skip_listen] = true
+ opts[:skip_git] = true
+ opts[:skip_turbolinks] = true
invoke Rails::Generators::AppGenerator,
[ File.expand_path(dummy_path, destination_root) ], opts
@@ -112,7 +114,6 @@ task default: :test
def test_dummy_clean
inside dummy_path do
- remove_file ".gitignore"
remove_file "db/seeds.rb"
remove_file "doc"
remove_file "Gemfile"
@@ -186,7 +187,7 @@ task default: :test
desc: "Skip gemspec file"
class_option :skip_gemfile_entry, type: :boolean, default: false,
- desc: "If creating plugin in application's directory " +
+ desc: "If creating plugin in application's directory " \
"skip adding entry to Gemfile"
class_option :api, type: :boolean, default: false,
@@ -195,10 +196,6 @@ task default: :test
def initialize(*args)
@dummy_path = nil
super
-
- unless plugin_path
- raise Error, "Plugin name should be provided in arguments. For details run: rails plugin new --help"
- end
end
public_task :set_default_accessors!
@@ -286,7 +283,7 @@ task default: :test
@namespaced_name ||= name.tr("-", "/")
end
- protected
+ private
def create_dummy_app(path = nil)
dummy_path(path) if path
@@ -415,7 +412,6 @@ task default: :test
require 'rake/testtask'
Rake::TestTask.new(:test) do |t|
- t.libs << 'lib'
t.libs << 'test'
t.pattern = 'test/**/*_test.rb'
t.verbose = false
@@ -437,7 +433,7 @@ end
end
def inside_application?
- rails_app_path && app_path =~ /^#{rails_app_path}/
+ rails_app_path && destination_root.start_with?(rails_app_path.to_s)
end
def relative_path
diff --git a/railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt b/railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt
index 56e7925c6b..c03d9953d4 100644
--- a/railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt
+++ b/railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt
@@ -3,6 +3,7 @@
ENGINE_ROOT = File.expand_path('../..', __FILE__)
ENGINE_PATH = File.expand_path('../../lib/<%= namespaced_name -%>/engine', __FILE__)
+APP_PATH = File.expand_path('../../<%= dummy_path -%>/config/application', __FILE__)
# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
diff --git a/railties/lib/rails/generators/rails/plugin/templates/bin/test.tt b/railties/lib/rails/generators/rails/plugin/templates/bin/test.tt
index c0fbb84a93..8385e6a8a2 100644
--- a/railties/lib/rails/generators/rails/plugin/templates/bin/test.tt
+++ b/railties/lib/rails/generators/rails/plugin/templates/bin/test.tt
@@ -1,10 +1,4 @@
-$: << File.expand_path(File.expand_path('../../test', __FILE__))
+$: << File.expand_path(File.expand_path("../../test", __FILE__))
-require 'bundler/setup'
-require 'rails/test_unit/minitest_plugin'
-
-Rails::TestUnitReporter.executable = 'bin/test'
-
-Minitest.run_via[:rails] = true
-
-require "active_support/testing/autorun"
+require "bundler/setup"
+require "rails/plugin/test"
diff --git a/railties/lib/rails/generators/rails/plugin/templates/test/application_system_test_case.rb b/railties/lib/rails/generators/rails/plugin/templates/test/application_system_test_case.rb
new file mode 100644
index 0000000000..d19212abd5
--- /dev/null
+++ b/railties/lib/rails/generators/rails/plugin/templates/test/application_system_test_case.rb
@@ -0,0 +1,5 @@
+require "test_helper"
+
+class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
+ driven_by :selenium, using: :chrome, screen_size: [1400, 1400]
+end
diff --git a/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb
index ed6bf7f7d7..12d6bc85b2 100644
--- a/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb
+++ b/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb
@@ -6,6 +6,7 @@ module Rails
remove_hook_for :resource_controller
remove_class_option :actions
+ class_option :api, type: :boolean
class_option :stylesheets, type: :boolean, desc: "Generate Stylesheets"
class_option :stylesheet_engine, desc: "Engine for Stylesheets"
class_option :assets, type: :boolean
@@ -15,10 +16,13 @@ module Rails
def handle_skip
@options = @options.merge(stylesheets: false) unless options[:assets]
@options = @options.merge(stylesheet_engine: false) unless options[:stylesheets] && options[:scaffold_stylesheet]
+ @options = @options.merge(system_tests: false) if options[:api]
end
hook_for :scaffold_controller, required: true
+ hook_for :system_tests, as: :system
+
hook_for :assets do |assets|
invoke assets, [controller_name]
end
diff --git a/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb b/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb
index e4f3161ffd..cf97c22160 100644
--- a/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb
+++ b/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb
@@ -20,7 +20,11 @@ module Rails
template template_file, File.join("app/controllers", controller_class_path, "#{controller_file_name}_controller.rb")
end
- hook_for :template_engine, :test_framework, as: :scaffold
+ hook_for :template_engine, as: :scaffold do |template_engine|
+ invoke template_engine unless options.api?
+ end
+
+ hook_for :test_framework, as: :scaffold
# Invoke the helper using the controller name (pluralized)
hook_for :helper, as: :scaffold do |invoked|
diff --git a/railties/lib/rails/generators/rails/system_test/USAGE b/railties/lib/rails/generators/rails/system_test/USAGE
new file mode 100644
index 0000000000..f11a99e008
--- /dev/null
+++ b/railties/lib/rails/generators/rails/system_test/USAGE
@@ -0,0 +1,10 @@
+Description:
+ Stubs out a new system test. Pass the name of the test, either
+ CamelCased or under_scored, as an argument.
+
+ This generator invokes the current system tool, which defaults to
+ TestUnit.
+
+Example:
+ `rails generate system_test GeneralStories` creates a GeneralStories
+ system test in test/system/general_stories_test.rb
diff --git a/railties/lib/rails/generators/rails/system_test/system_test_generator.rb b/railties/lib/rails/generators/rails/system_test/system_test_generator.rb
new file mode 100644
index 0000000000..901120e892
--- /dev/null
+++ b/railties/lib/rails/generators/rails/system_test/system_test_generator.rb
@@ -0,0 +1,7 @@
+module Rails
+ module Generators
+ class SystemTestGenerator < NamedBase # :nodoc:
+ hook_for :system_tests, as: :system
+ end
+ end
+end
diff --git a/railties/lib/rails/generators/resource_helpers.rb b/railties/lib/rails/generators/resource_helpers.rb
index a28977319a..e7cb722473 100644
--- a/railties/lib/rails/generators/resource_helpers.rb
+++ b/railties/lib/rails/generators/resource_helpers.rb
@@ -23,10 +23,14 @@ module Rails
assign_controller_names!(controller_name.pluralize)
end
+ # TODO Change this to private once we've dropped Ruby 2.2 support.
+ # Workaround for Ruby 2.2 "private attribute?" warning.
protected
attr_reader :controller_name, :controller_file_name
+ private
+
def controller_class_path
if options[:model_name]
@controller_class_path
@@ -55,7 +59,7 @@ module Rails
end
# Loads the ORM::Generators::ActiveModel class. This class is responsible
- # to tell scaffold entities how to generate an specific method for the
+ # to tell scaffold entities how to generate a specific method for the
# ORM. Check Rails::Generators::ActiveModel for more information.
def orm_class
@orm_class ||= begin
diff --git a/railties/lib/rails/generators/test_unit/generator/generator_generator.rb b/railties/lib/rails/generators/test_unit/generator/generator_generator.rb
index 59f8d40343..6b6e094453 100644
--- a/railties/lib/rails/generators/test_unit/generator/generator_generator.rb
+++ b/railties/lib/rails/generators/test_unit/generator/generator_generator.rb
@@ -12,7 +12,7 @@ module TestUnit # :nodoc:
template "generator_test.rb", File.join("test/lib/generators", class_path, "#{file_name}_generator_test.rb")
end
- protected
+ private
def generator_path
if options[:namespace]
diff --git a/railties/lib/rails/generators/test_unit/integration/templates/integration_test.rb b/railties/lib/rails/generators/test_unit/integration/templates/integration_test.rb
index dea7e22196..118e0f1271 100644
--- a/railties/lib/rails/generators/test_unit/integration/templates/integration_test.rb
+++ b/railties/lib/rails/generators/test_unit/integration/templates/integration_test.rb
@@ -1,7 +1,9 @@
require 'test_helper'
+<% module_namespacing do -%>
class <%= class_name %>Test < ActionDispatch::IntegrationTest
# test "the truth" do
# assert true
# end
end
+<% end -%>
diff --git a/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb b/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb
index 806279788e..67bff8e4f9 100644
--- a/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb
+++ b/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb
@@ -17,7 +17,7 @@ module TestUnit # :nodoc:
template "preview.rb", File.join("test/mailers/previews", class_path, "#{file_name}_mailer_preview.rb")
end
- protected
+ private
def file_name
@_file_name ||= super.gsub(/_mailer/i, "")
end
diff --git a/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb
index 8840a86d0d..292db35121 100644
--- a/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb
+++ b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb
@@ -22,7 +22,7 @@ module TestUnit # :nodoc:
def fixture_name
@fixture_name ||=
if mountable_engine?
- "%s_%s" % [namespaced_path, table_name]
+ (namespace_dirs + [table_name]).join("_")
else
table_name
end
diff --git a/railties/lib/rails/generators/test_unit/system/system_generator.rb b/railties/lib/rails/generators/test_unit/system/system_generator.rb
new file mode 100644
index 0000000000..aec415a4e5
--- /dev/null
+++ b/railties/lib/rails/generators/test_unit/system/system_generator.rb
@@ -0,0 +1,17 @@
+require "rails/generators/test_unit"
+
+module TestUnit # :nodoc:
+ module Generators # :nodoc:
+ class SystemGenerator < Base # :nodoc:
+ check_class_collision suffix: "Test"
+
+ def create_test_files
+ if !File.exist?(File.join("test/application_system_test_case.rb"))
+ template "application_system_test_case.rb", File.join("test", "application_system_test_case.rb")
+ end
+
+ template "system_test.rb", File.join("test/system", "#{file_name.pluralize}_test.rb")
+ end
+ end
+ end
+end
diff --git a/railties/lib/rails/generators/test_unit/system/templates/application_system_test_case.rb b/railties/lib/rails/generators/test_unit/system/templates/application_system_test_case.rb
new file mode 100644
index 0000000000..d19212abd5
--- /dev/null
+++ b/railties/lib/rails/generators/test_unit/system/templates/application_system_test_case.rb
@@ -0,0 +1,5 @@
+require "test_helper"
+
+class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
+ driven_by :selenium, using: :chrome, screen_size: [1400, 1400]
+end
diff --git a/railties/lib/rails/generators/test_unit/system/templates/system_test.rb b/railties/lib/rails/generators/test_unit/system/templates/system_test.rb
new file mode 100644
index 0000000000..b5ce2ba5c8
--- /dev/null
+++ b/railties/lib/rails/generators/test_unit/system/templates/system_test.rb
@@ -0,0 +1,9 @@
+require "application_system_test_case"
+
+class <%= class_name.pluralize %>Test < ApplicationSystemTestCase
+ # test "visiting the index" do
+ # visit <%= plural_table_name %>_url
+ #
+ # assert_selector "h1", text: "<%= class_name %>"
+ # end
+end
diff --git a/railties/lib/rails/generators/testing/behaviour.rb b/railties/lib/rails/generators/testing/behaviour.rb
index a1e5a233b9..64d641d096 100644
--- a/railties/lib/rails/generators/testing/behaviour.rb
+++ b/railties/lib/rails/generators/testing/behaviour.rb
@@ -82,23 +82,23 @@ module Rails
Rails::Generators::GeneratedAttribute.parse([name, attribute_type, index].compact.join(":"))
end
- protected
+ private
- def destination_root_is_set? # :nodoc:
+ def destination_root_is_set?
raise "You need to configure your Rails::Generators::TestCase destination root." unless destination_root
end
- def ensure_current_path # :nodoc:
+ def ensure_current_path
cd current_path
end
# Clears all files and directories in destination.
- def prepare_destination
+ def prepare_destination # :doc:
rm_rf(destination_root)
mkdir_p(destination_root)
end
- def migration_file_name(relative) # :nodoc:
+ def migration_file_name(relative)
absolute = File.expand_path(relative, destination_root)
dirname, file_name = File.dirname(absolute), File.basename(absolute).sub(/\.rb$/, "")
Dir.glob("#{dirname}/[0-9]*_*.rb").grep(/\d+_#{file_name}.rb$/).first
diff --git a/railties/lib/rails/info.rb b/railties/lib/rails/info.rb
index 5d4acd6f6b..fc064dac32 100644
--- a/railties/lib/rails/info.rb
+++ b/railties/lib/rails/info.rb
@@ -1,9 +1,9 @@
require "cgi"
module Rails
- # This module helps build the runtime properties used to display in the
- # Rails::InfoController responses. Including the active Rails version, Ruby
- # version, Rack version, and so on.
+ # This module helps build the runtime properties that are displayed in
+ # Rails::InfoController responses. These include the active Rails version,
+ # Ruby version, Rack version, and so on.
module Info
mattr_accessor :properties
class << (@@properties = [])
diff --git a/railties/lib/rails/mailers_controller.rb b/railties/lib/rails/mailers_controller.rb
index 95de998208..000ce40fbc 100644
--- a/railties/lib/rails/mailers_controller.rb
+++ b/railties/lib/rails/mailers_controller.rb
@@ -40,12 +40,12 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc:
end
end
- protected
- def show_previews?
+ private
+ def show_previews? # :doc:
ActionMailer::Base.show_previews
end
- def find_preview
+ def find_preview # :doc:
candidates = []
params[:path].to_s.scan(%r{/|$}) { candidates << $` }
preview = candidates.detect { |candidate| ActionMailer::Preview.exists?(candidate) }
@@ -57,7 +57,7 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc:
end
end
- def find_preferred_part(*formats)
+ def find_preferred_part(*formats) # :doc:
formats.each do |format|
if part = @email.find_first_mime_type(format)
return part
@@ -69,7 +69,7 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc:
end
end
- def find_part(format)
+ def find_part(format) # :doc:
if part = @email.find_first_mime_type(format)
part
elsif @email.mime_type == format
diff --git a/railties/lib/rails/paths.rb b/railties/lib/rails/paths.rb
index 10925de8b2..af3be10a31 100644
--- a/railties/lib/rails/paths.rb
+++ b/railties/lib/rails/paths.rb
@@ -2,12 +2,12 @@ module Rails
module Paths
# This object is an extended hash that behaves as root of the <tt>Rails::Paths</tt> system.
# It allows you to collect information about how you want to structure your application
- # paths by a Hash like API. It requires you to give a physical path on initialization.
+ # paths through a Hash-like API. It requires you to give a physical path on initialization.
#
# root = Root.new "/rails"
# root.add "app/controllers", eager_load: true
#
- # The command above creates a new root object and adds "app/controllers" as a path.
+ # The above command creates a new root object and adds "app/controllers" as a path.
# This means we can get a <tt>Rails::Paths::Path</tt> object back like below:
#
# path = root["app/controllers"]
diff --git a/railties/lib/rails/plugin/test.rb b/railties/lib/rails/plugin/test.rb
new file mode 100644
index 0000000000..ff043b488e
--- /dev/null
+++ b/railties/lib/rails/plugin/test.rb
@@ -0,0 +1,7 @@
+require "rails/test_unit/minitest_plugin"
+
+Rails::TestUnitReporter.executable = "bin/test"
+
+Minitest.run_via = :rails
+
+require "active_support/testing/autorun"
diff --git a/railties/lib/rails/rack/debugger.rb b/railties/lib/rails/rack/debugger.rb
deleted file mode 100644
index dccfa3e9bb..0000000000
--- a/railties/lib/rails/rack/debugger.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-require "active_support/deprecation"
-
-ActiveSupport::Deprecation.warn("This file is deprecated and will be removed in Rails 5.1 with no replacement.")
diff --git a/railties/lib/rails/rack/logger.rb b/railties/lib/rails/rack/logger.rb
index e3fee75603..853fc26051 100644
--- a/railties/lib/rails/rack/logger.rb
+++ b/railties/lib/rails/rack/logger.rb
@@ -27,45 +27,43 @@ module Rails
end
end
- protected
+ private
- def call_app(request, env)
- instrumenter = ActiveSupport::Notifications.instrumenter
- instrumenter.start "request.action_dispatch", request: request
- logger.info { started_request_message(request) }
- resp = @app.call(env)
- resp[2] = ::Rack::BodyProxy.new(resp[2]) { finish(request) }
- resp
- rescue Exception
- finish(request)
- raise
- ensure
- ActiveSupport::LogSubscriber.flush_all!
- end
+ def call_app(request, env) # :doc:
+ instrumenter = ActiveSupport::Notifications.instrumenter
+ instrumenter.start "request.action_dispatch", request: request
+ logger.info { started_request_message(request) }
+ resp = @app.call(env)
+ resp[2] = ::Rack::BodyProxy.new(resp[2]) { finish(request) }
+ resp
+ rescue Exception
+ finish(request)
+ raise
+ ensure
+ ActiveSupport::LogSubscriber.flush_all!
+ end
- # Started GET "/session/new" for 127.0.0.1 at 2012-09-26 14:51:42 -0700
- def started_request_message(request)
- 'Started %s "%s" for %s at %s' % [
- request.request_method,
- request.filtered_path,
- request.ip,
- Time.now.to_default_s ]
- end
+ # Started GET "/session/new" for 127.0.0.1 at 2012-09-26 14:51:42 -0700
+ def started_request_message(request) # :doc:
+ 'Started %s "%s" for %s at %s' % [
+ request.request_method,
+ request.filtered_path,
+ request.ip,
+ Time.now.to_default_s ]
+ end
- def compute_tags(request)
- @taggers.collect do |tag|
- case tag
- when Proc
- tag.call(request)
- when Symbol
- request.send(tag)
- else
- tag
+ def compute_tags(request) # :doc:
+ @taggers.collect do |tag|
+ case tag
+ when Proc
+ tag.call(request)
+ when Symbol
+ request.send(tag)
+ else
+ tag
+ end
end
end
- end
-
- private
def finish(request)
instrumenter = ActiveSupport::Notifications.instrumenter
diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb
index 696db61f01..474118c0a9 100644
--- a/railties/lib/rails/railtie.rb
+++ b/railties/lib/rails/railtie.rb
@@ -173,8 +173,8 @@ module Rails
instance.configure(&block)
end
- protected
- def generate_railtie_name(string) #:nodoc:
+ private
+ def generate_railtie_name(string)
ActiveSupport::Inflector.underscore(string).tr("/", "_")
end
@@ -188,7 +188,6 @@ module Rails
end
end
- private
# receives an instance variable identifier, set the variable value if is
# blank and append given block to value, which will be used later in
# `#each_registered_block(type, &block)`
diff --git a/railties/lib/rails/railtie/configurable.rb b/railties/lib/rails/railtie/configurable.rb
index 39f1f87575..2a8295426e 100644
--- a/railties/lib/rails/railtie/configurable.rb
+++ b/railties/lib/rails/railtie/configurable.rb
@@ -24,7 +24,7 @@ module Rails
class_eval(&block)
end
- protected
+ private
def method_missing(*args, &block)
instance.send(*args, &block)
diff --git a/railties/lib/rails/secrets.rb b/railties/lib/rails/secrets.rb
new file mode 100644
index 0000000000..a083914109
--- /dev/null
+++ b/railties/lib/rails/secrets.rb
@@ -0,0 +1,111 @@
+require "yaml"
+
+module Rails
+ # Greatly inspired by Ara T. Howard's magnificent sekrets gem. 😘
+ class Secrets # :nodoc:
+ class MissingKeyError < RuntimeError
+ def initialize
+ super(<<-end_of_message.squish)
+ Missing encryption key to decrypt secrets with.
+ Ask your team for your master key and put it in ENV["RAILS_MASTER_KEY"]
+ end_of_message
+ end
+ end
+
+ @read_encrypted_secrets = false
+ @root = File # Wonky, but ensures `join` uses the current directory.
+
+ class << self
+ attr_writer :root
+ attr_accessor :read_encrypted_secrets
+
+ def parse(paths, env:)
+ paths.each_with_object(Hash.new) do |path, all_secrets|
+ require "erb"
+
+ secrets = YAML.load(ERB.new(preprocess(path)).result) || {}
+ all_secrets.merge!(secrets["shared"].deep_symbolize_keys) if secrets["shared"]
+ all_secrets.merge!(secrets[env].deep_symbolize_keys) if secrets[env]
+ end
+ end
+
+ def generate_key
+ cipher = new_cipher
+ SecureRandom.hex(cipher.key_len)[0, cipher.key_len]
+ end
+
+ def key
+ ENV["RAILS_MASTER_KEY"] || read_key_file || handle_missing_key
+ end
+
+ def encrypt(text)
+ cipher(:encrypt, text)
+ end
+
+ def decrypt(data)
+ cipher(:decrypt, data)
+ end
+
+ def read
+ decrypt(IO.binread(path))
+ end
+
+ def write(contents)
+ IO.binwrite("#{path}.tmp", encrypt(contents))
+ FileUtils.mv("#{path}.tmp", path)
+ end
+
+ def read_for_editing
+ tmp_path = File.join(Dir.tmpdir, File.basename(path))
+ IO.binwrite(tmp_path, read)
+
+ yield tmp_path
+
+ write(IO.binread(tmp_path))
+ ensure
+ FileUtils.rm(tmp_path) if File.exist?(tmp_path)
+ end
+
+ private
+ def handle_missing_key
+ raise MissingKeyError
+ end
+
+ def read_key_file
+ if File.exist?(key_path)
+ IO.binread(key_path).strip
+ end
+ end
+
+ def key_path
+ @root.join("config", "secrets.yml.key")
+ end
+
+ def path
+ @root.join("config", "secrets.yml.enc").to_s
+ end
+
+ def preprocess(path)
+ if path.end_with?(".enc")
+ if @read_encrypted_secrets
+ decrypt(IO.binread(path))
+ else
+ ""
+ end
+ else
+ IO.read(path)
+ end
+ end
+
+ def new_cipher
+ OpenSSL::Cipher.new("aes-256-cbc")
+ end
+
+ def cipher(mode, data)
+ cipher = new_cipher.public_send(mode)
+ cipher.key = key
+ cipher.update(data) << cipher.final
+ end
+ end
+ end
+end
diff --git a/railties/lib/rails/source_annotation_extractor.rb b/railties/lib/rails/source_annotation_extractor.rb
index 3a48c4c496..e9088c44ce 100644
--- a/railties/lib/rails/source_annotation_extractor.rb
+++ b/railties/lib/rails/source_annotation_extractor.rb
@@ -13,7 +13,7 @@
# start with the tag optionally followed by a colon. Everything up to the end
# of the line (or closing ERB comment tag) is considered to be their text.
class SourceAnnotationExtractor
- class Annotation < Struct.new(:line, :tag, :text)
+ Annotation = Struct.new(:line, :tag, :text) do
def self.directories
@@directories ||= %w(app config db lib test) + (ENV["SOURCE_ANNOTATION_DIRECTORIES"] || "").split(",")
end
diff --git a/railties/lib/rails/tasks.rb b/railties/lib/rails/tasks.rb
index 48675b3845..c0a50e5bda 100644
--- a/railties/lib/rails/tasks.rb
+++ b/railties/lib/rails/tasks.rb
@@ -12,6 +12,7 @@ require "rake"
restart
routes
tmp
+ yarn
).tap { |arr|
arr << "statistics" if Rake.application.current_scope.empty?
}.each do |task|
diff --git a/railties/lib/rails/tasks/framework.rake b/railties/lib/rails/tasks/framework.rake
index a2167796eb..f5586b53f0 100644
--- a/railties/lib/rails/tasks/framework.rake
+++ b/railties/lib/rails/tasks/framework.rake
@@ -1,5 +1,3 @@
-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", "update:upgrade_guide_info" ]
@@ -73,15 +71,3 @@ namespace :app 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/log.rake b/railties/lib/rails/tasks/log.rake
index c376234fee..ba796845d7 100644
--- a/railties/lib/rails/tasks/log.rake
+++ b/railties/lib/rails/tasks/log.rake
@@ -3,7 +3,7 @@ namespace :log do
##
# Truncates all/specified log files
# ENV['LOGS']
- # - defaults to standard environment log files i.e. 'development,test,production'
+ # - defaults to all environments log files i.e. 'development,test,production'
# - ENV['LOGS']=all truncates all files i.e. log/*.log
# - ENV['LOGS']='test,development' truncates only specified files
desc "Truncates all/specified *.log files in log/ to zero bytes (specify which logs with LOGS=test,development)"
@@ -19,7 +19,7 @@ namespace :log do
elsif ENV["LOGS"]
log_files_to_truncate(ENV["LOGS"])
else
- log_files_to_truncate("development,test,production")
+ log_files_to_truncate(all_environments.join(","))
end
end
@@ -33,4 +33,8 @@ namespace :log do
f = File.open(file, "w")
f.close
end
+
+ def all_environments
+ Dir["config/environments/*.rb"].map { |fname| File.basename(fname, ".*") }
+ end
end
diff --git a/railties/lib/rails/tasks/routes.rake b/railties/lib/rails/tasks/routes.rake
index f5e5b9ae87..215fb2ceb5 100644
--- a/railties/lib/rails/tasks/routes.rake
+++ b/railties/lib/rails/tasks/routes.rake
@@ -1,5 +1,3 @@
-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 -c option, or grep routes using -g option"
@@ -7,15 +5,8 @@ task routes: :environment do
all_routes = Rails.application.routes.routes
require "action_dispatch/routing/inspector"
inspector = ActionDispatch::Routing::RoutesInspector.new(all_routes)
- if ARGV.any? { |argv| argv.start_with? "CONTROLLER" }
- puts <<-eow.strip_heredoc
- Passing `CONTROLLER` to `bin/rails routes` is deprecated and will be removed in Rails 5.1.
- Please use `bin/rails routes -c controller_name` instead.
- eow
- end
routes_filter = nil
- routes_filter = { controller: ENV["CONTROLLER"] } if ENV["CONTROLLER"]
OptionParser.new do |opts|
opts.banner = "Usage: rails routes [options]"
diff --git a/railties/lib/rails/tasks/statistics.rake b/railties/lib/rails/tasks/statistics.rake
index 8265aef10b..cb569be58b 100644
--- a/railties/lib/rails/tasks/statistics.rake
+++ b/railties/lib/rails/tasks/statistics.rake
@@ -10,7 +10,6 @@ STATS_DIRECTORIES = [
%w(Channels app/channels),
%w(JavaScripts app/assets/javascripts),
%w(Libraries lib/),
- %w(Tasks lib/tasks),
%w(APIs app/apis),
%w(Controller\ tests test/controllers),
%w(Helper\ tests test/helpers),
@@ -18,6 +17,7 @@ STATS_DIRECTORIES = [
%w(Mailer\ tests test/mailers),
%w(Job\ tests test/jobs),
%w(Integration\ tests test/integration),
+ %w(System\ tests test/system),
].collect do |name, dir|
[ name, "#{File.dirname(Rake.application.rakefile_location)}/#{dir}" ]
end.select { |name, dir| File.directory?(dir) }
diff --git a/railties/lib/rails/tasks/yarn.rake b/railties/lib/rails/tasks/yarn.rake
new file mode 100644
index 0000000000..87476b1b8c
--- /dev/null
+++ b/railties/lib/rails/tasks/yarn.rake
@@ -0,0 +1,11 @@
+namespace :yarn do
+ desc "Install all JavaScript dependencies as specified via Yarn"
+ task :install do
+ system("./bin/yarn install --no-progress")
+ end
+end
+
+# Run Yarn prior to Sprockets assets precompilation, so dependencies are available for use.
+if Rake::Task.task_defined?("assets:precompile")
+ Rake::Task["assets:precompile"].enhance [ "yarn:install" ]
+end
diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb
index db341dd847..8e290239bd 100644
--- a/railties/lib/rails/test_help.rb
+++ b/railties/lib/rails/test_help.rb
@@ -11,13 +11,19 @@ require "rails/generators/test_case"
require "active_support/testing/autorun"
+if defined?(Capybara) && defined?(Puma)
+ require "action_dispatch/system_test_case"
+end
+
if defined?(ActiveRecord::Base)
ActiveRecord::Migration.maintain_test_schema!
- class ActiveSupport::TestCase
- include ActiveRecord::TestFixtures
- self.fixture_path = "#{Rails.root}/test/fixtures/"
- self.file_fixture_path = self.fixture_path + "files"
+ module ActiveSupport
+ class TestCase
+ include ActiveRecord::TestFixtures
+ self.fixture_path = "#{Rails.root}/test/fixtures/"
+ self.file_fixture_path = fixture_path + "files"
+ end
end
ActionDispatch::IntegrationTest.fixture_path = ActiveSupport::TestCase.fixture_path
@@ -27,6 +33,8 @@ if defined?(ActiveRecord::Base)
end
end
+# :enddoc:
+
class ActionController::TestCase
def before_setup # :nodoc:
@routes = Rails.application.routes
@@ -40,3 +48,12 @@ class ActionDispatch::IntegrationTest
super
end
end
+
+if defined?(Capybara) && defined?(Puma)
+ class ActionDispatch::SystemTestCase
+ def before_setup # :nodoc:
+ @routes = Rails.application.routes
+ super
+ end
+ end
+end
diff --git a/railties/lib/rails/test_unit/minitest_plugin.rb b/railties/lib/rails/test_unit/minitest_plugin.rb
index 6e196a32ab..e44fe78bbd 100644
--- a/railties/lib/rails/test_unit/minitest_plugin.rb
+++ b/railties/lib/rails/test_unit/minitest_plugin.rb
@@ -52,21 +52,25 @@ module Minitest
options[:color] = value
end
+ opts.on("-w", "--warnings",
+ "Enable ruby warnings") do
+ $VERBOSE = true
+ end
+
options[:color] = true
options[:output_inline] = true
- options[:patterns] = defined?(@rake_patterns) ? @rake_patterns : opts.order!
+ options[:patterns] = opts.order! unless run_via.rake?
end
- # Running several Rake tasks in a single command would trip up the runner,
- # as the patterns would also contain the other Rake tasks.
def self.rake_run(patterns) # :nodoc:
- @rake_patterns = patterns
+ self.run_via = :rake unless run_via.set?
+ ::Rails::TestRequirer.require_files(patterns)
autorun
end
module RunRespectingRakeTestopts
def run(args = [])
- if defined?(@rake_patterns)
+ if run_via.rake?
args = Shellwords.split(ENV["TESTOPTS"] || "")
end
@@ -81,8 +85,9 @@ module Minitest
def self.plugin_rails_init(options)
ENV["RAILS_ENV"] = options[:environment] || "test"
- # If run via `ruby` we've been passed the files to run directly.
- unless run_via[:ruby]
+ # If run via `ruby` we've been passed the files to run directly, or if run
+ # via `rake` then they have already been eagerly required.
+ unless run_via.ruby? || run_via.rake?
::Rails::TestRequirer.require_files(options[:patterns])
end
@@ -97,7 +102,33 @@ module Minitest
reporter << ::Rails::TestUnitReporter.new(options[:io], options)
end
- mattr_accessor(:run_via) { Hash.new }
+ def self.run_via=(runner)
+ if run_via.set?
+ raise ArgumentError, "run_via already assigned"
+ else
+ run_via.runner = runner
+ end
+ end
+
+ class RunVia
+ attr_accessor :runner
+ alias set? runner
+
+ # Backwardscompatibility with Rails 5.0 generated plugin test scripts.
+ def []=(runner, *)
+ @runner = runner
+ end
+
+ def ruby?
+ runner == :ruby
+ end
+
+ def rake?
+ runner == :rake
+ end
+ end
+
+ mattr_reader(:run_via) { RunVia.new }
end
# Put Rails as the first plugin minitest initializes so other plugins
diff --git a/railties/lib/rails/test_unit/railtie.rb b/railties/lib/rails/test_unit/railtie.rb
index 746120e6a1..9cc3f73a9c 100644
--- a/railties/lib/rails/test_unit/railtie.rb
+++ b/railties/lib/rails/test_unit/railtie.rb
@@ -11,6 +11,7 @@ module Rails
fixture_replacement: nil
c.integration_tool :test_unit
+ c.system_tests :test_unit
end
initializer "test_unit.line_filtering" do
diff --git a/railties/lib/rails/test_unit/testing.rake b/railties/lib/rails/test_unit/testing.rake
index 4c157c1262..4dde3d3c97 100644
--- a/railties/lib/rails/test_unit/testing.rake
+++ b/railties/lib/rails/test_unit/testing.rake
@@ -47,4 +47,9 @@ namespace :test do
$: << "test"
Minitest.rake_run(["test/controllers", "test/mailers", "test/functional"])
end
+
+ task system: "test:prepare" do
+ $: << "test"
+ Minitest.rake_run(["test/system"])
+ end
end