aboutsummaryrefslogtreecommitdiffstats
path: root/railties/lib
diff options
context:
space:
mode:
Diffstat (limited to 'railties/lib')
-rw-r--r--railties/lib/rails.rb10
-rw-r--r--railties/lib/rails/api/task.rb14
-rw-r--r--railties/lib/rails/app_loader.rb (renamed from railties/lib/rails/app_rails_loader.rb)7
-rw-r--r--railties/lib/rails/application.rb51
-rw-r--r--railties/lib/rails/application/bootstrap.rb2
-rw-r--r--railties/lib/rails/application/configuration.rb39
-rw-r--r--railties/lib/rails/application/default_middleware_stack.rb42
-rw-r--r--railties/lib/rails/application/finisher.rb13
-rw-r--r--railties/lib/rails/application_controller.rb2
-rw-r--r--railties/lib/rails/cli.rb4
-rw-r--r--railties/lib/rails/code_statistics.rb14
-rw-r--r--railties/lib/rails/commands.rb3
-rw-r--r--railties/lib/rails/commands/commands_tasks.rb18
-rw-r--r--railties/lib/rails/commands/console.rb33
-rw-r--r--railties/lib/rails/commands/console_helper.rb34
-rw-r--r--railties/lib/rails/commands/dbconsole.rb138
-rw-r--r--railties/lib/rails/commands/server.rb45
-rw-r--r--railties/lib/rails/commands/test.rb9
-rw-r--r--railties/lib/rails/configuration.rb26
-rw-r--r--railties/lib/rails/console/app.rb5
-rw-r--r--railties/lib/rails/console/helpers.rb2
-rw-r--r--railties/lib/rails/engine.rb126
-rw-r--r--railties/lib/rails/engine/commands.rb6
-rw-r--r--railties/lib/rails/engine/configuration.rb11
-rw-r--r--railties/lib/rails/generators.rb34
-rw-r--r--railties/lib/rails/generators/actions.rb26
-rw-r--r--railties/lib/rails/generators/app_base.rb57
-rw-r--r--railties/lib/rails/generators/base.rb10
-rw-r--r--railties/lib/rails/generators/erb/mailer/mailer_generator.rb6
-rw-r--r--railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb2
-rw-r--r--railties/lib/rails/generators/erb/scaffold/templates/index.html.erb2
-rw-r--r--railties/lib/rails/generators/migration.rb14
-rw-r--r--railties/lib/rails/generators/named_base.rb12
-rw-r--r--railties/lib/rails/generators/rails/app/app_generator.rb57
-rw-r--r--railties/lib/rails/generators/rails/app/templates/Gemfile26
-rw-r--r--railties/lib/rails/generators/rails/app/templates/README.md (renamed from railties/lib/rails/generators/rails/app/templates/README.rdoc)6
-rw-r--r--railties/lib/rails/generators/rails/app/templates/app/assets/config/manifest.js.tt8
-rw-r--r--railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt4
-rw-r--r--railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css6
-rw-r--r--railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt4
-rw-r--r--railties/lib/rails/generators/rails/app/templates/app/jobs/application_job.rb2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/bin/setup15
-rw-r--r--railties/lib/rails/generators/rails/app/templates/bin/update28
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/application.rb11
-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/environments/development.rb.tt14
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt5
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt6
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/initializers/active_record_belongs_to_required_by_default.rb4
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/initializers/application_controller_renderer.rb6
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/initializers/callback_terminator.rb2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/initializers/cors.rb14
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt4
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/routes.rb55
-rw-r--r--railties/lib/rails/generators/rails/app/templates/gitignore5
-rw-r--r--railties/lib/rails/generators/rails/controller/controller_generator.rb10
-rw-r--r--railties/lib/rails/generators/rails/model/USAGE9
-rw-r--r--railties/lib/rails/generators/rails/plugin/plugin_generator.rb111
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec10
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/Gemfile2
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/README.rdoc2
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/Rakefile2
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/app/controllers/%name%/application_controller.rb.tt4
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/app/controllers/%namespaced_name%/application_controller.rb.tt5
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/app/helpers/%name%/application_helper.rb.tt4
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/app/helpers/%namespaced_name%/application_helper.rb.tt5
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/app/jobs/%namespaced_name%/application_job.rb.tt5
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/app/views/layouts/%name%/application.html.erb.tt14
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/app/views/layouts/%namespaced_name%/application.html.erb.tt14
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt2
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/config/routes.rb2
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/gitignore4
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/lib/%name%.rb6
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/lib/%name%/engine.rb7
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/lib/%name%/version.rb3
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%.rb5
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/engine.rb7
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/version.rb1
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/lib/tasks/%namespaced_name%_tasks.rake (renamed from railties/lib/rails/generators/rails/plugin/templates/lib/tasks/%name%_tasks.rake)2
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/rails/application.rb4
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/rails/dummy_manifest.js11
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/rails/engine_manifest.js6
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js4
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/rails/routes.rb2
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/rails/stylesheets.css6
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/test/%name%_test.rb7
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/test/%namespaced_name%_test.rb7
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/test/integration/navigation_test.rb4
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb6
-rw-r--r--railties/lib/rails/generators/rails/resource/resource_generator.rb1
-rw-r--r--railties/lib/rails/generators/rails/resource_route/resource_route_generator.rb7
-rw-r--r--railties/lib/rails/generators/rails/scaffold/USAGE2
-rw-r--r--railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb3
-rw-r--r--railties/lib/rails/generators/rails/scaffold/templates/scaffold.css38
-rw-r--r--railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb5
-rw-r--r--railties/lib/rails/generators/rails/scaffold_controller/templates/api_controller.rb61
-rw-r--r--railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb2
-rw-r--r--railties/lib/rails/generators/resource_helpers.rb2
-rw-r--r--railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb6
-rw-r--r--railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb5
-rw-r--r--railties/lib/rails/generators/test_unit/mailer/templates/functional_test.rb2
-rw-r--r--railties/lib/rails/generators/test_unit/mailer/templates/preview.rb4
-rw-r--r--railties/lib/rails/generators/test_unit/model/model_generator.rb2
-rw-r--r--railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb15
-rw-r--r--railties/lib/rails/generators/test_unit/scaffold/templates/api_functional_test.rb43
-rw-r--r--railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb20
-rw-r--r--railties/lib/rails/generators/testing/assertions.rb4
-rw-r--r--railties/lib/rails/generators/testing/behaviour.rb21
-rw-r--r--railties/lib/rails/info_controller.rb25
-rw-r--r--railties/lib/rails/mailers_controller.rb34
-rw-r--r--railties/lib/rails/paths.rb10
-rw-r--r--railties/lib/rails/rack/logger.rb4
-rw-r--r--railties/lib/rails/ruby_version_check.rb6
-rw-r--r--railties/lib/rails/source_annotation_extractor.rb2
-rw-r--r--railties/lib/rails/tasks.rb9
-rw-r--r--railties/lib/rails/tasks/dev.rake15
-rw-r--r--railties/lib/rails/tasks/documentation.rake70
-rw-r--r--railties/lib/rails/tasks/engine.rake2
-rw-r--r--railties/lib/rails/tasks/framework.rake34
-rw-r--r--railties/lib/rails/tasks/initializers.rake6
-rw-r--r--railties/lib/rails/tasks/restart.rake5
-rw-r--r--railties/lib/rails/tasks/tmp.rake2
-rw-r--r--railties/lib/rails/templates/rails/mailers/email.html.erb35
-rw-r--r--railties/lib/rails/templates/rails/mailers/index.html.erb4
-rw-r--r--railties/lib/rails/templates/rails/mailers/mailer.html.erb2
-rw-r--r--railties/lib/rails/templates/rails/welcome/index.html.erb13
-rw-r--r--railties/lib/rails/test_help.rb15
-rw-r--r--railties/lib/rails/test_unit/minitest_plugin.rb88
-rw-r--r--railties/lib/rails/test_unit/reporter.rb64
-rw-r--r--railties/lib/rails/test_unit/sub_test_task.rb126
-rw-r--r--railties/lib/rails/test_unit/test_requirer.rb28
-rw-r--r--railties/lib/rails/test_unit/testing.rake34
133 files changed, 1396 insertions, 876 deletions
diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb
index b1f7c29b5a..fe789f3c2a 100644
--- a/railties/lib/rails.rb
+++ b/railties/lib/rails.rb
@@ -52,6 +52,11 @@ module Rails
end
end
+ # Returns a Pathname object of the current rails project,
+ # otherwise it returns nil if there is no project:
+ #
+ # Rails.root
+ # # => #<Pathname:/Users/someuser/some/path/project>
def root
application && application.config.root
end
@@ -94,6 +99,11 @@ module Rails
groups
end
+ # Returns a Pathname object of the public folder of the current
+ # rails project, otherwise it returns nil if there is no project:
+ #
+ # Rails.public_path
+ # # => #<Pathname:/Users/someuser/some/path/project/public>
def public_path
application && Pathname.new(application.paths["public"].first)
end
diff --git a/railties/lib/rails/api/task.rb b/railties/lib/rails/api/task.rb
index 4d49244807..a082932632 100644
--- a/railties/lib/rails/api/task.rb
+++ b/railties/lib/rails/api/task.rb
@@ -152,19 +152,5 @@ module Rails
File.read('RAILS_VERSION').strip
end
end
-
- class AppTask < Task
- def component_root_dir(gem_name)
- $:.grep(%r{#{gem_name}[\w.-]*/lib\z}).first[0..-5]
- end
-
- def api_dir
- 'doc/api'
- end
-
- def rails_version
- Rails::VERSION::STRING
- end
- end
end
end
diff --git a/railties/lib/rails/app_rails_loader.rb b/railties/lib/rails/app_loader.rb
index 39d8007333..a9fe21824e 100644
--- a/railties/lib/rails/app_rails_loader.rb
+++ b/railties/lib/rails/app_loader.rb
@@ -1,7 +1,8 @@
require 'pathname'
+require 'rails/version'
module Rails
- module AppRailsLoader
+ module AppLoader # :nodoc:
extend self
RUBY = Gem.ruby
@@ -9,7 +10,7 @@ module Rails
BUNDLER_WARNING = <<EOS
Looks like your app's ./bin/rails is a stub that was generated by Bundler.
-In Rails 4, your app's bin/ directory contains executables that are versioned
+In Rails #{Rails::VERSION::MAJOR}, your app's bin/ directory contains executables that are versioned
like any other source code, rather than stubs that are generated on demand.
Here's how to upgrade:
@@ -28,7 +29,7 @@ generate it and add it to source control:
EOS
- def exec_app_rails
+ def exec_app
original_cwd = Dir.pwd
loop do
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index 8da73db821..e81ec62a1d 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -1,4 +1,5 @@
require 'fileutils'
+require 'yaml'
require 'active_support/core_ext/hash/keys'
require 'active_support/core_ext/object/blank'
require 'active_support/key_generator'
@@ -6,8 +7,7 @@ require 'active_support/message_verifier'
require 'rails/engine'
module Rails
- # In Rails 3.0, a Rails::Application object was introduced which is nothing more than
- # an Engine but with the responsibility of coordinating the whole boot process.
+ # An Engine with the responsibility of coordinating the whole boot process.
#
# == Initialization
#
@@ -156,25 +156,20 @@ module Rails
self
end
- # Implements call according to the Rack API. It simply
- # dispatches the request to the underlying middleware stack.
- def call(env)
- env["ORIGINAL_FULLPATH"] = build_original_fullpath(env)
- env["ORIGINAL_SCRIPT_NAME"] = env["SCRIPT_NAME"]
- super(env)
- end
-
# Reload application routes regardless if they changed or not.
def reload_routes!
routes_reloader.reload!
end
- # Return the application's KeyGenerator
+ # Returns the application's KeyGenerator
def key_generator
# number of iterations selected based on consultation with the google security
# team. Details at https://github.com/rails/rails/pull/6952#issuecomment-7661220
@caching_key_generator ||=
if secrets.secret_key_base
+ unless secrets.secret_key_base.kind_of?(String)
+ raise ArgumentError, "`secret_key_base` for #{Rails.env} environment must be a type of String, change this value in `config/secrets.yml`"
+ end
key_generator = ActiveSupport::KeyGenerator.new(secrets.secret_key_base, iterations: 1000)
ActiveSupport::CachingKeyGenerator.new(key_generator)
else
@@ -227,7 +222,6 @@ module Rails
yaml = Pathname.new("#{paths["config"].existent.first}/#{name}.yml")
if yaml.exist?
- require "yaml"
require "erb"
(YAML.load(ERB.new(yaml.read).result) || {})[Rails.env] || {}
else
@@ -427,9 +421,9 @@ module Rails
# Return an array of railties respecting the order they're loaded
# and the order specified by the +railties_order+ config.
#
- # While when running initializers we need engines in reverse
- # order here when copying migrations from railties we need then in the same
- # order as given by +railties_order+
+ # While running initializers we need engines in reverse order here when
+ # copying migrations from railties ; we need them in the order given by
+ # +railties_order+.
def migration_railties # :nodoc:
ordered_railties.flatten - [self]
end
@@ -504,27 +498,28 @@ module Rails
default_stack.build_stack
end
- def build_original_fullpath(env) #:nodoc:
- path_info = env["PATH_INFO"]
- query_string = env["QUERY_STRING"]
- script_name = env["SCRIPT_NAME"]
-
- if query_string.present?
- "#{script_name}#{path_info}?#{query_string}"
- else
- "#{script_name}#{path_info}"
- end
- end
-
def validate_secret_key_config! #:nodoc:
if secrets.secret_key_base.blank?
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?
- raise "Missing `secret_token` and `secret_key_base` for '#{Rails.env}' environment, set these values in `config/secrets.yml`"
+ raise "Missing `secret_key_base` for '#{Rails.env}' environment, set this value in `config/secrets.yml`"
end
end
end
+
+ private
+
+ def build_request(env)
+ req = super
+ env["ORIGINAL_FULLPATH"] = req.fullpath
+ env["ORIGINAL_SCRIPT_NAME"] = req.script_name
+ req
+ end
+
+ def build_middleware
+ config.app_middleware + super
+ end
end
end
diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb
index 0f4d932749..9baf8aa742 100644
--- a/railties/lib/rails/application/bootstrap.rb
+++ b/railties/lib/rails/application/bootstrap.rb
@@ -63,7 +63,7 @@ INFO
Rails.cache = ActiveSupport::Cache.lookup_store(config.cache_store)
if Rails.cache.respond_to?(:middleware)
- config.middleware.insert_before("Rack::Runtime", Rails.cache.middleware)
+ config.middleware.insert_before(::Rack::Runtime, Rails.cache.middleware)
end
end
end
diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb
index 2821c8d757..ee9c87b5cf 100644
--- a/railties/lib/rails/application/configuration.rb
+++ b/railties/lib/rails/application/configuration.rb
@@ -6,17 +6,17 @@ require 'rails/source_annotation_extractor'
module Rails
class Application
class Configuration < ::Rails::Engine::Configuration
- attr_accessor :allow_concurrency, :asset_host, :assets, :autoflush_log,
+ attr_accessor :allow_concurrency, :asset_host, :autoflush_log,
:cache_classes, :cache_store, :consider_all_requests_local, :console,
:eager_load, :exceptions_app, :file_watcher, :filter_parameters,
:force_ssl, :helpers_paths, :logger, :log_formatter, :log_tags,
:railties_order, :relative_url_root, :secret_key_base, :secret_token,
- :serve_static_files, :ssl_options, :static_cache_control, :session_options,
- :time_zone, :reload_classes_only_on_change,
+ :serve_static_files, :ssl_options, :static_index, :public_file_server,
+ :session_options, :time_zone, :reload_classes_only_on_change,
:beginning_of_week, :filter_redirect, :x
attr_writer :log_level
- attr_reader :encoding
+ attr_reader :encoding, :api_only, :static_cache_control
def initialize(*)
super
@@ -27,7 +27,8 @@ module Rails
@filter_redirect = []
@helpers_paths = []
@serve_static_files = true
- @static_cache_control = nil
+ @static_index = "index"
+ @public_file_server = ActiveSupport::OrderedOptions.new
@force_ssl = false
@ssl_options = {}
@session_store = :cookie_store
@@ -35,7 +36,6 @@ module Rails
@time_zone = "UTC"
@beginning_of_week = :monday
@log_level = nil
- @middleware = app_middleware
@generators = app_generators
@cache_store = [ :file_store, "#{root}/tmp/cache/" ]
@railties_order = [:all]
@@ -48,22 +48,16 @@ module Rails
@eager_load = nil
@secret_token = nil
@secret_key_base = nil
+ @api_only = false
@x = Custom.new
+ end
+
+ def static_cache_control=(value)
+ ActiveSupport::Deprecation.warn("static_cache_control is deprecated and will be removed in Rails 5.1. " \
+ "Please use `config.public_file_server.headers = {'Cache-Control' => #{value}} " \
+ "instead.")
- @assets = ActiveSupport::OrderedOptions.new
- @assets.enabled = true
- @assets.paths = []
- @assets.precompile = [ Proc.new { |path, fn| fn =~ /app\/assets/ && !%w(.js .css).include?(File.extname(path)) },
- /(?:\/|\\|\A)application\.(css|js)$/ ]
- @assets.prefix = "/assets"
- @assets.version = '1.0'
- @assets.debug = false
- @assets.compile = true
- @assets.digest = false
- @assets.cache_store = [ :file_store, "#{root}/tmp/cache/assets/#{Rails.env}/" ]
- @assets.js_compressor = nil
- @assets.css_compressor = nil
- @assets.logger = nil
+ @static_cache_control = value
end
def encoding=(value)
@@ -74,6 +68,11 @@ module Rails
end
end
+ def api_only=(value)
+ @api_only = value
+ generators.api_only = value
+ end
+
def paths
@paths ||= begin
paths = super
diff --git a/railties/lib/rails/application/default_middleware_stack.rb b/railties/lib/rails/application/default_middleware_stack.rb
index 02eea82b0c..387d92db73 100644
--- a/railties/lib/rails/application/default_middleware_stack.rb
+++ b/railties/lib/rails/application/default_middleware_stack.rb
@@ -18,7 +18,10 @@ module Rails
middleware.use ::Rack::Sendfile, config.action_dispatch.x_sendfile_header
if config.serve_static_files
- middleware.use ::ActionDispatch::Static, paths["public"].first, config.static_cache_control
+ 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.static_index, headers: headers
end
if rack_cache = load_rack_cache
@@ -26,9 +29,29 @@ module Rails
middleware.use ::Rack::Cache, rack_cache
end
- middleware.use ::Rack::Lock unless allow_concurrency?
+ if config.allow_concurrency == false
+ # User has explicitly opted out of concurrent request
+ # handling: presumably their code is not threadsafe
+
+ middleware.use ::Rack::Lock
+
+ elsif config.allow_concurrency == :unsafe
+ # Do nothing, even if we know this is dangerous. This is the
+ # historical behaviour for true.
+
+ else
+ # Default concurrency setting: enabled, but safe
+
+ unless config.cache_classes && config.eager_load
+ # Without cache_classes + eager_load, the load interlock
+ # is required for proper operation
+
+ middleware.use ::ActionDispatch::LoadInterlock
+ end
+ end
+
middleware.use ::Rack::Runtime
- middleware.use ::Rack::MethodOverride
+ middleware.use ::Rack::MethodOverride unless config.api_only
middleware.use ::ActionDispatch::RequestId
# Must come after Rack::MethodOverride to properly log overridden methods
@@ -42,9 +65,9 @@ module Rails
end
middleware.use ::ActionDispatch::Callbacks
- middleware.use ::ActionDispatch::Cookies
+ middleware.use ::ActionDispatch::Cookies unless config.api_only
- if config.session_store
+ if !config.api_only && config.session_store
if config.force_ssl && !config.session_options.key?(:secure)
config.session_options[:secure] = true
end
@@ -52,7 +75,6 @@ module Rails
middleware.use ::ActionDispatch::Flash
end
- middleware.use ::ActionDispatch::ParamsParser
middleware.use ::Rack::Head
middleware.use ::Rack::ConditionalGet
middleware.use ::Rack::ETag, "no-cache"
@@ -65,14 +87,6 @@ module Rails
config.reload_classes_only_on_change != true || app.reloaders.map(&:updated?).any?
end
- def allow_concurrency?
- if config.allow_concurrency.nil?
- config.cache_classes && config.eager_load
- else
- config.allow_concurrency
- end
- end
-
def load_rack_cache
rack_cache = config.action_dispatch.rack_cache
return unless rack_cache
diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb
index 7a1bb1e25c..404e3c3e23 100644
--- a/railties/lib/rails/application/finisher.rb
+++ b/railties/lib/rails/application/finisher.rb
@@ -86,8 +86,10 @@ module Rails
# added in the hook are taken into account.
initializer :set_clear_dependencies_hook, group: :all do
callback = lambda do
- ActiveSupport::DescendantsTracker.clear
- ActiveSupport::Dependencies.clear
+ ActiveSupport::Dependencies.interlock.attempt_unloading do
+ ActiveSupport::DescendantsTracker.clear
+ ActiveSupport::Dependencies.clear
+ end
end
if config.reload_classes_only_on_change
@@ -108,6 +110,13 @@ module Rails
ActionDispatch::Reloader.to_cleanup(&callback)
end
end
+
+ # Disable dependency loading during request cycle
+ initializer :disable_dependency_loading do
+ if config.eager_load && config.cache_classes
+ ActiveSupport::Dependencies.unhook!
+ end
+ end
end
end
end
diff --git a/railties/lib/rails/application_controller.rb b/railties/lib/rails/application_controller.rb
index 9a29ec21cf..618a09a5b3 100644
--- a/railties/lib/rails/application_controller.rb
+++ b/railties/lib/rails/application_controller.rb
@@ -6,7 +6,7 @@ class Rails::ApplicationController < ActionController::Base # :nodoc:
def require_local!
unless local_request?
- render text: '<p>For security purposes, this information is only available to local requests.</p>', status: :forbidden
+ render html: '<p>For security purposes, this information is only available to local requests.</p>'.html_safe, status: :forbidden
end
end
diff --git a/railties/lib/rails/cli.rb b/railties/lib/rails/cli.rb
index dd70c272c6..a8794bc0de 100644
--- a/railties/lib/rails/cli.rb
+++ b/railties/lib/rails/cli.rb
@@ -1,8 +1,8 @@
-require 'rails/app_rails_loader'
+require 'rails/app_loader'
# If we are inside a Rails application this method performs an exec and thus
# the rest of this script is not run.
-Rails::AppRailsLoader.exec_app_rails
+Rails::AppLoader.exec_app
require 'rails/ruby_version_check'
Signal.trap("INT") { puts; exit(1) }
diff --git a/railties/lib/rails/code_statistics.rb b/railties/lib/rails/code_statistics.rb
index 0bdf63943f..fd352dc9b7 100644
--- a/railties/lib/rails/code_statistics.rb
+++ b/railties/lib/rails/code_statistics.rb
@@ -41,11 +41,9 @@ class CodeStatistics #:nodoc:
if File.directory?(path) && (/^\./ !~ file_name)
stats.add(calculate_directory_statistics(path, pattern))
+ elsif file_name =~ pattern
+ stats.add_by_file_path(path)
end
-
- next unless file_name =~ pattern
-
- stats.add_by_file_path(path)
end
stats
@@ -71,12 +69,12 @@ class CodeStatistics #:nodoc:
def print_header
print_splitter
- puts "| Name | Lines | LOC | Classes | Methods | M/C | LOC/M |"
+ puts "| Name | Lines | LOC | Classes | Methods | M/C | LOC/M |"
print_splitter
end
def print_splitter
- puts "+----------------------+-------+-------+---------+---------+-----+-------+"
+ puts "+----------------------+--------+--------+---------+---------+-----+-------+"
end
def print_line(name, statistics)
@@ -84,8 +82,8 @@ class CodeStatistics #:nodoc:
loc_over_m = (statistics.code_lines / statistics.methods) - 2 rescue loc_over_m = 0
puts "| #{name.ljust(20)} " \
- "| #{statistics.lines.to_s.rjust(5)} " \
- "| #{statistics.code_lines.to_s.rjust(5)} " \
+ "| #{statistics.lines.to_s.rjust(6)} " \
+ "| #{statistics.code_lines.to_s.rjust(6)} " \
"| #{statistics.classes.to_s.rjust(7)} " \
"| #{statistics.methods.to_s.rjust(7)} " \
"| #{m_over_c.to_s.rjust(3)} " \
diff --git a/railties/lib/rails/commands.rb b/railties/lib/rails/commands.rb
index f32bf772a5..12bd73db24 100644
--- a/railties/lib/rails/commands.rb
+++ b/railties/lib/rails/commands.rb
@@ -6,7 +6,8 @@ aliases = {
"c" => "console",
"s" => "server",
"db" => "dbconsole",
- "r" => "runner"
+ "r" => "runner",
+ "t" => "test",
}
command = ARGV.shift
diff --git a/railties/lib/rails/commands/commands_tasks.rb b/railties/lib/rails/commands/commands_tasks.rb
index 8bae08e44e..685d55eea8 100644
--- a/railties/lib/rails/commands/commands_tasks.rb
+++ b/railties/lib/rails/commands/commands_tasks.rb
@@ -14,6 +14,7 @@ The most common rails commands are:
generate Generate new code (short-cut alias: "g")
console Start the Rails console (short-cut alias: "c")
server Start the Rails server (short-cut alias: "s")
+ test Run tests (short-cut alias: "t")
dbconsole Start a console for the database specified in config/database.yml
(short-cut alias: "db")
new Create a new Rails application. "rails new my_app" creates a
@@ -27,7 +28,7 @@ In addition to those, there are:
All commands can be run with -h (or --help) for more information.
EOT
- COMMAND_WHITELIST = %w(plugin generate destroy console server dbconsole runner new version help)
+ COMMAND_WHITELIST = %w(plugin generate destroy console server dbconsole runner new version help test)
def initialize(argv)
@argv = argv
@@ -81,6 +82,10 @@ EOT
end
end
+ def test
+ require_command!("test")
+ end
+
def dbconsole
require_command!("dbconsole")
Rails::DBConsole.start
@@ -146,6 +151,17 @@ EOT
puts HELP_MESSAGE
end
+ # Output an error message stating that the attempted command is not a valid rails command.
+ # Run the attempted command as a rake command with the --dry-run flag. If successful, suggest
+ # to the user that they possibly meant to run the given rails command as a rake command.
+ # Append the help message.
+ #
+ # Example:
+ # $ rails db:migrate
+ # Error: Command 'db:migrate' not recognized
+ # Did you mean: `$ rake db:migrate` ?
+ # (Help message output)
+ #
def write_error_message(command)
puts "Error: Command '#{command}' not recognized"
if %x{rake #{command} --dry-run 2>&1 } && $?.success?
diff --git a/railties/lib/rails/commands/console.rb b/railties/lib/rails/commands/console.rb
index 35a815a34f..ea5d20ea24 100644
--- a/railties/lib/rails/commands/console.rb
+++ b/railties/lib/rails/commands/console.rb
@@ -1,14 +1,13 @@
require 'optparse'
require 'irb'
require 'irb/completion'
+require 'rails/commands/console_helper'
module Rails
class Console
- class << self
- def start(*args)
- new(*args).start
- end
+ include ConsoleHelper
+ class << self
def parse_arguments(arguments)
options = {}
@@ -21,23 +20,8 @@ module Rails
opt.parse!(arguments)
end
- if arguments.first && arguments.first[0] != '-'
- env = arguments.first
- if available_environments.include? env
- options[:environment] = env
- else
- options[:environment] = %w(production development test).detect {|e| e =~ /^#{env}/} || env
- end
- end
-
- options
+ set_options_env(arguments, options)
end
-
- private
-
- def available_environments
- Dir['config/environments/*.rb'].map { |fname| File.basename(fname, '.*') }
- end
end
attr_reader :options, :app, :console
@@ -57,12 +41,9 @@ module Rails
end
def environment
- options[:environment] ||= ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
- end
-
- def environment?
- environment
+ options[:environment] ||= super
end
+ alias_method :environment?, :environment
def set_environment!
Rails.env = environment
@@ -79,7 +60,7 @@ module Rails
end
if defined?(console::ExtendCommandBundle)
- console::ExtendCommandBundle.send :include, Rails::ConsoleMethods
+ console::ExtendCommandBundle.include(Rails::ConsoleMethods)
end
console.start
end
diff --git a/railties/lib/rails/commands/console_helper.rb b/railties/lib/rails/commands/console_helper.rb
new file mode 100644
index 0000000000..8ee0b60012
--- /dev/null
+++ b/railties/lib/rails/commands/console_helper.rb
@@ -0,0 +1,34 @@
+require 'active_support/concern'
+
+module Rails
+ module ConsoleHelper # :nodoc:
+ extend ActiveSupport::Concern
+
+ module ClassMethods
+ def start(*args)
+ new(*args).start
+ end
+
+ private
+ def set_options_env(arguments, options)
+ if arguments.first && arguments.first[0] != '-'
+ env = arguments.first
+ if available_environments.include? env
+ options[:environment] = env
+ else
+ options[:environment] = %w(production development test).detect { |e| e =~ /^#{env}/ } || env
+ end
+ end
+ options
+ end
+
+ def available_environments
+ Dir['config/environments/*.rb'].map { |fname| File.basename(fname, '.*') }
+ end
+ end
+
+ def environment
+ ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
+ end
+ end
+end \ No newline at end of file
diff --git a/railties/lib/rails/commands/dbconsole.rb b/railties/lib/rails/commands/dbconsole.rb
index 63bf8b11ba..dca60f948f 100644
--- a/railties/lib/rails/commands/dbconsole.rb
+++ b/railties/lib/rails/commands/dbconsole.rb
@@ -1,13 +1,49 @@
require 'erb'
require 'yaml'
require 'optparse'
+require 'rails/commands/console_helper'
module Rails
class DBConsole
+ include ConsoleHelper
+
attr_reader :arguments
- def self.start
- new.start
+ class << self
+ def parse_arguments(arguments)
+ options = {}
+
+ OptionParser.new do |opt|
+ opt.banner = "Usage: rails dbconsole [environment] [options]"
+ opt.on("-p", "--include-password", "Automatically provide the password from database.yml") do |v|
+ options['include_password'] = true
+ end
+
+ opt.on("--mode [MODE]", ['html', 'list', 'line', 'column'],
+ "Automatically put the sqlite3 database in the specified mode (html, list, line, column).") do |mode|
+ options['mode'] = mode
+ end
+
+ opt.on("--header") do |h|
+ options['header'] = h
+ end
+
+ opt.on("-h", "--help", "Show this help message.") do
+ puts opt
+ exit
+ end
+
+ opt.on("-e", "--environment=name", String,
+ "Specifies the environment to run this console under (test/development/production).",
+ "Default: development"
+ ) { |v| options[:environment] = v.strip }
+
+ opt.parse!(arguments)
+ abort opt.to_s unless (0..1).include?(arguments.size)
+ end
+
+ set_options_env(arguments, options)
+ end
end
def initialize(arguments = ARGV)
@@ -15,7 +51,7 @@ module Rails
end
def start
- options = parse_arguments(arguments)
+ options = self.class.parse_arguments(arguments)
ENV['RAILS_ENV'] = options[:environment] || environment
case config["adapter"]
@@ -50,9 +86,6 @@ module Rails
ENV['PGPASSWORD'] = config["password"].to_s if config["password"] && options['include_password']
find_cmd_and_exec('psql', config["database"])
- when "sqlite"
- find_cmd_and_exec('sqlite', config["database"])
-
when "sqlite3"
args = []
@@ -89,7 +122,7 @@ module Rails
find_cmd_and_exec("sqsh", *args)
else
- abort "Unknown command-line client for #{config['database']}. Submit a Rails patch to add support!"
+ abort "Unknown command-line client for #{config['database']}."
end
end
@@ -104,88 +137,37 @@ module Rails
end
def environment
- if Rails.respond_to?(:env)
- Rails.env
- else
- ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
- end
+ Rails.respond_to?(:env) ? Rails.env : super
end
protected
+ def configurations
+ require APP_PATH
+ ActiveRecord::Base.configurations = Rails.application.config.database_configuration
+ ActiveRecord::Base.configurations
+ end
- def configurations
- require APP_PATH
- ActiveRecord::Base.configurations = Rails.application.config.database_configuration
- ActiveRecord::Base.configurations
- end
-
- def parse_arguments(arguments)
- options = {}
-
- OptionParser.new do |opt|
- opt.banner = "Usage: rails dbconsole [environment] [options]"
- opt.on("-p", "--include-password", "Automatically provide the password from database.yml") do |v|
- options['include_password'] = true
- end
-
- opt.on("--mode [MODE]", ['html', 'list', 'line', 'column'],
- "Automatically put the sqlite3 database in the specified mode (html, list, line, column).") do |mode|
- options['mode'] = mode
- end
+ def find_cmd_and_exec(commands, *args)
+ commands = Array(commands)
- opt.on("--header") do |h|
- options['header'] = h
+ dirs_on_path = ENV['PATH'].to_s.split(File::PATH_SEPARATOR)
+ unless (ext = RbConfig::CONFIG['EXEEXT']).empty?
+ commands = commands.map{|cmd| "#{cmd}#{ext}"}
end
- opt.on("-h", "--help", "Show this help message.") do
- puts opt
- exit
+ full_path_command = nil
+ found = commands.detect do |cmd|
+ dirs_on_path.detect do |path|
+ full_path_command = File.join(path, cmd)
+ File.file?(full_path_command) && File.executable?(full_path_command)
+ end
end
- opt.on("-e", "--environment=name", String,
- "Specifies the environment to run this console under (test/development/production).",
- "Default: development"
- ) { |v| options[:environment] = v.strip }
-
- opt.parse!(arguments)
- abort opt.to_s unless (0..1).include?(arguments.size)
- end
-
- if arguments.first && arguments.first[0] != '-'
- env = arguments.first
- if available_environments.include? env
- options[:environment] = env
+ if found
+ exec full_path_command, *args
else
- options[:environment] = %w(production development test).detect {|e| e =~ /^#{env}/} || env
+ abort("Couldn't find database client: #{commands.join(', ')}. Check your $PATH and try again.")
end
end
-
- options
- end
-
- def available_environments
- Dir['config/environments/*.rb'].map { |fname| File.basename(fname, '.*') }
- end
-
- def find_cmd_and_exec(commands, *args)
- commands = Array(commands)
-
- dirs_on_path = ENV['PATH'].to_s.split(File::PATH_SEPARATOR)
- commands += commands.map{|cmd| "#{cmd}.exe"} if RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
-
- full_path_command = nil
- found = commands.detect do |cmd|
- dirs_on_path.detect do |path|
- full_path_command = File.join(path, cmd)
- File.file?(full_path_command) && File.executable?(full_path_command)
- end
- end
-
- if found
- exec full_path_command, *args
- else
- abort("Couldn't find database client: #{commands.join(', ')}. Check your $PATH and try again.")
- end
- end
end
end
diff --git a/railties/lib/rails/commands/server.rb b/railties/lib/rails/commands/server.rb
index bc8f1a8dea..d3ea441f8e 100644
--- a/railties/lib/rails/commands/server.rb
+++ b/railties/lib/rails/commands/server.rb
@@ -34,6 +34,9 @@ module Rails
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 ""
@@ -67,6 +70,7 @@ module Rails
print_boot_information
trap(:INT) { exit }
create_tmp_directories
+ setup_dev_caching
log_to_stdout if options[:log_stdout]
super
@@ -77,37 +81,32 @@ module Rails
end
def middleware
- middlewares = []
- middlewares << [::Rack::ContentLength]
-
- # FIXME: add Rack::Lock in the case people are using webrick.
- # This is to remain backwards compatible for those who are
- # running webrick in production. We should consider removing this
- # in development.
- if server.name == 'Rack::Handler::WEBrick'
- middlewares << [::Rack::Lock]
- end
-
- Hash.new(middlewares)
- end
-
- def log_path
- "log/#{options[:environment]}.log"
+ Hash.new([])
end
def default_options
super.merge({
- Port: 3000,
+ Port: ENV.fetch('PORT', 3000).to_i,
DoNotReverseLookup: true,
environment: (ENV['RAILS_ENV'] || ENV['RACK_ENV'] || "development").dup,
daemonize: false,
- pid: File.expand_path("tmp/pids/server.pid"),
- config: File.expand_path("config.ru")
+ caching: false,
+ pid: File.expand_path("tmp/pids/server.pid")
})
end
private
+ def setup_dev_caching
+ return unless options[:environment] == "development"
+
+ if options[:caching] == false
+ delete_cache_file
+ elsif options[:caching]
+ create_cache_file
+ end
+ end
+
def print_boot_information
url = "#{options[:SSLEnable] ? 'https' : 'http'}://#{options[:Host]}:#{options[:Port]}"
puts "=> Booting #{ActiveSupport::Inflector.demodulize(server)}"
@@ -117,6 +116,14 @@ module Rails
puts "=> Ctrl-C to shutdown server" unless options[:daemonize]
end
+ def create_cache_file
+ FileUtils.touch("tmp/caching-dev.txt")
+ end
+
+ def delete_cache_file
+ FileUtils.rm("tmp/caching-dev.txt") if File.exist?("tmp/caching-dev.txt")
+ end
+
def create_tmp_directories
%w(cache pids sockets).each do |dir_to_make|
FileUtils.mkdir_p(File.join(Rails.root, 'tmp', dir_to_make))
diff --git a/railties/lib/rails/commands/test.rb b/railties/lib/rails/commands/test.rb
new file mode 100644
index 0000000000..dd069f081f
--- /dev/null
+++ b/railties/lib/rails/commands/test.rb
@@ -0,0 +1,9 @@
+require "rails/test_unit/minitest_plugin"
+
+if defined?(ENGINE_ROOT)
+ $: << File.expand_path('test', ENGINE_ROOT)
+else
+ $: << File.expand_path('../../test', APP_PATH)
+end
+
+exit Minitest.run(ARGV)
diff --git a/railties/lib/rails/configuration.rb b/railties/lib/rails/configuration.rb
index f99cec04c5..30eafd59f2 100644
--- a/railties/lib/rails/configuration.rb
+++ b/railties/lib/rails/configuration.rb
@@ -33,8 +33,9 @@ module Rails
# config.middleware.delete ActionDispatch::Flash
#
class MiddlewareStackProxy
- def initialize
- @operations = []
+ def initialize(operations = [], delete_operations = [])
+ @operations = operations
+ @delete_operations = delete_operations
end
def insert_before(*args, &block)
@@ -56,7 +57,7 @@ module Rails
end
def delete(*args, &block)
- @operations << [__method__, args, block]
+ @delete_operations << [__method__, args, block]
end
def unshift(*args, &block)
@@ -64,15 +65,29 @@ module Rails
end
def merge_into(other) #:nodoc:
- @operations.each do |operation, args, block|
+ (@operations + @delete_operations).each do |operation, args, block|
other.send(operation, *args, &block)
end
+
other
end
+
+ def +(other) # :nodoc:
+ MiddlewareStackProxy.new(@operations + other.operations, @delete_operations + other.delete_operations)
+ end
+
+ protected
+ def operations
+ @operations
+ end
+
+ def delete_operations
+ @delete_operations
+ end
end
class Generators #:nodoc:
- attr_accessor :aliases, :options, :templates, :fallbacks, :colorize_logging
+ attr_accessor :aliases, :options, :templates, :fallbacks, :colorize_logging, :api_only
attr_reader :hidden_namespaces
def initialize
@@ -81,6 +96,7 @@ module Rails
@fallbacks = {}
@templates = []
@colorize_logging = true
+ @api_only = false
@hidden_namespaces = []
end
diff --git a/railties/lib/rails/console/app.rb b/railties/lib/rails/console/app.rb
index 2a69c26deb..ac5836a588 100644
--- a/railties/lib/rails/console/app.rb
+++ b/railties/lib/rails/console/app.rb
@@ -18,6 +18,11 @@ module Rails
app = Rails.application
session = ActionDispatch::Integration::Session.new(app)
yield session if block_given?
+
+ # This makes app.url_for and app.foo_path available in the console
+ session.extend(app.routes.url_helpers)
+ session.extend(app.routes.mounted_helpers)
+
session
end
diff --git a/railties/lib/rails/console/helpers.rb b/railties/lib/rails/console/helpers.rb
index b775f1ff8d..a33f71dc5b 100644
--- a/railties/lib/rails/console/helpers.rb
+++ b/railties/lib/rails/console/helpers.rb
@@ -4,7 +4,7 @@ module Rails
#
# This method assumes an +ApplicationController+ exists, and it extends +ActionController::Base+
def helper
- @helper ||= ApplicationController.helpers
+ ApplicationController.helpers
end
# Gets a new instance of a controller object.
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index a338f31f15..5757d235d2 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -2,11 +2,12 @@ require 'rails/railtie'
require 'rails/engine/railties'
require 'active_support/core_ext/module/delegation'
require 'pathname'
+require 'thread'
module Rails
# <tt>Rails::Engine</tt> allows you to wrap a specific Rails application or subset of
# functionality and share it with other applications or within a larger packaged application.
- # Since Rails 3.0, every <tt>Rails::Application</tt> is just an engine, which allows for simple
+ # Every <tt>Rails::Application</tt> is just an engine, which allows for simple
# feature and application sharing.
#
# Any <tt>Rails::Engine</tt> is also a <tt>Rails::Railtie</tt>, so the same
@@ -15,10 +16,9 @@ module Rails
#
# == Creating an Engine
#
- # In Rails versions prior to 3.0, your gems automatically behaved as engines, however,
- # this coupled Rails to Rubygems. Since Rails 3.0, if you want a gem to automatically
- # behave as an engine, you have to specify an +Engine+ for it somewhere inside
- # your plugin's +lib+ folder (similar to how we specify a +Railtie+):
+ # If you want a gem to behave as an engine, you have to specify an +Engine+
+ # for it somewhere inside your plugin's +lib+ folder (similar to how we
+ # specify a +Railtie+):
#
# # lib/my_engine.rb
# module MyEngine
@@ -69,10 +69,9 @@ module Rails
#
# == Paths
#
- # Since Rails 3.0, applications and engines have more flexible path configuration (as
- # opposed to the previous hardcoded path configuration). This means that you are not
- # required to place your controllers at <tt>app/controllers</tt>, but in any place
- # which you find convenient.
+ # Applications and engines have flexible path configuration, meaning that you
+ # are not required to place your controllers at <tt>app/controllers</tt>, but
+ # in any place which you find convenient.
#
# For example, let's suppose you want to place your controllers in <tt>lib/controllers</tt>.
# You can set that as an option:
@@ -206,42 +205,51 @@ module Rails
# With such an engine, everything that is inside the +MyEngine+ module will be isolated from
# the application.
#
- # Consider such controller:
+ # Consider this controller:
#
# module MyEngine
# class FooController < ActionController::Base
# end
# end
#
- # If an engine is marked as isolated, +FooController+ has access only to helpers from +Engine+ and
- # <tt>url_helpers</tt> from <tt>MyEngine::Engine.routes</tt>.
+ # If the +MyEngine+ engine is marked as isolated, +FooController+ only has
+ # access to helpers from +MyEngine+, and <tt>url_helpers</tt> from
+ # <tt>MyEngine::Engine.routes</tt>.
#
- # The next thing that changes in isolated engines is the behavior of routes. Normally, when you namespace
- # your controllers, you also need to do namespace all your routes. With an isolated engine,
- # the namespace is applied by default, so you can ignore it in routes:
+ # The next thing that changes in isolated engines is the behavior of routes.
+ # Normally, when you namespace your controllers, you also need to namespace
+ # the related routes. With an isolated engine, the engine's namespace is
+ # automatically applied, so you don't need to specify it explicity in your
+ # routes:
#
# MyEngine::Engine.routes.draw do
# resources :articles
# end
#
- # The routes above will automatically point to <tt>MyEngine::ArticlesController</tt>. Furthermore, you don't
- # need to use longer url helpers like <tt>my_engine_articles_path</tt>. Instead, you should simply use
- # <tt>articles_path</tt> as you would do with your application.
+ # If +MyEngine+ is isolated, The routes above will point to
+ # <tt>MyEngine::ArticlesController</tt>. You also don't need to use longer
+ # url helpers like +my_engine_articles_path+. Instead, you should simply use
+ # +articles_path+, like you would do with your main application.
#
- # To make that behavior consistent with other parts of the framework, an isolated engine also has influence on
- # <tt>ActiveModel::Naming</tt>. When you use a namespaced model, like <tt>MyEngine::Article</tt>, it will normally
- # use the prefix "my_engine". In an isolated engine, the prefix will be omitted in url helpers and
- # form fields for convenience.
+ # To make this behavior consistent with other parts of the framework,
+ # isolated engines also have an effect on <tt>ActiveModel::Naming</tt>. In a
+ # normal Rails app, when you use a namespaced model such as
+ # <tt>Namespace::Article</tt>, <tt>ActiveModel::Naming</tt> will generate
+ # names with the prefix "namespace". In an isolated engine, the prefix will
+ # be omitted in url helpers and form fields, for convenience.
#
- # polymorphic_url(MyEngine::Article.new) # => "articles_path"
+ # polymorphic_url(MyEngine::Article.new)
+ # # => "articles_path" # not "my_engine_articles_path"
#
# form_for(MyEngine::Article.new) do
# text_field :title # => <input type="text" name="article[title]" id="article_title" />
# end
#
- # Additionally, an isolated engine will set its name according to namespace, so
- # MyEngine::Engine.engine_name will be "my_engine". It will also set MyEngine.table_name_prefix
- # to "my_engine_", changing the MyEngine::Article model to use the my_engine_articles table.
+ # Additionally, an isolated engine will set its own name according to its
+ # namespace, so <tt>MyEngine::Engine.engine_name</tt> will return
+ # "my_engine". It will also set +MyEngine.table_name_prefix+ to "my_engine_",
+ # meaning for example that <tt>MyEngine::Article</tt> will use the
+ # +my_engine_articles+ database table by default.
#
# == Using Engine's routes outside Engine
#
@@ -296,7 +304,7 @@ module Rails
# helper MyEngine::SharedEngineHelper
# end
#
- # If you want to include all of the engine's helpers, you can use #helper method on an engine's
+ # If you want to include all of the engine's helpers, you can use the #helper method on an engine's
# instance:
#
# class ApplicationController < ActionController::Base
@@ -312,7 +320,7 @@ module Rails
# Engines can have their own migrations. The default path for migrations is exactly the same
# as in application: <tt>db/migrate</tt>
#
- # To use engine's migrations in application you can use rake task, which copies them to
+ # To use engine's migrations in application you can use the rake task below, which copies them to
# application's dir:
#
# rake ENGINE_NAME:install:migrations
@@ -328,7 +336,7 @@ module Rails
#
# == Loading priority
#
- # In order to change engine's priority you can use +config.railties_order+ in main application.
+ # In order to change engine's priority you can use +config.railties_order+ in the main application.
# It will affect the priority of loading views, helpers, assets and all the other files
# related to engine or application.
#
@@ -350,12 +358,7 @@ module Rails
Rails::Railtie::Configuration.eager_load_namespaces << base
base.called_from = begin
- call_stack = if Kernel.respond_to?(:caller_locations)
- caller_locations.map { |l| l.absolute_path || l.path }
- else
- # Remove the line number from backtraces making sure we don't leave anything behind
- caller.map { |p| p.sub(/:\d+.*/, '') }
- end
+ call_stack = caller_locations.map { |l| l.absolute_path || l.path }
File.dirname(call_stack.detect { |p| p !~ %r[railties[\w.-]*/lib/rails|rack[\w.-]*/lib/rack] })
end
@@ -405,7 +408,7 @@ module Rails
end
end
- # Finds engine with given path
+ # Finds engine with given path.
def find(path)
expanded_path = File.expand_path path
Rails::Engine.subclasses.each do |klass|
@@ -427,6 +430,7 @@ module Rails
@env_config = nil
@helpers = nil
@routes = nil
+ @app_build_lock = Mutex.new
super
end
@@ -484,7 +488,7 @@ module Rails
helpers = Module.new
all = ActionController::Base.all_helpers_from_path(helpers_paths)
ActionController::Base.modules_for_helpers(all).each do |mod|
- helpers.send(:include, mod)
+ helpers.include(mod)
end
helpers
end
@@ -497,10 +501,13 @@ module Rails
# Returns the underlying rack application for this engine.
def app
- @app ||= begin
- config.middleware = config.middleware.merge_into(default_middleware_stack)
- config.middleware.build(endpoint)
- end
+ @app || @app_build_lock.synchronize {
+ @app ||= begin
+ stack = default_middleware_stack
+ config.middleware = build_middleware.merge_into(stack)
+ config.middleware.build(endpoint)
+ end
+ }
end
# Returns the endpoint for this engine. If none is registered,
@@ -511,24 +518,19 @@ module Rails
# Define the Rack API for this engine.
def call(env)
- env.merge!(env_config)
- if env['SCRIPT_NAME']
- env["ROUTES_#{routes.object_id}_SCRIPT_NAME"] = env['SCRIPT_NAME'].dup
- end
- app.call(env)
+ req = build_request env
+ app.call req.env
end
# Defines additional Rack env configuration that is added on each call.
def env_config
- @env_config ||= {
- 'action_dispatch.routes' => routes
- }
+ @env_config ||= {}
end
# Defines the routes for this engine. If a block is given to
# routes, it is appended to the engine.
def routes
- @routes ||= ActionDispatch::Routing::RouteSet.new
+ @routes ||= ActionDispatch::Routing::RouteSet.new_with_config(config)
@routes.append(&Proc.new) if block_given?
@routes
end
@@ -559,7 +561,7 @@ module Rails
# and the load_once paths.
#
# This needs to be an initializer, since it needs to run once
- # per engine and get the engine as a block parameter
+ # per engine and get the engine as a block parameter.
initializer :set_autoload_paths, before: :bootstrap_hook do
ActiveSupport::Dependencies.autoload_paths.unshift(*_all_autoload_paths)
ActiveSupport::Dependencies.autoload_once_paths.unshift(*_all_autoload_once_paths)
@@ -582,7 +584,7 @@ module Rails
# I18n load paths are a special case since the ones added
# later have higher priority.
initializer :add_locales do
- config.i18n.railties_load_path.concat(paths["config/locales"].existent)
+ config.i18n.railties_load_path << paths["config/locales"]
end
initializer :add_view_paths do
@@ -599,12 +601,6 @@ module Rails
end
end
- initializer :append_assets_path, group: :all do |app|
- app.config.assets.paths.unshift(*paths["vendor/assets"].existent_directories)
- app.config.assets.paths.unshift(*paths["lib/assets"].existent_directories)
- app.config.assets.paths.unshift(*paths["app/assets"].existent_directories)
- end
-
initializer :prepend_helpers_path do |app|
if !isolated? || (app == self)
app.config.helpers_paths.unshift(*paths["app/helpers"].existent)
@@ -690,5 +686,19 @@ module Rails
def _all_load_paths #:nodoc:
@_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
+ req.routes = routes
+ req.engine_script_name = req.script_name
+ req
+ end
+
+ def build_middleware
+ config.middleware
+ end
end
end
diff --git a/railties/lib/rails/engine/commands.rb b/railties/lib/rails/engine/commands.rb
index f39f926109..a6d87b78e4 100644
--- a/railties/lib/rails/engine/commands.rb
+++ b/railties/lib/rails/engine/commands.rb
@@ -2,7 +2,8 @@ ARGV << '--help' if ARGV.empty?
aliases = {
"g" => "generate",
- "d" => "destroy"
+ "d" => "destroy",
+ "t" => "test"
}
command = ARGV.shift
@@ -12,7 +13,7 @@ require ENGINE_PATH
engine = ::Rails::Engine.find(ENGINE_ROOT)
case command
-when 'generate', 'destroy'
+when 'generate', 'destroy', 'test'
require 'rails/generators'
Rails::Generators.namespace = engine.railtie_namespace
engine.load_generators
@@ -30,6 +31,7 @@ Usage: rails COMMAND [ARGS]
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.
diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb
index 62a4139d07..8cadbc3ddd 100644
--- a/railties/lib/rails/engine/configuration.rb
+++ b/railties/lib/rails/engine/configuration.rb
@@ -4,17 +4,14 @@ module Rails
class Engine
class Configuration < ::Rails::Railtie::Configuration
attr_reader :root
- attr_writer :middleware, :eager_load_paths, :autoload_once_paths, :autoload_paths
+ attr_accessor :middleware
+ attr_writer :eager_load_paths, :autoload_once_paths, :autoload_paths
def initialize(root=nil)
super()
@root = root
@generators = app_generators.dup
- end
-
- # Returns the middleware stack for the engine.
- def middleware
- @middleware ||= Rails::Configuration::MiddlewareStackProxy.new
+ @middleware = Rails::Configuration::MiddlewareStackProxy.new
end
# Holds generators configuration:
@@ -29,7 +26,7 @@ module Rails
#
# config.generators.colorize_logging = false
#
- def generators #:nodoc:
+ def generators
@generators ||= Rails::Configuration::Generators.new
yield(@generators) if block_given?
@generators
diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb
index e25c364178..2645102619 100644
--- a/railties/lib/rails/generators.rb
+++ b/railties/lib/rails/generators.rb
@@ -33,6 +33,7 @@ module Rails
scaffold_controller: '-c',
stylesheets: '-y',
stylesheet_engine: '-se',
+ scaffold_stylesheet: '-ss',
template_engine: '-e',
test_framework: '-t'
},
@@ -44,6 +45,7 @@ module Rails
DEFAULT_OPTIONS = {
rails: {
+ api: false,
assets: true,
force_plural: false,
helper: true,
@@ -56,12 +58,14 @@ module Rails
scaffold_controller: :scaffold_controller,
stylesheets: true,
stylesheet_engine: :css,
+ scaffold_stylesheet: true,
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
@@ -99,6 +103,21 @@ module Rails
@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 views, 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
+ )
+ end
+
# Remove the color from output.
def self.no_color!
Thor::Base.shell = Thor::Shell::Basic
@@ -156,10 +175,10 @@ module Rails
args << "--help" if args.empty? && klass.arguments.any?(&:required?)
klass.start(args, config)
else
- options = sorted_groups.map(&:last).flatten
+ 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}'"}.join(" or ") }\n"
+ 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
@@ -260,19 +279,20 @@ module Rails
t = str2
n = s.length
m = t.length
- max = n/2
return m if (0 == n)
return n if (0 == m)
- return n if (n - m).abs > max
d = (0..m).to_a
x = nil
- str1.each_char.each_with_index do |char1,i|
+ # avoid duplicating an enumerable object in the loop
+ str2_codepoint_enumerable = str2.each_codepoint
+
+ str1.each_codepoint.with_index do |char1, i|
e = i+1
- str2.each_char.each_with_index do |char2,j|
+ str2_codepoint_enumerable.with_index do |char2, j|
cost = (char1 == char2) ? 0 : 1
x = [
d[j+1] + 1, # insertion
@@ -286,7 +306,7 @@ module Rails
d[m] = x
end
- return x
+ x
end
# Prints a list of generators.
diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb
index e35015f630..b4356f71e0 100644
--- a/railties/lib/rails/generators/actions.rb
+++ b/railties/lib/rails/generators/actions.rb
@@ -63,12 +63,26 @@ module Rails
# Add the given source to +Gemfile+
#
+ # If block is given, gem entries in block are wrapped into the source group.
+ #
# add_source "http://gems.github.com/"
- def add_source(source, options={})
+ #
+ # add_source "http://gems.github.com/" do
+ # gem "rspec-rails"
+ # end
+ def add_source(source, options={}, &block)
log :source, source
in_root do
- prepend_file "Gemfile", "source #{quote(source)}\n", verbose: false
+ if block
+ append_file "Gemfile", "source #{quote(source)} do", force: true
+ @in_group = true
+ instance_eval(&block)
+ @in_group = false
+ append_file "Gemfile", "\nend\n", force: true
+ else
+ prepend_file "Gemfile", "source #{quote(source)}\n", verbose: false
+ end
end
end
@@ -78,11 +92,11 @@ module Rails
# file in <tt>config/environments</tt>.
#
# environment do
- # "config.autoload_paths += %W(#{config.root}/extras)"
+ # "config.action_controller.asset_host = 'cdn.provider.com'"
# end
#
# environment(nil, env: "development") do
- # "config.autoload_paths += %W(#{config.root}/extras)"
+ # "config.action_controller.asset_host = 'localhost:3000'"
# end
def environment(data=nil, options={})
sentinel = /class [a-z_:]+ < Rails::Application/i
@@ -218,10 +232,10 @@ module Rails
# route "root 'welcome#index'"
def route(routing_code)
log :route, routing_code
- sentinel = /\.routes\.draw do\s*$/
+ sentinel = /\.routes\.draw do\s*\n/m
in_root do
- inject_into_file 'config/routes.rb', "\n #{routing_code}", { after: sentinel, verbose: false }
+ inject_into_file 'config/routes.rb', " #{routing_code}\n", { after: sentinel, verbose: false, force: true }
end
end
diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb
index 71186891a3..0f44f4694e 100644
--- a/railties/lib/rails/generators/app_base.rb
+++ b/railties/lib/rails/generators/app_base.rb
@@ -69,8 +69,8 @@ module Rails
class_option :skip_turbolinks, type: :boolean, default: false,
desc: 'Skip turbolinks gem'
- class_option :skip_test_unit, type: :boolean, aliases: '-T', default: false,
- desc: 'Skip Test::Unit files'
+ class_option :skip_test, type: :boolean, aliases: '-T', default: false,
+ desc: 'Skip test files'
class_option :rc, type: :string, default: false,
desc: "Path to file containing extra configuration options for rails command"
@@ -113,7 +113,6 @@ module Rails
assets_gemfile_entry,
javascript_gemfile_entry,
jbuilder_gemfile_entry,
- sdoc_gemfile_entry,
psych_gemfile_entry,
@extra_entries].flatten.find_all(&@gem_filter)
end
@@ -127,7 +126,7 @@ module Rails
def builder
@builder ||= begin
builder_class = get_builder_class
- builder_class.send(:include, ActionMethods)
+ builder_class.include(ActionMethods)
builder_class.new(self)
end
end
@@ -168,13 +167,17 @@ module Rails
end
def include_all_railties?
- options.values_at(:skip_active_record, :skip_action_mailer, :skip_test_unit, :skip_sprockets).none?
+ options.values_at(:skip_active_record, :skip_action_mailer, :skip_test, :skip_sprockets).none?
end
def comment_if(value)
options[value] ? '# ' : ''
end
+ def keeps?
+ !options[:skip_keeps]
+ end
+
def sqlite3?
!options[:skip_active_record] && options[:database] == 'sqlite3'
end
@@ -202,16 +205,21 @@ module Rails
end
def rails_gemfile_entry
+ dev_edge_common = [
+ GemfileEntry.github('sprockets-rails', 'rails/sprockets-rails'),
+ GemfileEntry.github('sprockets', 'rails/sprockets'),
+ GemfileEntry.github('sass-rails', 'rails/sass-rails'),
+ GemfileEntry.github('arel', 'rails/arel'),
+ GemfileEntry.github('rack', 'rack/rack')
+ ]
if options.dev?
[
- GemfileEntry.path('rails', Rails::Generators::RAILS_DEV_PATH),
- GemfileEntry.github('arel', 'rails/arel')
- ]
+ GemfileEntry.path('rails', Rails::Generators::RAILS_DEV_PATH)
+ ] + dev_edge_common
elsif options.edge?
[
- GemfileEntry.github('rails', 'rails/rails'),
- GemfileEntry.github('arel', 'rails/arel')
- ]
+ GemfileEntry.github('rails', 'rails/rails')
+ ] + dev_edge_common
else
[GemfileEntry.version('rails',
Rails::VERSION::STRING,
@@ -250,8 +258,6 @@ module Rails
return [] if options[:skip_sprockets]
gems = []
- gems << GemfileEntry.version('sass-rails', '~> 5.0',
- 'Use SCSS for stylesheets')
gems << GemfileEntry.version('uglifier',
'>= 1.3.0',
@@ -261,15 +267,12 @@ module Rails
end
def jbuilder_gemfile_entry
+ return [] if options[:api]
+
comment = 'Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder'
GemfileEntry.version('jbuilder', '~> 2.0', comment)
end
- def sdoc_gemfile_entry
- comment = 'bundle exec rake doc:rails generates the API under doc/api.'
- GemfileEntry.new('sdoc', '~> 0.4.0', comment, group: :doc)
- end
-
def coffee_gemfile_entry
comment = 'Use CoffeeScript for .coffee assets and views'
if options.dev? || options.edge?
@@ -297,7 +300,7 @@ module Rails
end
def javascript_runtime_gemfile_entry
- comment = 'See https://github.com/sstephenson/execjs#readme for more supported runtimes'
+ comment = 'See https://github.com/rails/execjs#readme for more supported runtimes'
if defined?(JRUBY_VERSION)
GemfileEntry.version 'therubyrhino', nil, comment
else
@@ -321,10 +324,6 @@ module Rails
# its own vendored Thor, which could be a different version. Running both
# things in the same process is a recipe for a night with paracetamol.
#
- # We use backticks and #print here instead of vanilla #system because it
- # is easier to silence stdout in the existing test suite this way. The
- # end-user gets the bundler commands called anyway, so no big deal.
- #
# We unset temporary bundler variables to load proper bundler and Gemfile.
#
# Thanks to James Tucker for the Gem tricks involved in this call.
@@ -332,8 +331,12 @@ module Rails
require 'bundler'
Bundler.with_clean_env do
- output = `"#{Gem.ruby}" "#{_bundle_command}" #{command}`
- print output unless options[:quiet]
+ full_command = %Q["#{Gem.ruby}" "#{_bundle_command}" #{command}]
+ if options[:quiet]
+ system(full_command, out: File::NULL)
+ else
+ system(full_command)
+ end
end
end
@@ -342,7 +345,7 @@ module Rails
end
def spring_install?
- !options[:skip_spring] && Process.respond_to?(:fork) && !RUBY_PLATFORM.include?("cygwin")
+ !options[:skip_spring] && !options.dev? && Process.respond_to?(:fork) && !RUBY_PLATFORM.include?("cygwin")
end
def run_bundle
@@ -361,7 +364,7 @@ module Rails
end
def keep_file(destination)
- create_file("#{destination}/.keep") unless options[:skip_keeps]
+ create_file("#{destination}/.keep") if keeps?
end
end
end
diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb
index 813b8b629e..c72ec400a0 100644
--- a/railties/lib/rails/generators/base.rb
+++ b/railties/lib/rails/generators/base.rb
@@ -103,12 +103,12 @@ module Rails
# hook_for :test_framework, as: :controller
# end
#
- # And now it will lookup at:
+ # And now it will look up at:
#
# "test_unit:controller", "test_unit"
#
- # Similarly, if you want it to also lookup in the rails namespace, you just
- # need to provide the :in value:
+ # Similarly, if you want it to also look up in the rails namespace, you
+ # just need to provide the :in value:
#
# class AwesomeGenerator < Rails::Generators::Base
# hook_for :test_framework, in: :rails, as: :controller
@@ -302,13 +302,13 @@ module Rails
default_for_option(Rails::Generators.options, name, options, options[:default])
end
- # Return default aliases for the option name given doing a lookup in
+ # Returns default aliases for the option name given doing a lookup in
# Rails::Generators.aliases.
def self.default_aliases_for_option(name, options)
default_for_option(Rails::Generators.aliases, name, options, options[:aliases])
end
- # Return default for the option name given doing a lookup in config.
+ # Returns default for the option name given doing a lookup in config.
def self.default_for_option(config, name, options, default)
if generator_name and c = config[generator_name.to_sym] and c.key?(name)
c[name]
diff --git a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb
index 7d27321610..65563aa6db 100644
--- a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb
+++ b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb
@@ -6,7 +6,7 @@ module Erb # :nodoc:
argument :actions, type: :array, default: [], banner: "method method"
def copy_view_files
- view_base_path = File.join("app/views", class_path, file_name)
+ view_base_path = File.join("app/views", class_path, file_name + '_mailer')
empty_directory view_base_path
if self.behavior == :invoke
@@ -31,6 +31,10 @@ module Erb # :nodoc:
def formats
[:text, :html]
end
+
+ def file_name
+ @_file_name ||= super.gsub(/\_mailer/i, '')
+ end
end
end
end
diff --git a/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb
index d9713b0238..d99b27cb2d 100644
--- a/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb
+++ b/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb
@@ -17,6 +17,7 @@
<%%= f.label :password %><br>
<%%= f.password_field :password %>
</div>
+
<div class="field">
<%%= f.label :password_confirmation %><br>
<%%= f.password_field :password_confirmation %>
@@ -25,6 +26,7 @@
<%%= f.<%= attribute.field_type %> :<%= attribute.column_name %> %>
<% end -%>
</div>
+
<% end -%>
<div class="actions">
<%%= f.submit %>
diff --git a/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb
index c3b8ef1181..5f4904fee1 100644
--- a/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb
+++ b/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb
@@ -28,4 +28,4 @@
<br>
-<%%= link_to 'New <%= human_name %>', new_<%= singular_table_name %>_path %>
+<%%= link_to 'New <%= singular_table_name.titleize %>', new_<%= singular_table_name %>_path %>
diff --git a/railties/lib/rails/generators/migration.rb b/railties/lib/rails/generators/migration.rb
index cd388e590a..87f2e1d42b 100644
--- a/railties/lib/rails/generators/migration.rb
+++ b/railties/lib/rails/generators/migration.rb
@@ -3,29 +3,29 @@ require 'rails/generators/actions/create_migration'
module Rails
module Generators
- # Holds common methods for migrations. It assumes that migrations has the
- # [0-9]*_name format and can be used by another frameworks (like Sequel)
+ # Holds common methods for migrations. It assumes that migrations have the
+ # [0-9]*_name format and can be used by other frameworks (like Sequel)
# just by implementing the next migration version method.
module Migration
extend ActiveSupport::Concern
attr_reader :migration_number, :migration_file_name, :migration_class_name
- module ClassMethods
- def migration_lookup_at(dirname) #:nodoc:
+ module ClassMethods #:nodoc:
+ def migration_lookup_at(dirname)
Dir.glob("#{dirname}/[0-9]*_*.rb")
end
- def migration_exists?(dirname, file_name) #:nodoc:
+ def migration_exists?(dirname, file_name)
migration_lookup_at(dirname).grep(/\d+_#{file_name}.rb$/).first
end
- def current_migration_number(dirname) #:nodoc:
+ def current_migration_number(dirname)
migration_lookup_at(dirname).collect do |file|
File.basename(file).split("_").first.to_i
end.max.to_i
end
- def next_migration_number(dirname) #:nodoc:
+ def next_migration_number(dirname)
raise NotImplementedError
end
end
diff --git a/railties/lib/rails/generators/named_base.rb b/railties/lib/rails/generators/named_base.rb
index 36456e64f5..243694f38e 100644
--- a/railties/lib/rails/generators/named_base.rb
+++ b/railties/lib/rails/generators/named_base.rb
@@ -18,8 +18,8 @@ module Rails
parse_attributes! if respond_to?(:attributes)
end
- # Defines the template that would be used for the migration file.
- # The arguments include the source template file, the migration filename etc.
+ # Overrides <tt>Thor::Actions#template</tt> so it can tell if
+ # a template is currently being created.
no_tasks do
def template(source, *args, &block)
inside_template do
@@ -141,6 +141,10 @@ module Rails
@plural_file_name ||= file_name.pluralize
end
+ def fixture_file_name
+ @fixture_file_name ||= (pluralize_table_names? ? plural_file_name : file_name)
+ end
+
def route_url
@route_url ||= class_path.collect {|dname| "/" + dname }.join + "/" + plural_file_name
end
@@ -179,6 +183,10 @@ module Rails
!defined?(ActiveRecord::Base) || ActiveRecord::Base.pluralize_table_names
end
+ def mountable_engine?
+ defined?(ENGINE_ROOT) && namespaced?
+ end
+
# Add a class collisions name to be checked on class initialization. You
# can supply a hash with a :prefix or :suffix to be tested.
#
diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb
index 0550bf113e..b813b083f4 100644
--- a/railties/lib/rails/generators/rails/app/app_generator.rb
+++ b/railties/lib/rails/generators/rails/app/app_generator.rb
@@ -38,7 +38,7 @@ module Rails
end
def readme
- copy_file "README.rdoc", "README.rdoc"
+ copy_file "README.md", "README.md"
end
def gemfile
@@ -89,6 +89,7 @@ module Rails
def config_when_updating
cookie_serializer_config_exist = File.exist?('config/initializers/cookies_serializer.rb')
callback_terminator_config_exist = File.exist?('config/initializers/callback_terminator.rb')
+ active_record_belongs_to_required_by_default_config_exist = File.exist?('config/initializers/active_record_belongs_to_required_by_default.rb')
config
@@ -99,6 +100,10 @@ module Rails
unless cookie_serializer_config_exist
gsub_file 'config/initializers/cookies_serializer.rb', /json/, 'marshal'
end
+
+ unless active_record_belongs_to_required_by_default_config_exist
+ remove_file 'config/initializers/active_record_belongs_to_required_by_default.rb'
+ end
end
def database_yml
@@ -125,6 +130,7 @@ module Rails
def test
empty_directory_with_keep_file 'test/fixtures'
+ empty_directory_with_keep_file 'test/fixtures/files'
empty_directory_with_keep_file 'test/controllers'
empty_directory_with_keep_file 'test/mailers'
empty_directory_with_keep_file 'test/models'
@@ -135,6 +141,7 @@ module Rails
end
def tmp
+ empty_directory_with_keep_file "tmp"
empty_directory "tmp/cache"
empty_directory "tmp/cache/assets"
end
@@ -168,6 +175,9 @@ module Rails
class_option :version, type: :boolean, aliases: "-v", group: :rails,
desc: "Show Rails version number and quit"
+ class_option :api, type: :boolean,
+ desc: "Preconfigure smaller stack for API only apps"
+
def initialize(*args)
super
@@ -178,6 +188,10 @@ module Rails
if !options[:skip_active_record] && !DATABASES.include?(options[:database])
raise Error, "Invalid value for --database option. Supported for preconfiguration are: #{DATABASES.join(", ")}."
end
+
+ # Force sprockets to be skipped when generating API only apps.
+ # Can't modify options hash as it's frozen by default.
+ self.options = options.merge(skip_sprockets: true, skip_javascript: true).freeze if options[:api]
end
public_task :set_default_accessors!
@@ -234,7 +248,7 @@ module Rails
end
def create_test_files
- build(:test) unless options[:skip_test_unit]
+ build(:test) unless options[:skip_test]
end
def create_tmp_files
@@ -245,6 +259,28 @@ module Rails
build(:vendor)
end
+ def delete_app_assets_if_api_option
+ if options[:api]
+ remove_dir 'app/assets'
+ remove_dir 'lib/assets'
+ remove_dir 'tmp/cache/assets'
+ remove_dir 'vendor/assets'
+ end
+ end
+
+ def delete_app_helpers_if_api_option
+ if options[:api]
+ remove_dir 'app/helpers'
+ remove_dir 'test/helpers'
+ end
+ end
+
+ def delete_app_views_if_api_option
+ if options[:api]
+ remove_dir 'app/views'
+ end
+ end
+
def delete_js_folder_skipping_javascript
if options[:skip_javascript]
remove_dir 'app/assets/javascripts'
@@ -257,6 +293,19 @@ module Rails
end
end
+ def delete_active_record_initializers_skipping_active_record
+ if options[:skip_active_record]
+ remove_file 'config/initializers/active_record_belongs_to_required_by_default.rb'
+ end
+ end
+
+ def delete_non_api_initializers_if_api_option
+ if options[:api]
+ remove_file 'config/initializers/session_store.rb'
+ remove_file 'config/initializers/cookies_serializer.rb'
+ end
+ end
+
def finish_template
build(:leftovers)
end
@@ -307,7 +356,9 @@ module Rails
if app_const =~ /^\d/
raise Error, "Invalid application name #{app_name}. Please give a name which does not start with numbers."
elsif RESERVED_NAMES.include?(app_name)
- raise Error, "Invalid application name #{app_name}. Please give a name which does not match one of the reserved rails words."
+ raise Error, "Invalid application name #{app_name}. Please give a " \
+ "name which does not match one of the reserved rails " \
+ "words: #{RESERVED_NAMES.join(", ")}"
elsif Object.const_defined?(app_const_base)
raise Error, "Invalid application name #{app_name}, constant #{app_const_base} is already in use. Please choose another application name."
end
diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile
index 143673f711..975be07622 100644
--- a/railties/lib/rails/generators/rails/app/templates/Gemfile
+++ b/railties/lib/rails/generators/rails/app/templates/Gemfile
@@ -21,29 +21,35 @@ source 'https://rubygems.org'
# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development
-group :development, :test do
+<%- if options.api? -%>
+# Use ActiveModelSerializers to serialize JSON responses
+gem 'active_model_serializers', '~> 0.10.0.rc2'
+
+# Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin AJAX possible
+# gem 'rack-cors'
+
+<%- 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'
+end
+group :development do
+<%- unless options.api? -%>
# Access an IRB console on exception pages or by using <%%= console %> in views
<%- if options.dev? || options.edge? -%>
- gem 'web-console', github: "rails/web-console"
+ gem 'web-console', github: 'rails/web-console'
<%- else -%>
gem 'web-console', '~> 2.0'
<%- end -%>
-<%- if spring_install? %>
+<%- end -%>
+<% if spring_install? -%>
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
gem 'spring'
<% end -%>
-
- # Adds `Method#source` and `Method#comment` to get the source code of a
- # method from the console
- gem 'method_source'
-<% end -%>
end
+<% end -%>
-<% if RUBY_PLATFORM.match(/bccwin|cygwin|emx|mingw|mswin|wince|java/) -%>
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
-<% end -%>
diff --git a/railties/lib/rails/generators/rails/app/templates/README.rdoc b/railties/lib/rails/generators/rails/app/templates/README.md
index dd4e97e22e..55e144da18 100644
--- a/railties/lib/rails/generators/rails/app/templates/README.rdoc
+++ b/railties/lib/rails/generators/rails/app/templates/README.md
@@ -1,4 +1,4 @@
-== README
+## README
This README would normally document whatever steps are necessary to get the
application up and running.
@@ -22,7 +22,3 @@ Things you may want to cover:
* Deployment instructions
* ...
-
-
-Please feel free to use a different markup language if you do not plan to run
-<tt>rake doc:app</tt>.
diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/config/manifest.js.tt b/railties/lib/rails/generators/rails/app/templates/app/assets/config/manifest.js.tt
new file mode 100644
index 0000000000..f80631bac6
--- /dev/null
+++ b/railties/lib/rails/generators/rails/app/templates/app/assets/config/manifest.js.tt
@@ -0,0 +1,8 @@
+
+<% unless options.api? -%>
+//= link_tree ../images
+<% end -%>
+<% unless options.skip_javascript -%>
+//= link_directory ../javascripts .js
+<% end -%>
+//= link_directory ../stylesheets .css
diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt
index c1a77944e8..c88426ec06 100644
--- a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt
+++ b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt
@@ -5,9 +5,9 @@
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
-// compiled file.
+// compiled file. JavaScript code in this file should be added after the last require_* statement.
//
-// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
+// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
<% unless options[:skip_javascript] -%>
diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css b/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css
index f9cd5b3483..0ebd7fe829 100644
--- a/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css
+++ b/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css
@@ -6,9 +6,9 @@
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
*
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
- * compiled file so the styles you add here take precedence over styles defined in any styles
- * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
- * file per style scope.
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
+ * files in this directory. Styles in this file should be added after the last require_* statement.
+ * It is generally better to create a new file per style scope.
*
*= require_tree .
*= require_self
diff --git a/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt b/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt
index d83690e1b9..f726fd6305 100644
--- a/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt
@@ -1,5 +1,7 @@
-class ApplicationController < ActionController::Base
+class ApplicationController < ActionController::<%= options[:api] ? "API" : "Base" %>
+<%- unless options[:api] -%>
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
+<%- end -%>
end
diff --git a/railties/lib/rails/generators/rails/app/templates/app/jobs/application_job.rb b/railties/lib/rails/generators/rails/app/templates/app/jobs/application_job.rb
new file mode 100644
index 0000000000..a009ace51c
--- /dev/null
+++ b/railties/lib/rails/generators/rails/app/templates/app/jobs/application_job.rb
@@ -0,0 +1,2 @@
+class ApplicationJob < ActiveJob::Base
+end
diff --git a/railties/lib/rails/generators/rails/app/templates/bin/setup b/railties/lib/rails/generators/rails/app/templates/bin/setup
index eee810be30..0c8b179827 100644
--- a/railties/lib/rails/generators/rails/app/templates/bin/setup
+++ b/railties/lib/rails/generators/rails/app/templates/bin/setup
@@ -5,13 +5,17 @@ include FileUtils
# path to your application root.
APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
+def system!(*args)
+ system(*args) || abort("\n== Command #{args} failed ==")
+end
+
chdir APP_ROOT do
# This script is a starting point to setup your application.
# Add necessary setup steps to this file.
puts '== Installing dependencies =='
- system 'gem install bundler --conservative'
- system('bundle check') or system('bundle install')
+ system! 'gem install bundler --conservative'
+ system('bundle check') or system!('bundle install')
# puts "\n== Copying sample files =="
# unless File.exist?('config/database.yml')
@@ -19,12 +23,11 @@ chdir APP_ROOT do
# end
puts "\n== Preparing database =="
- system 'ruby bin/rake db:setup'
+ system! 'ruby bin/rake db:setup'
puts "\n== Removing old logs and tempfiles =="
- rm_f Dir.glob('log/*')
- rm_rf 'tmp/cache'
+ system! 'ruby bin/rake log:clear tmp:clear'
puts "\n== Restarting application server =="
- touch 'tmp/restart.txt'
+ system! 'ruby bin/rake restart'
end
diff --git a/railties/lib/rails/generators/rails/app/templates/bin/update b/railties/lib/rails/generators/rails/app/templates/bin/update
new file mode 100644
index 0000000000..9830e6b29a
--- /dev/null
+++ b/railties/lib/rails/generators/rails/app/templates/bin/update
@@ -0,0 +1,28 @@
+require 'pathname'
+require 'fileutils'
+include FileUtils
+
+# path to your application root.
+APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
+
+def system!(*args)
+ system(*args) || abort("\n== Command #{args} failed ==")
+end
+
+chdir APP_ROOT do
+ # This script is a way to update your development environment automatically.
+ # Add necessary update steps to this file.
+
+ puts '== Installing dependencies =='
+ system! 'gem install bundler --conservative'
+ system 'bundle check' or system! 'bundle install'
+
+ puts "\n== Updating database =="
+ system! 'bin/rake db:migrate'
+
+ puts "\n== Removing old logs and tempfiles =="
+ system! 'bin/rake log:clear tmp:clear'
+
+ puts "\n== Restarting application server =="
+ system! 'bin/rake restart'
+end
diff --git a/railties/lib/rails/generators/rails/app/templates/config/application.rb b/railties/lib/rails/generators/rails/app/templates/config/application.rb
index 20ee229e97..ddd0fcade1 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/application.rb
+++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb
@@ -12,7 +12,7 @@ require "action_controller/railtie"
<%= comment_if :skip_action_mailer %>require "action_mailer/railtie"
require "action_view/railtie"
<%= comment_if :skip_sprockets %>require "sprockets/railtie"
-<%= comment_if :skip_test_unit %>require "rails/test_unit/railtie"
+<%= comment_if :skip_test %>require "rails/test_unit/railtie"
<% end -%>
# Require the gems listed in Gemfile, including any gems
@@ -26,11 +26,18 @@ module <%= app_const_base %>
# -- all .rb files in that directory are automatically loaded.
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
- # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
+ # Run "rake time:zones:all" for a time zone names list. Default is UTC.
# config.time_zone = 'Central Time (US & Canada)'
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
# config.i18n.default_locale = :de
+<%- if options[:api] -%>
+
+ # Only loads a smaller set of middleware suitable for API only apps.
+ # Middleware like session, flash, cookies can be added back manually.
+ # Skip views, helpers and assets when generating a new resource.
+ config.api_only = true
+<%- end -%>
end
end
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 acb93939e1..5ca549a8c8 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
@@ -7,7 +7,7 @@
# gem 'activerecord-jdbcmysql-adapter'
#
# And be sure to use new-style password hashing:
-# http://dev.mysql.com/doc/refman/5.0/en/old-client.html
+# http://dev.mysql.com/doc/refman/5.7/en/old-client.html
#
default: &default
adapter: mysql
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 596c916573..119c2fe2c3 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
@@ -7,7 +7,7 @@
# gem 'mysql2'
#
# And be sure to use new-style password hashing:
-# http://dev.mysql.com/doc/refman/5.0/en/old-client.html
+# http://dev.mysql.com/doc/refman/5.7/en/old-client.html
#
default: &default
adapter: mysql2
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
index ecb5d4170f..e29f0bacaa 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
@@ -9,9 +9,19 @@ Rails.application.configure do
# Do not eager load code on boot.
config.eager_load = false
- # Show full error reports and disable caching.
+ # Show full error reports.
config.consider_all_requests_local = true
- config.action_controller.perform_caching = false
+
+ # Enable/disable caching. By default caching is disabled.
+ if Rails.root.join('tmp/caching-dev.txt').exist?
+ config.action_controller.perform_caching = true
+ config.static_cache_control = "public, max-age=172800"
+ config.cache_store = :memory_store
+ else
+ config.action_controller.perform_caching = false
+ config.cache_store = :null_store
+ end
+
<%- unless options.skip_action_mailer? -%>
# Don't care if the mailer can't send.
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 75666d20c5..0297ab75f6 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
@@ -48,10 +48,11 @@ Rails.application.configure do
config.log_level = :debug
# Prepend all log lines with the following tags.
- # config.log_tags = [ :subdomain, :uuid ]
+ # config.log_tags = [ :subdomain, :request_id ]
# Use a different logger for distributed setups.
- # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
+ # require 'syslog/logger'
+ # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
# Use a different cache store in production.
# config.cache_store = :mem_cache_store
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt
index 0306deb18c..5165100c22 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt
@@ -13,8 +13,10 @@ Rails.application.configure do
config.eager_load = false
# Configure static file server for tests with Cache-Control for performance.
- config.serve_static_files = true
- config.static_cache_control = 'public, max-age=3600'
+ config.serve_static_files = true
+ config.public_file_server.headers = {
+ 'Cache-Control' => 'public, max-age=3600'
+ }
# Show full error reports and disable caching.
config.consider_all_requests_local = true
diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/active_record_belongs_to_required_by_default.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/active_record_belongs_to_required_by_default.rb
new file mode 100644
index 0000000000..30c4f89792
--- /dev/null
+++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/active_record_belongs_to_required_by_default.rb
@@ -0,0 +1,4 @@
+# Be sure to restart your server when you modify this file.
+
+# Require `belongs_to` associations by default.
+Rails.application.config.active_record.belongs_to_required_by_default = true
diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/application_controller_renderer.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/application_controller_renderer.rb
new file mode 100644
index 0000000000..ea930f54da
--- /dev/null
+++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/application_controller_renderer.rb
@@ -0,0 +1,6 @@
+## Change renderer defaults here.
+#
+# ApplicationController.renderer.defaults.merge!(
+# http_host: 'example.org',
+# https: false
+# )
diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/callback_terminator.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/callback_terminator.rb
index e63022da91..a70a1b9cde 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/initializers/callback_terminator.rb
+++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/callback_terminator.rb
@@ -1,4 +1,4 @@
# Be sure to restart your server when you modify this file.
# Do not halt callback chains when a callback returns false.
-Rails.application.config.active_support.halt_callback_chains_on_return_false = false
+ActiveSupport.halt_callback_chains_on_return_false = false
diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/cors.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/cors.rb
new file mode 100644
index 0000000000..9fca213a04
--- /dev/null
+++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/cors.rb
@@ -0,0 +1,14 @@
+# Avoid CORS issues when API is called from the frontend app
+# Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin AJAX requests
+
+# Read more: https://github.com/cyu/rack-cors
+
+# Rails.application.config.middleware.insert_before 0, Rack::Cors do
+# allow do
+# origins 'example.com'
+#
+# resource '*',
+# headers: :any,
+# methods: [:get, :post, :put, :patch, :delete, :options, :head]
+# end
+# end
diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt
index f2110c2c70..cadc85cfac 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt
@@ -5,12 +5,12 @@
# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
ActiveSupport.on_load(:action_controller) do
- wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
+ wrap_parameters format: [:json]
end
<%- unless options.skip_active_record? -%>
# To enable root element in JSON for ActiveRecord objects.
# ActiveSupport.on_load(:active_record) do
-# self.include_root_in_json = true
+# self.include_root_in_json = true
# end
<%- end -%>
diff --git a/railties/lib/rails/generators/rails/app/templates/config/routes.rb b/railties/lib/rails/generators/rails/app/templates/config/routes.rb
index 3f66539d54..787824f888 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/routes.rb
+++ b/railties/lib/rails/generators/rails/app/templates/config/routes.rb
@@ -1,56 +1,3 @@
Rails.application.routes.draw do
- # The priority is based upon order of creation: first created -> highest priority.
- # See how all your routes lay out with "rake routes".
-
- # You can have the root of your site routed with "root"
- # root 'welcome#index'
-
- # Example of regular route:
- # get 'products/:id' => 'catalog#view'
-
- # Example of named route that can be invoked with purchase_url(id: product.id)
- # get 'products/:id/purchase' => 'catalog#purchase', as: :purchase
-
- # Example resource route (maps HTTP verbs to controller actions automatically):
- # resources :products
-
- # Example resource route with options:
- # resources :products do
- # member do
- # get 'short'
- # post 'toggle'
- # end
- #
- # collection do
- # get 'sold'
- # end
- # end
-
- # Example resource route with sub-resources:
- # resources :products do
- # resources :comments, :sales
- # resource :seller
- # end
-
- # Example resource route with more complex sub-resources:
- # resources :products do
- # resources :comments
- # resources :sales do
- # get 'recent', on: :collection
- # end
- # end
-
- # Example resource route with concerns:
- # concern :toggleable do
- # post 'toggle'
- # end
- # resources :posts, concerns: :toggleable
- # resources :photos, concerns: :toggleable
-
- # Example resource route within a namespace:
- # namespace :admin do
- # # Directs /admin/products/* to Admin::ProductsController
- # # (app/controllers/admin/products_controller.rb)
- # resources :products
- # end
+ # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
diff --git a/railties/lib/rails/generators/rails/app/templates/gitignore b/railties/lib/rails/generators/rails/app/templates/gitignore
index 7c6f2098b8..1b8cf8a9fa 100644
--- a/railties/lib/rails/generators/rails/app/templates/gitignore
+++ b/railties/lib/rails/generators/rails/app/templates/gitignore
@@ -15,5 +15,8 @@
<% end -%>
# Ignore all logfiles and tempfiles.
/log/*
+/tmp/*
+<% if keeps? -%>
!/log/.keep
-/tmp
+!/tmp/.keep
+<% end -%>
diff --git a/railties/lib/rails/generators/rails/controller/controller_generator.rb b/railties/lib/rails/generators/rails/controller/controller_generator.rb
index df615c88b5..0a4c509a31 100644
--- a/railties/lib/rails/generators/rails/controller/controller_generator.rb
+++ b/railties/lib/rails/generators/rails/controller/controller_generator.rb
@@ -13,12 +13,14 @@ module Rails
def add_routes
unless options[:skip_routes]
actions.reverse_each do |action|
- route generate_routing_code(action)
+ # route prepends two spaces onto the front of the string that is passed, this corrects that.
+ route generate_routing_code(action)[2..-1]
end
end
end
- hook_for :template_engine, :test_framework, :helper, :assets
+ hook_for :template_engine, :test_framework
+ hook_for :helper, :assets, hide: true
private
@@ -36,12 +38,12 @@ module Rails
# 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)
+ indent(" namespace :#{ns} do\n", i * 2)
end.join
# Create route
# get 'baz/index'
- route = indent(%{get '#{file_name}/#{action}'\n}, depth * 2)
+ route = indent(%{ get '#{file_name}/#{action}'\n}, depth * 2)
# Create `end` ladder
# end
diff --git a/railties/lib/rails/generators/rails/model/USAGE b/railties/lib/rails/generators/rails/model/USAGE
index 8c3b63c3b4..11daa5c3cb 100644
--- a/railties/lib/rails/generators/rails/model/USAGE
+++ b/railties/lib/rails/generators/rails/model/USAGE
@@ -22,7 +22,7 @@ Description:
If you pass a namespaced model name (e.g. admin/account or Admin::Account)
then the generator will create a module with a table_name_prefix method
- to prefix the model's table name with the module name (e.g. admin_account)
+ to prefix the model's table name with the module name (e.g. admin_accounts)
Available field types:
@@ -79,10 +79,15 @@ Available field types:
`rails generate model product supplier:references{polymorphic}:index`
If you require a `password_digest` string column for use with
- has_secure_password, you should specify `password:digest`:
+ has_secure_password, you can specify `password:digest`:
`rails generate model user password:digest`
+ If you require a `token` string column for use with
+ has_secure_token, you can specify `auth_token:token`:
+
+ `rails generate model user auth_token:token`
+
Examples:
`rails generate model account`
diff --git a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb
index 1c270dd7d4..eeeef430bb 100644
--- a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb
+++ b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb
@@ -8,7 +8,7 @@ module Rails
# generator.
#
# This allows you to override entire operations, like the creation of the
- # Gemfile, README, or JavaScript files, without needing to know exactly
+ # Gemfile, \README, or JavaScript files, without needing to know exactly
# what those operations do so you can create another template action.
class PluginBuilder
def rakefile
@@ -17,15 +17,22 @@ module Rails
def app
if mountable?
- directory 'app'
- empty_directory_with_keep_file "app/assets/images/#{name}"
+ if api?
+ directory 'app', exclude_pattern: %r{app/(views|helpers)}
+ else
+ directory 'app'
+ empty_directory_with_keep_file "app/assets/images/#{namespaced_name}"
+ end
elsif full?
empty_directory_with_keep_file 'app/models'
empty_directory_with_keep_file 'app/controllers'
- empty_directory_with_keep_file 'app/views'
- empty_directory_with_keep_file 'app/helpers'
empty_directory_with_keep_file 'app/mailers'
- empty_directory_with_keep_file "app/assets/images/#{name}"
+
+ unless api?
+ empty_directory_with_keep_file "app/assets/images/#{namespaced_name}"
+ empty_directory_with_keep_file 'app/helpers'
+ empty_directory_with_keep_file 'app/views'
+ end
end
end
@@ -50,10 +57,10 @@ module Rails
end
def lib
- template "lib/%name%.rb"
- template "lib/tasks/%name%_tasks.rake"
- template "lib/%name%/version.rb"
- template "lib/%name%/engine.rb" if engine?
+ template "lib/%namespaced_name%.rb"
+ template "lib/tasks/%namespaced_name%_tasks.rake"
+ template "lib/%namespaced_name%/version.rb"
+ template "lib/%namespaced_name%/engine.rb" if engine?
end
def config
@@ -62,7 +69,7 @@ module Rails
def test
template "test/test_helper.rb"
- template "test/%name%_test.rb"
+ template "test/%namespaced_name%_test.rb"
append_file "Rakefile", <<-EOF
#{rakefile_test_tasks}
@@ -82,6 +89,7 @@ task default: :test
opts = (options || {}).slice(*PASSTHROUGH_OPTIONS)
opts[:force] = force
opts[:skip_bundle] = true
+ opts[:api] = options.api?
invoke Rails::Generators::AppGenerator,
[ File.expand_path(dummy_path, destination_root) ], opts
@@ -96,8 +104,9 @@ task default: :test
end
def test_dummy_assets
- template "rails/javascripts.js", "#{dummy_path}/app/assets/javascripts/application.js", force: true
- template "rails/stylesheets.css", "#{dummy_path}/app/assets/stylesheets/application.css", force: true
+ template "rails/javascripts.js", "#{dummy_path}/app/assets/javascripts/application.js", force: true
+ template "rails/stylesheets.css", "#{dummy_path}/app/assets/stylesheets/application.css", force: true
+ template "rails/dummy_manifest.js", "#{dummy_path}/app/assets/config/manifest.js", force: true
end
def test_dummy_clean
@@ -108,18 +117,22 @@ task default: :test
remove_file "Gemfile"
remove_file "lib/tasks"
remove_file "public/robots.txt"
- remove_file "README"
+ remove_file "README.md"
remove_file "test"
remove_file "vendor"
end
end
+ def assets_manifest
+ template "rails/engine_manifest.js", "app/assets/config/#{underscored_name}_manifest.js"
+ end
+
def stylesheets
if mountable?
copy_file "rails/stylesheets.css",
- "app/assets/stylesheets/#{name}/application.css"
+ "app/assets/stylesheets/#{namespaced_name}/application.css"
elsif full?
- empty_directory_with_keep_file "app/assets/stylesheets/#{name}"
+ empty_directory_with_keep_file "app/assets/stylesheets/#{namespaced_name}"
end
end
@@ -128,9 +141,9 @@ task default: :test
if mountable?
template "rails/javascripts.js",
- "app/assets/javascripts/#{name}/application.js"
+ "app/assets/javascripts/#{namespaced_name}/application.js"
elsif full?
- empty_directory_with_keep_file "app/assets/javascripts/#{name}"
+ empty_directory_with_keep_file "app/assets/javascripts/#{namespaced_name}"
end
end
@@ -176,6 +189,9 @@ task default: :test
desc: "If creating plugin in application's directory " +
"skip adding entry to Gemfile"
+ class_option :api, type: :boolean, default: false,
+ desc: "Generate a smaller stack for API application plugins"
+
def initialize(*args)
@dummy_path = nil
super
@@ -209,16 +225,16 @@ task default: :test
build(:lib)
end
- def create_public_stylesheets_files
- build(:stylesheets)
+ def create_assets_manifest_file
+ build(:assets_manifest) if !api? && engine?
end
- def create_javascript_files
- build(:javascripts)
+ def create_public_stylesheets_files
+ build(:stylesheets) unless api?
end
- def create_images_directory
- build(:images)
+ def create_javascript_files
+ build(:javascripts) unless api?
end
def create_bin_files
@@ -226,7 +242,7 @@ task default: :test
end
def create_test_files
- build(:test) unless options[:skip_test_unit]
+ build(:test) unless options[:skip_test]
end
def create_test_dummy_files
@@ -256,6 +272,14 @@ task default: :test
end
end
+ def underscored_name
+ @underscored_name ||= original_name.underscore
+ end
+
+ def namespaced_name
+ @namespaced_name ||= name.gsub('-', '/')
+ end
+
protected
def app_templates_dir
@@ -294,7 +318,11 @@ task default: :test
end
def with_dummy_app?
- options[:skip_test_unit].blank? || options[:dummy_path] != 'test/dummy'
+ options[:skip_test].blank? || options[:dummy_path] != 'test/dummy'
+ end
+
+ def api?
+ options[:api]
end
def self.banner
@@ -305,6 +333,27 @@ task default: :test
@original_name ||= File.basename(destination_root)
end
+ def modules
+ @modules ||= namespaced_name.camelize.split("::")
+ end
+
+ def wrap_in_modules(unwrapped_code)
+ unwrapped_code = "#{unwrapped_code}".strip.gsub(/\W$\n/, '')
+ modules.reverse.inject(unwrapped_code) do |content, mod|
+ str = "module #{mod}\n"
+ str += content.lines.map { |line| " #{line}" }.join
+ str += content.present? ? "\nend" : "end"
+ end
+ end
+
+ def camelized_modules
+ @camelized_modules ||= namespaced_name.camelize
+ end
+
+ def humanized
+ @humanized ||= original_name.underscore.humanize
+ end
+
def camelized
@camelized ||= name.gsub(/\W/, '_').squeeze('_').camelize
end
@@ -328,12 +377,16 @@ task default: :test
end
def valid_const?
- if original_name =~ /[^0-9a-zA-Z_]+/
- raise Error, "Invalid plugin name #{original_name}. Please give a name which use only alphabetic or numeric or \"_\" characters."
+ if original_name =~ /-\d/
+ raise Error, "Invalid plugin name #{original_name}. Please give a name which does not contain a namespace starting with numeric characters."
+ elsif original_name =~ /[^\w-]+/
+ raise Error, "Invalid plugin name #{original_name}. Please give a name which uses only alphabetic, numeric, \"_\" or \"-\" characters."
elsif camelized =~ /^\d/
raise Error, "Invalid plugin name #{original_name}. Please give a name which does not start with numbers."
elsif RESERVED_NAMES.include?(name)
- raise Error, "Invalid plugin name #{original_name}. Please give a name which does not match one of the reserved rails words."
+ raise Error, "Invalid plugin name #{original_name}. Please give a " \
+ "name which does not match one of the reserved rails " \
+ "words: #{RESERVED_NAMES.join(", ")}"
elsif Object.const_defined?(camelized)
raise Error, "Invalid plugin name #{original_name}, constant #{camelized} is already in use. Please choose another plugin name."
end
diff --git a/railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec b/railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec
index 919c349470..f8ece4fe73 100644
--- a/railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec
+++ b/railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec
@@ -1,21 +1,21 @@
$:.push File.expand_path("../lib", __FILE__)
# Maintain your gem's version:
-require "<%= name %>/version"
+require "<%= namespaced_name %>/version"
# Describe your gem and declare its dependencies:
Gem::Specification.new do |s|
s.name = "<%= name %>"
- s.version = <%= camelized %>::VERSION
+ s.version = <%= camelized_modules %>::VERSION
s.authors = ["<%= author %>"]
s.email = ["<%= email %>"]
s.homepage = "TODO"
- s.summary = "TODO: Summary of <%= camelized %>."
- s.description = "TODO: Description of <%= camelized %>."
+ s.summary = "TODO: Summary of <%= camelized_modules %>."
+ s.description = "TODO: Description of <%= camelized_modules %>."
s.license = "MIT"
s.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.rdoc"]
-<% unless options.skip_test_unit? -%>
+<% unless options.skip_test? -%>
s.test_files = Dir["test/**/*"]
<% end -%>
diff --git a/railties/lib/rails/generators/rails/plugin/templates/Gemfile b/railties/lib/rails/generators/rails/plugin/templates/Gemfile
index f325455bac..2c91c6a0ea 100644
--- a/railties/lib/rails/generators/rails/plugin/templates/Gemfile
+++ b/railties/lib/rails/generators/rails/plugin/templates/Gemfile
@@ -41,7 +41,7 @@ end
# To use a debugger
# gem 'byebug', group: [:development, :test]
<% end -%>
-
<% if RUBY_PLATFORM.match(/bccwin|cygwin|emx|mingw|mswin|wince|java/) -%>
+
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
<% end -%>
diff --git a/railties/lib/rails/generators/rails/plugin/templates/README.rdoc b/railties/lib/rails/generators/rails/plugin/templates/README.rdoc
index 301d647731..25983ca5da 100644
--- a/railties/lib/rails/generators/rails/plugin/templates/README.rdoc
+++ b/railties/lib/rails/generators/rails/plugin/templates/README.rdoc
@@ -1,3 +1,3 @@
-= <%= camelized %>
+= <%= camelized_modules %>
This project rocks and uses MIT-LICENSE. \ No newline at end of file
diff --git a/railties/lib/rails/generators/rails/plugin/templates/Rakefile b/railties/lib/rails/generators/rails/plugin/templates/Rakefile
index c338a0bdb1..bda55bae29 100644
--- a/railties/lib/rails/generators/rails/plugin/templates/Rakefile
+++ b/railties/lib/rails/generators/rails/plugin/templates/Rakefile
@@ -8,7 +8,7 @@ require 'rdoc/task'
RDoc::Task.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
- rdoc.title = '<%= camelized %>'
+ rdoc.title = '<%= camelized_modules %>'
rdoc.options << '--line-numbers'
rdoc.rdoc_files.include('README.rdoc')
rdoc.rdoc_files.include('lib/**/*.rb')
diff --git a/railties/lib/rails/generators/rails/plugin/templates/app/controllers/%name%/application_controller.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/controllers/%name%/application_controller.rb.tt
deleted file mode 100644
index 448ad7f989..0000000000
--- a/railties/lib/rails/generators/rails/plugin/templates/app/controllers/%name%/application_controller.rb.tt
+++ /dev/null
@@ -1,4 +0,0 @@
-module <%= camelized %>
- class ApplicationController < ActionController::Base
- end
-end
diff --git a/railties/lib/rails/generators/rails/plugin/templates/app/controllers/%namespaced_name%/application_controller.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/controllers/%namespaced_name%/application_controller.rb.tt
new file mode 100644
index 0000000000..7fe4e5034d
--- /dev/null
+++ b/railties/lib/rails/generators/rails/plugin/templates/app/controllers/%namespaced_name%/application_controller.rb.tt
@@ -0,0 +1,5 @@
+<%= wrap_in_modules <<-rb.strip_heredoc
+ class ApplicationController < ActionController::#{api? ? "API" : "Base"}
+ end
+rb
+%>
diff --git a/railties/lib/rails/generators/rails/plugin/templates/app/helpers/%name%/application_helper.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/helpers/%name%/application_helper.rb.tt
deleted file mode 100644
index 40ae9f52c2..0000000000
--- a/railties/lib/rails/generators/rails/plugin/templates/app/helpers/%name%/application_helper.rb.tt
+++ /dev/null
@@ -1,4 +0,0 @@
-module <%= camelized %>
- module ApplicationHelper
- end
-end
diff --git a/railties/lib/rails/generators/rails/plugin/templates/app/helpers/%namespaced_name%/application_helper.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/helpers/%namespaced_name%/application_helper.rb.tt
new file mode 100644
index 0000000000..25d692732d
--- /dev/null
+++ b/railties/lib/rails/generators/rails/plugin/templates/app/helpers/%namespaced_name%/application_helper.rb.tt
@@ -0,0 +1,5 @@
+<%= wrap_in_modules <<-rb.strip_heredoc
+ module ApplicationHelper
+ end
+rb
+%>
diff --git a/railties/lib/rails/generators/rails/plugin/templates/app/jobs/%namespaced_name%/application_job.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/jobs/%namespaced_name%/application_job.rb.tt
new file mode 100644
index 0000000000..bad1ff2d16
--- /dev/null
+++ b/railties/lib/rails/generators/rails/plugin/templates/app/jobs/%namespaced_name%/application_job.rb.tt
@@ -0,0 +1,5 @@
+<%= wrap_in_modules <<-rb.strip_heredoc
+ class ApplicationJob < ActiveJob::Base
+ end
+rb
+%>
diff --git a/railties/lib/rails/generators/rails/plugin/templates/app/views/layouts/%name%/application.html.erb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/views/layouts/%name%/application.html.erb.tt
deleted file mode 100644
index 1d380420b4..0000000000
--- a/railties/lib/rails/generators/rails/plugin/templates/app/views/layouts/%name%/application.html.erb.tt
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <title><%= camelized %></title>
- <%%= stylesheet_link_tag "<%= name %>/application", media: "all" %>
- <%%= javascript_include_tag "<%= name %>/application" %>
- <%%= csrf_meta_tags %>
-</head>
-<body>
-
-<%%= yield %>
-
-</body>
-</html>
diff --git a/railties/lib/rails/generators/rails/plugin/templates/app/views/layouts/%namespaced_name%/application.html.erb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/views/layouts/%namespaced_name%/application.html.erb.tt
new file mode 100644
index 0000000000..6bc480161d
--- /dev/null
+++ b/railties/lib/rails/generators/rails/plugin/templates/app/views/layouts/%namespaced_name%/application.html.erb.tt
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title><%= humanized %></title>
+ <%%= stylesheet_link_tag "<%= namespaced_name %>/application", media: "all" %>
+ <%%= javascript_include_tag "<%= namespaced_name %>/application" %>
+ <%%= csrf_meta_tags %>
+</head>
+<body>
+
+<%%= yield %>
+
+</body>
+</html>
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 c3314d7e68..3edaac35c9 100644
--- a/railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt
+++ b/railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt
@@ -1,7 +1,7 @@
# This command will automatically be run when you run "rails" with Rails 4 gems installed from the root of your application.
ENGINE_ROOT = File.expand_path('../..', __FILE__)
-ENGINE_PATH = File.expand_path('../../lib/<%= name -%>/engine', __FILE__)
+ENGINE_PATH = File.expand_path('../../lib/<%= namespaced_name -%>/engine', __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/config/routes.rb b/railties/lib/rails/generators/rails/plugin/templates/config/routes.rb
index 8e158d5831..154452bfe5 100644
--- a/railties/lib/rails/generators/rails/plugin/templates/config/routes.rb
+++ b/railties/lib/rails/generators/rails/plugin/templates/config/routes.rb
@@ -1,5 +1,5 @@
<% if mountable? -%>
-<%= camelized %>::Engine.routes.draw do
+<%= camelized_modules %>::Engine.routes.draw do
<% else -%>
Rails.application.routes.draw do
<% end -%>
diff --git a/railties/lib/rails/generators/rails/plugin/templates/gitignore b/railties/lib/rails/generators/rails/plugin/templates/gitignore
index 086d87818a..d524fcbc4e 100644
--- a/railties/lib/rails/generators/rails/plugin/templates/gitignore
+++ b/railties/lib/rails/generators/rails/plugin/templates/gitignore
@@ -1,10 +1,10 @@
.bundle/
log/*.log
pkg/
-<% unless options[:skip_test_unit] && options[:dummy_path] == 'test/dummy' -%>
+<% unless options[:skip_test] && options[:dummy_path] == 'test/dummy' -%>
<%= dummy_path %>/db/*.sqlite3
<%= dummy_path %>/db/*.sqlite3-journal
<%= dummy_path %>/log/*.log
<%= dummy_path %>/tmp/
<%= dummy_path %>/.sass-cache
-<% end -%> \ No newline at end of file
+<% end -%>
diff --git a/railties/lib/rails/generators/rails/plugin/templates/lib/%name%.rb b/railties/lib/rails/generators/rails/plugin/templates/lib/%name%.rb
deleted file mode 100644
index 40c074cced..0000000000
--- a/railties/lib/rails/generators/rails/plugin/templates/lib/%name%.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-<% if engine? -%>
-require "<%= name %>/engine"
-
-<% end -%>
-module <%= camelized %>
-end
diff --git a/railties/lib/rails/generators/rails/plugin/templates/lib/%name%/engine.rb b/railties/lib/rails/generators/rails/plugin/templates/lib/%name%/engine.rb
deleted file mode 100644
index 967668fe66..0000000000
--- a/railties/lib/rails/generators/rails/plugin/templates/lib/%name%/engine.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-module <%= camelized %>
- class Engine < ::Rails::Engine
-<% if mountable? -%>
- isolate_namespace <%= camelized %>
-<% end -%>
- end
-end
diff --git a/railties/lib/rails/generators/rails/plugin/templates/lib/%name%/version.rb b/railties/lib/rails/generators/rails/plugin/templates/lib/%name%/version.rb
deleted file mode 100644
index ef07ef2e19..0000000000
--- a/railties/lib/rails/generators/rails/plugin/templates/lib/%name%/version.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-module <%= camelized %>
- VERSION = "0.0.1"
-end
diff --git a/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%.rb b/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%.rb
new file mode 100644
index 0000000000..40b1c4cee7
--- /dev/null
+++ b/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%.rb
@@ -0,0 +1,5 @@
+<% if engine? -%>
+require "<%= namespaced_name %>/engine"
+
+<% end -%>
+<%= wrap_in_modules "# Your code goes here..." %>
diff --git a/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/engine.rb b/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/engine.rb
new file mode 100644
index 0000000000..8938770fc4
--- /dev/null
+++ b/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/engine.rb
@@ -0,0 +1,7 @@
+<%= wrap_in_modules <<-rb.strip_heredoc
+ class Engine < ::Rails::Engine
+ #{mountable? ? ' isolate_namespace ' + camelized_modules : ' '}
+ #{api? ? " config.generators.api_only = true" : ' '}
+ end
+rb
+%>
diff --git a/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/version.rb b/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/version.rb
new file mode 100644
index 0000000000..b08f4ef9ae
--- /dev/null
+++ b/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/version.rb
@@ -0,0 +1 @@
+<%= wrap_in_modules "VERSION = '0.1.0'" %>
diff --git a/railties/lib/rails/generators/rails/plugin/templates/lib/tasks/%name%_tasks.rake b/railties/lib/rails/generators/rails/plugin/templates/lib/tasks/%namespaced_name%_tasks.rake
index 7121f5ae23..88a2c4120f 100644
--- a/railties/lib/rails/generators/rails/plugin/templates/lib/tasks/%name%_tasks.rake
+++ b/railties/lib/rails/generators/rails/plugin/templates/lib/tasks/%namespaced_name%_tasks.rake
@@ -1,4 +1,4 @@
# desc "Explaining what the task does"
-# task :<%= name %> do
+# task :<%= underscored_name %> do
# # Task goes here
# end
diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb b/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb
index 3a9a7e5437..b1038c839e 100644
--- a/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb
+++ b/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb
@@ -9,10 +9,10 @@ require "action_controller/railtie"
<%= comment_if :skip_action_mailer %>require "action_mailer/railtie"
require "action_view/railtie"
<%= comment_if :skip_sprockets %>require "sprockets/railtie"
-<%= comment_if :skip_test_unit %>require "rails/test_unit/railtie"
+<%= comment_if :skip_test %>require "rails/test_unit/railtie"
<% end -%>
Bundler.require(*Rails.groups)
-require "<%= name %>"
+require "<%= namespaced_name %>"
<%= application_definition %>
diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/dummy_manifest.js b/railties/lib/rails/generators/rails/plugin/templates/rails/dummy_manifest.js
new file mode 100644
index 0000000000..8d21b2b6fb
--- /dev/null
+++ b/railties/lib/rails/generators/rails/plugin/templates/rails/dummy_manifest.js
@@ -0,0 +1,11 @@
+
+<% unless api? -%>
+//= link_tree ../images
+<% end -%>
+<% unless options.skip_javascript -%>
+//= link_directory ../javascripts .js
+<% end -%>
+//= link_directory ../stylesheets .css
+<% if mountable? && !api? -%>
+//= link <%= underscored_name %>_manifest.js
+<% end -%>
diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/engine_manifest.js b/railties/lib/rails/generators/rails/plugin/templates/rails/engine_manifest.js
new file mode 100644
index 0000000000..2f23844f5e
--- /dev/null
+++ b/railties/lib/rails/generators/rails/plugin/templates/rails/engine_manifest.js
@@ -0,0 +1,6 @@
+<% if mountable? -%>
+<% if !options.skip_javascript -%>
+//= link_directory ../javascripts/<%= namespaced_name %> .js
+<% end -%>
+//= link_directory ../stylesheets/<%= namespaced_name %> .css
+<% end -%>
diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js b/railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js
index c28e5badc6..e54c6461cc 100644
--- a/railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js
+++ b/railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js
@@ -5,9 +5,9 @@
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
-// compiled file.
+// compiled file. JavaScript code in this file should be added after the last require_* statement.
//
-// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
+// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require_tree .
diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/routes.rb b/railties/lib/rails/generators/rails/plugin/templates/rails/routes.rb
index 730ee31c3d..673de44108 100644
--- a/railties/lib/rails/generators/rails/plugin/templates/rails/routes.rb
+++ b/railties/lib/rails/generators/rails/plugin/templates/rails/routes.rb
@@ -1,4 +1,4 @@
Rails.application.routes.draw do
- mount <%= camelized %>::Engine => "/<%= name %>"
+ mount <%= camelized_modules %>::Engine => "/<%= name %>"
end
diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/stylesheets.css b/railties/lib/rails/generators/rails/plugin/templates/rails/stylesheets.css
index f9cd5b3483..0ebd7fe829 100644
--- a/railties/lib/rails/generators/rails/plugin/templates/rails/stylesheets.css
+++ b/railties/lib/rails/generators/rails/plugin/templates/rails/stylesheets.css
@@ -6,9 +6,9 @@
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
*
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
- * compiled file so the styles you add here take precedence over styles defined in any styles
- * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
- * file per style scope.
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
+ * files in this directory. Styles in this file should be added after the last require_* statement.
+ * It is generally better to create a new file per style scope.
*
*= require_tree .
*= require_self
diff --git a/railties/lib/rails/generators/rails/plugin/templates/test/%name%_test.rb b/railties/lib/rails/generators/rails/plugin/templates/test/%name%_test.rb
deleted file mode 100644
index 0a8bbd4aaf..0000000000
--- a/railties/lib/rails/generators/rails/plugin/templates/test/%name%_test.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require 'test_helper'
-
-class <%= camelized %>Test < ActiveSupport::TestCase
- test "truth" do
- assert_kind_of Module, <%= camelized %>
- end
-end
diff --git a/railties/lib/rails/generators/rails/plugin/templates/test/%namespaced_name%_test.rb b/railties/lib/rails/generators/rails/plugin/templates/test/%namespaced_name%_test.rb
new file mode 100644
index 0000000000..1ee05d7871
--- /dev/null
+++ b/railties/lib/rails/generators/rails/plugin/templates/test/%namespaced_name%_test.rb
@@ -0,0 +1,7 @@
+require 'test_helper'
+
+class <%= camelized_modules %>::Test < ActiveSupport::TestCase
+ test "truth" do
+ assert_kind_of Module, <%= camelized_modules %>
+ end
+end
diff --git a/railties/lib/rails/generators/rails/plugin/templates/test/integration/navigation_test.rb b/railties/lib/rails/generators/rails/plugin/templates/test/integration/navigation_test.rb
index 824caecb24..f5d1ec2046 100644
--- a/railties/lib/rails/generators/rails/plugin/templates/test/integration/navigation_test.rb
+++ b/railties/lib/rails/generators/rails/plugin/templates/test/integration/navigation_test.rb
@@ -1,10 +1,6 @@
require 'test_helper'
class NavigationTest < ActionDispatch::IntegrationTest
-<% unless options[:skip_active_record] -%>
- fixtures :all
-<% end -%>
-
# test "the truth" do
# assert true
# end
diff --git a/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb
index bf3da1fc4d..f315144723 100644
--- a/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb
+++ b/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb
@@ -14,10 +14,10 @@ require "rails/test_help"
# to be shown.
Minitest.backtrace_filter = Minitest::BacktraceFilter.new
-# Load support files
-Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
-
# Load fixtures from the engine
if ActiveSupport::TestCase.respond_to?(:fixture_path=)
ActiveSupport::TestCase.fixture_path = File.expand_path("../fixtures", __FILE__)
+ ActionDispatch::IntegrationTest.fixture_path = ActiveSupport::TestCase.fixture_path
+ ActiveSupport::TestCase.file_fixture_path = ActiveSupport::TestCase.fixture_path + "/files"
+ ActiveSupport::TestCase.fixtures :all
end
diff --git a/railties/lib/rails/generators/rails/resource/resource_generator.rb b/railties/lib/rails/generators/rails/resource/resource_generator.rb
index 8014feb75f..3acf21df13 100644
--- a/railties/lib/rails/generators/rails/resource/resource_generator.rb
+++ b/railties/lib/rails/generators/rails/resource/resource_generator.rb
@@ -1,6 +1,5 @@
require 'rails/generators/resource_helpers'
require 'rails/generators/rails/model/model_generator'
-require 'active_support/core_ext/object/blank'
module Rails
module Generators
diff --git a/railties/lib/rails/generators/rails/resource_route/resource_route_generator.rb b/railties/lib/rails/generators/rails/resource_route/resource_route_generator.rb
index e4a2bc2b0f..42705107ae 100644
--- a/railties/lib/rails/generators/rails/resource_route/resource_route_generator.rb
+++ b/railties/lib/rails/generators/rails/resource_route/resource_route_generator.rb
@@ -1,7 +1,6 @@
module Rails
module Generators
class ResourceRouteGenerator < NamedBase # :nodoc:
-
# Properly nests namespaces passed into a generator
#
# $ rails generate resource admin/users/products
@@ -29,8 +28,10 @@ module Rails
write("end", route_length - index)
end
- # route prepends two spaces onto the front of the string that is passed, this corrects that
- route route_string[2..-1]
+ # route prepends two spaces onto the front of the string that is passed, this corrects that.
+ # Also it adds a \n to the end of each line, as route already adds that
+ # we need to correct that too.
+ route route_string[2..-2]
end
private
diff --git a/railties/lib/rails/generators/rails/scaffold/USAGE b/railties/lib/rails/generators/rails/scaffold/USAGE
index 1b2a944103..d2e495758d 100644
--- a/railties/lib/rails/generators/rails/scaffold/USAGE
+++ b/railties/lib/rails/generators/rails/scaffold/USAGE
@@ -36,6 +36,6 @@ Description:
Examples:
`rails generate scaffold post`
- `rails generate scaffold post title body:text published:boolean`
+ `rails generate scaffold post title:string body:text published:boolean`
`rails generate scaffold purchase amount:decimal tracking_id:integer:uniq`
`rails generate scaffold user email:uniq password:digest`
diff --git a/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb
index e89789e72b..17c32bfdb3 100644
--- a/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb
+++ b/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb
@@ -10,10 +10,11 @@ module Rails
class_option :stylesheet_engine, desc: "Engine for Stylesheets"
class_option :assets, type: :boolean
class_option :resource_route, type: :boolean
+ class_option :scaffold_stylesheet, type: :boolean
def handle_skip
@options = @options.merge(stylesheets: false) unless options[:assets]
- @options = @options.merge(stylesheet_engine: false) unless options[:stylesheets]
+ @options = @options.merge(stylesheet_engine: false) unless options[:stylesheets] && options[:scaffold_stylesheet]
end
hook_for :scaffold_controller, required: true
diff --git a/railties/lib/rails/generators/rails/scaffold/templates/scaffold.css b/railties/lib/rails/generators/rails/scaffold/templates/scaffold.css
index 1ae7000299..b7818883d1 100644
--- a/railties/lib/rails/generators/rails/scaffold/templates/scaffold.css
+++ b/railties/lib/rails/generators/rails/scaffold/templates/scaffold.css
@@ -1,9 +1,13 @@
-body { background-color: #fff; color: #333; }
+body {
+ background-color: #fff;
+ color: #333;
+}
body, p, ol, ul, td {
font-family: verdana, arial, helvetica, sans-serif;
- font-size: 13px;
+ font-size: 13px;
line-height: 18px;
+ margin: 33px;
}
pre {
@@ -12,11 +16,31 @@ pre {
font-size: 11px;
}
-a { color: #000; }
-a:visited { color: #666; }
-a:hover { color: #fff; background-color:#000; }
+a {
+ color: #000;
+}
+
+a:visited {
+ color: #666;
+}
+
+a:hover {
+ color: #fff;
+ background-color: #000;
+}
+
+th {
+ padding-bottom: 5px;
+}
+
+td {
+ padding-bottom: 7px;
+ padding-left: 5px;
+ padding-right: 5px;
+}
-div.field, div.actions {
+div.field,
+div.actions {
margin-bottom: 10px;
}
@@ -45,7 +69,7 @@ div.field, div.actions {
padding: 5px 5px 5px 15px;
font-size: 12px;
margin: -7px;
- margin-bottom: 0px;
+ margin-bottom: 0;
background-color: #c00;
color: #fff;
}
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 c01b82884d..d0b8cad896 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
@@ -10,11 +10,14 @@ module Rails
class_option :helper, type: :boolean
class_option :orm, banner: "NAME", type: :string, required: true,
desc: "ORM to generate the controller for"
+ class_option :api, type: :boolean,
+ desc: "Generates API controller"
argument :attributes, type: :array, default: [], banner: "field:type field:type"
def create_controller_files
- template "controller.rb", File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb")
+ template_file = options.api? ? "api_controller.rb" : "controller.rb"
+ template template_file, File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb")
end
hook_for :template_engine, :test_framework, as: :scaffold
diff --git a/railties/lib/rails/generators/rails/scaffold_controller/templates/api_controller.rb b/railties/lib/rails/generators/rails/scaffold_controller/templates/api_controller.rb
new file mode 100644
index 0000000000..bc3c9b3f6b
--- /dev/null
+++ b/railties/lib/rails/generators/rails/scaffold_controller/templates/api_controller.rb
@@ -0,0 +1,61 @@
+<% if namespaced? -%>
+require_dependency "<%= namespaced_file_path %>/application_controller"
+
+<% end -%>
+<% module_namespacing do -%>
+class <%= controller_class_name %>Controller < ApplicationController
+ before_action :set_<%= singular_table_name %>, only: [:show, :update, :destroy]
+
+ # GET <%= route_url %>
+ def index
+ @<%= plural_table_name %> = <%= orm_class.all(class_name) %>
+
+ render json: <%= "@#{plural_table_name}" %>
+ end
+
+ # GET <%= route_url %>/1
+ def show
+ render json: <%= "@#{singular_table_name}" %>
+ end
+
+ # POST <%= route_url %>
+ def create
+ @<%= singular_table_name %> = <%= orm_class.build(class_name, "#{singular_table_name}_params") %>
+
+ if @<%= orm_instance.save %>
+ render json: <%= "@#{singular_table_name}" %>, status: :created, location: <%= "@#{singular_table_name}" %>
+ else
+ render json: <%= "@#{orm_instance.errors}" %>, status: :unprocessable_entity
+ end
+ end
+
+ # PATCH/PUT <%= route_url %>/1
+ def update
+ if @<%= orm_instance.update("#{singular_table_name}_params") %>
+ render json: <%= "@#{singular_table_name}" %>
+ else
+ render json: <%= "@#{orm_instance.errors}" %>, status: :unprocessable_entity
+ end
+ end
+
+ # DELETE <%= route_url %>/1
+ def destroy
+ @<%= orm_instance.destroy %>
+ end
+
+ private
+ # Use callbacks to share common setup or constraints between actions.
+ def set_<%= singular_table_name %>
+ @<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %>
+ end
+
+ # Only allow a trusted parameter "white list" through.
+ def <%= "#{singular_table_name}_params" %>
+ <%- if attributes_names.empty? -%>
+ params[:<%= singular_table_name %>]
+ <%- else -%>
+ params.require(:<%= singular_table_name %>).permit(<%= attributes_names.map { |name| ":#{name}" }.join(', ') %>)
+ <%- end -%>
+ end
+end
+<% end -%>
diff --git a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb
index 2c3b04043f..f73e9a96ba 100644
--- a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb
+++ b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb
@@ -1,5 +1,5 @@
<% if namespaced? -%>
-require_dependency "<%= namespaced_file_path %>/application_controller"
+require_dependency "<%= namespaced_path %>/application_controller"
<% end -%>
<% module_namespacing do -%>
diff --git a/railties/lib/rails/generators/resource_helpers.rb b/railties/lib/rails/generators/resource_helpers.rb
index 3f84d76ae0..9c2037783e 100644
--- a/railties/lib/rails/generators/resource_helpers.rb
+++ b/railties/lib/rails/generators/resource_helpers.rb
@@ -8,7 +8,7 @@ module Rails
module ResourceHelpers # :nodoc:
def self.included(base) #:nodoc:
- base.send :include, Rails::Generators::ModelHelpers
+ base.include(Rails::Generators::ModelHelpers)
base.class_option :model_name, type: :string, desc: "ModelName to be used"
end
diff --git a/railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb b/railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb
index 509bd60564..5a8a3ca5e0 100644
--- a/railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb
+++ b/railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb
@@ -2,6 +2,12 @@ require 'test_helper'
<% module_namespacing do -%>
class <%= class_name %>ControllerTest < ActionController::TestCase
+<% if mountable_engine? -%>
+ setup do
+ @routes = Engine.routes
+ end
+
+<% end -%>
<% if actions.empty? -%>
# test "the truth" do
# assert true
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 ba131da79d..343c8a3949 100644
--- a/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb
+++ b/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb
@@ -16,6 +16,11 @@ module TestUnit # :nodoc:
def create_preview_files
template "preview.rb", File.join('test/mailers/previews', class_path, "#{file_name}_mailer_preview.rb")
end
+
+ protected
+ def file_name
+ @_file_name ||= super.gsub(/\_mailer/i, '')
+ end
end
end
end
diff --git a/railties/lib/rails/generators/test_unit/mailer/templates/functional_test.rb b/railties/lib/rails/generators/test_unit/mailer/templates/functional_test.rb
index 3cee517db3..a2f2d30de5 100644
--- a/railties/lib/rails/generators/test_unit/mailer/templates/functional_test.rb
+++ b/railties/lib/rails/generators/test_unit/mailer/templates/functional_test.rb
@@ -4,7 +4,7 @@ require 'test_helper'
class <%= class_name %>MailerTest < ActionMailer::TestCase
<% actions.each do |action| -%>
test "<%= action %>" do
- mail = <%= class_name %>.<%= action %>
+ mail = <%= class_name %>Mailer.<%= action %>
assert_equal <%= action.to_s.humanize.inspect %>, mail.subject
assert_equal ["to@example.org"], mail.to
assert_equal ["from@example.com"], mail.from
diff --git a/railties/lib/rails/generators/test_unit/mailer/templates/preview.rb b/railties/lib/rails/generators/test_unit/mailer/templates/preview.rb
index 6b85764a66..b063cbc47b 100644
--- a/railties/lib/rails/generators/test_unit/mailer/templates/preview.rb
+++ b/railties/lib/rails/generators/test_unit/mailer/templates/preview.rb
@@ -1,9 +1,9 @@
<% module_namespacing do -%>
-# Preview all emails at http://localhost:3000/rails/mailers/<%= file_path %>
+# Preview all emails at http://localhost:3000/rails/mailers/<%= file_path %>_mailer
class <%= class_name %>MailerPreview < ActionMailer::Preview
<% actions.each do |action| -%>
- # Preview this email at http://localhost:3000/rails/mailers/<%= file_path %>/<%= action %>
+ # Preview this email at http://localhost:3000/rails/mailers/<%= file_path %>_mailer/<%= action %>
def <%= action %>
<%= class_name %>Mailer.<%= action %>
end
diff --git a/railties/lib/rails/generators/test_unit/model/model_generator.rb b/railties/lib/rails/generators/test_unit/model/model_generator.rb
index 2826a3ffa1..086588750e 100644
--- a/railties/lib/rails/generators/test_unit/model/model_generator.rb
+++ b/railties/lib/rails/generators/test_unit/model/model_generator.rb
@@ -19,7 +19,7 @@ module TestUnit # :nodoc:
def create_fixture_file
if options[:fixture] && options[:fixture_replacement].nil?
- template 'fixtures.yml', File.join('test/fixtures', class_path, "#{plural_file_name}.yml")
+ template 'fixtures.yml', File.join('test/fixtures', class_path, "#{fixture_file_name}.yml")
end
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 2e1f55f2a6..0171da7cc7 100644
--- a/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb
+++ b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb
@@ -8,13 +8,26 @@ module TestUnit # :nodoc:
check_class_collision suffix: "ControllerTest"
+ class_option :api, type: :boolean,
+ desc: "Generates API functional tests"
+
argument :attributes, type: :array, default: [], banner: "field:type field:type"
def create_test_files
- template "functional_test.rb",
+ template_file = options.api? ? "api_functional_test.rb" : "functional_test.rb"
+ template template_file,
File.join("test/controllers", controller_class_path, "#{controller_file_name}_controller_test.rb")
end
+ def fixture_name
+ @fixture_name ||=
+ if mountable_engine?
+ "%s_%s" % [namespaced_path, table_name]
+ else
+ table_name
+ end
+ end
+
private
def attributes_hash
diff --git a/railties/lib/rails/generators/test_unit/scaffold/templates/api_functional_test.rb b/railties/lib/rails/generators/test_unit/scaffold/templates/api_functional_test.rb
new file mode 100644
index 0000000000..f302cd6c3d
--- /dev/null
+++ b/railties/lib/rails/generators/test_unit/scaffold/templates/api_functional_test.rb
@@ -0,0 +1,43 @@
+require 'test_helper'
+
+<% module_namespacing do -%>
+class <%= controller_class_name %>ControllerTest < ActionController::TestCase
+ setup do
+ @<%= singular_table_name %> = <%= fixture_name %>(:one)
+<% if mountable_engine? -%>
+ @routes = Engine.routes
+<% end -%>
+ end
+
+ test "should get index" do
+ get :index
+ assert_response :success
+ end
+
+ test "should create <%= singular_table_name %>" do
+ assert_difference('<%= class_name %>.count') do
+ post :create, params: { <%= "#{singular_table_name}: { #{attributes_hash} }" %> }
+ end
+
+ assert_response 201
+ end
+
+ test "should show <%= singular_table_name %>" do
+ get :show, params: { id: <%= "@#{singular_table_name}" %> }
+ assert_response :success
+ end
+
+ test "should update <%= singular_table_name %>" do
+ patch :update, params: { id: <%= "@#{singular_table_name}" %>, <%= "#{singular_table_name}: { #{attributes_hash} }" %> }
+ assert_response 200
+ end
+
+ test "should destroy <%= singular_table_name %>" do
+ assert_difference('<%= class_name %>.count', -1) do
+ delete :destroy, params: { id: <%= "@#{singular_table_name}" %> }
+ end
+
+ assert_response 204
+ end
+end
+<% end -%>
diff --git a/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb
index 18bd1ece9d..50b98b2631 100644
--- a/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb
+++ b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb
@@ -3,13 +3,15 @@ require 'test_helper'
<% module_namespacing do -%>
class <%= controller_class_name %>ControllerTest < ActionController::TestCase
setup do
- @<%= singular_table_name %> = <%= table_name %>(:one)
+ @<%= singular_table_name %> = <%= fixture_name %>(:one)
+<% if mountable_engine? -%>
+ @routes = Engine.routes
+<% end -%>
end
test "should get index" do
get :index
assert_response :success
- assert_not_nil assigns(:<%= table_name %>)
end
test "should get new" do
@@ -19,30 +21,30 @@ class <%= controller_class_name %>ControllerTest < ActionController::TestCase
test "should create <%= singular_table_name %>" do
assert_difference('<%= class_name %>.count') do
- post :create, <%= "#{singular_table_name}: { #{attributes_hash} }" %>
+ post :create, params: { <%= "#{singular_table_name}: { #{attributes_hash} }" %> }
end
- assert_redirected_to <%= singular_table_name %>_path(assigns(:<%= singular_table_name %>))
+ assert_redirected_to <%= singular_table_name %>_path(<%= class_name %>.last)
end
test "should show <%= singular_table_name %>" do
- get :show, id: <%= "@#{singular_table_name}" %>
+ get :show, params: { id: <%= "@#{singular_table_name}" %> }
assert_response :success
end
test "should get edit" do
- get :edit, id: <%= "@#{singular_table_name}" %>
+ get :edit, params: { id: <%= "@#{singular_table_name}" %> }
assert_response :success
end
test "should update <%= singular_table_name %>" do
- patch :update, id: <%= "@#{singular_table_name}" %>, <%= "#{singular_table_name}: { #{attributes_hash} }" %>
- assert_redirected_to <%= singular_table_name %>_path(assigns(:<%= singular_table_name %>))
+ patch :update, params: { id: <%= "@#{singular_table_name}" %>, <%= "#{singular_table_name}: { #{attributes_hash} }" %> }
+ assert_redirected_to <%= singular_table_name %>_path(<%= "@#{singular_table_name}" %>)
end
test "should destroy <%= singular_table_name %>" do
assert_difference('<%= class_name %>.count', -1) do
- delete :destroy, id: <%= "@#{singular_table_name}" %>
+ delete :destroy, params: { id: <%= "@#{singular_table_name}" %> }
end
assert_redirected_to <%= index_helper %>_path
diff --git a/railties/lib/rails/generators/testing/assertions.rb b/railties/lib/rails/generators/testing/assertions.rb
index bd069e4bd0..76758df86d 100644
--- a/railties/lib/rails/generators/testing/assertions.rb
+++ b/railties/lib/rails/generators/testing/assertions.rb
@@ -1,5 +1,3 @@
-require 'shellwords'
-
module Rails
module Generators
module Testing
@@ -23,7 +21,7 @@ module Rails
# end
# end
def assert_file(relative, *contents)
- absolute = File.expand_path(relative, destination_root).shellescape
+ absolute = File.expand_path(relative, destination_root)
assert File.exist?(absolute), "Expected file #{relative.inspect} to exist, but does not"
read = File.read(absolute) if block_given? || !contents.empty?
diff --git a/railties/lib/rails/generators/testing/behaviour.rb b/railties/lib/rails/generators/testing/behaviour.rb
index fd2ea274e1..94b5e52224 100644
--- a/railties/lib/rails/generators/testing/behaviour.rb
+++ b/railties/lib/rails/generators/testing/behaviour.rb
@@ -2,6 +2,7 @@ require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/module/delegation'
require 'active_support/core_ext/hash/reverse_merge'
require 'active_support/core_ext/kernel/reporting'
+require 'active_support/testing/stream'
require 'active_support/concern'
require 'rails/generators'
@@ -10,6 +11,7 @@ module Rails
module Testing
module Behaviour
extend ActiveSupport::Concern
+ include ActiveSupport::Testing::Stream
included do
class_attribute :destination_root, :current_path, :generator_class, :default_arguments
@@ -90,7 +92,8 @@ module Rails
cd current_path
end
- def prepare_destination # :nodoc:
+ # Clears all files and directories in destination.
+ def prepare_destination
rm_rf(destination_root)
mkdir_p(destination_root)
end
@@ -101,22 +104,6 @@ module Rails
Dir.glob("#{dirname}/[0-9]*_*.rb").grep(/\d+_#{file_name}.rb$/).first
end
- def capture(stream)
- stream = stream.to_s
- captured_stream = Tempfile.new(stream)
- stream_io = eval("$#{stream}")
- origin_stream = stream_io.dup
- stream_io.reopen(captured_stream)
-
- yield
-
- stream_io.rewind
- return captured_stream.read
- ensure
- captured_stream.close
- captured_stream.unlink
- stream_io.reopen(origin_stream)
- end
end
end
end
diff --git a/railties/lib/rails/info_controller.rb b/railties/lib/rails/info_controller.rb
index 49e5431a16..778105c5f7 100644
--- a/railties/lib/rails/info_controller.rb
+++ b/railties/lib/rails/info_controller.rb
@@ -17,7 +17,28 @@ class Rails::InfoController < Rails::ApplicationController # :nodoc:
end
def routes
- @routes_inspector = ActionDispatch::Routing::RoutesInspector.new(_routes.routes)
- @page_title = 'Routes'
+ if path = params[:path]
+ path = URI.parser.escape path
+ normalized_path = with_leading_slash path
+ render json: {
+ exact: match_route {|it| it.match normalized_path },
+ fuzzy: match_route {|it| it.spec.to_s.match path }
+ }
+ else
+ @routes_inspector = ActionDispatch::Routing::RoutesInspector.new(_routes.routes)
+ @page_title = 'Routes'
+ end
+ end
+
+ private
+
+ def match_route
+ _routes.routes.select {|route|
+ yield route.path
+ }.map {|route| route.path.spec.to_s }
+ end
+
+ def with_leading_slash(path)
+ ('/' + path).squeeze('/')
end
end
diff --git a/railties/lib/rails/mailers_controller.rb b/railties/lib/rails/mailers_controller.rb
index 32740d66da..6143cf2dd9 100644
--- a/railties/lib/rails/mailers_controller.rb
+++ b/railties/lib/rails/mailers_controller.rb
@@ -3,7 +3,7 @@ require 'rails/application_controller'
class Rails::MailersController < Rails::ApplicationController # :nodoc:
prepend_view_path ActionDispatch::DebugExceptions::RESCUES_TEMPLATE_PATH
- before_action :require_local!
+ before_action :require_local!, unless: :show_previews?
before_action :find_preview, only: :preview
def index
@@ -16,31 +16,35 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc:
@page_title = "Mailer Previews for #{@preview.preview_name}"
render action: 'mailer'
else
- email = File.basename(params[:path])
+ @email_action = File.basename(params[:path])
- if @preview.email_exists?(email)
- @email = @preview.call(email)
+ if @preview.email_exists?(@email_action)
+ @email = @preview.call(@email_action)
if params[:part]
part_type = Mime::Type.lookup(params[:part])
if part = find_part(part_type)
response.content_type = part_type
- render text: part.respond_to?(:decoded) ? part.decoded : part
+ render plain: part.respond_to?(:decoded) ? part.decoded : part
else
- raise AbstractController::ActionNotFound, "Email part '#{part_type}' not found in #{@preview.name}##{email}"
+ raise AbstractController::ActionNotFound, "Email part '#{part_type}' not found in #{@preview.name}##{@email_action}"
end
else
- @part = find_preferred_part(request.format, Mime::HTML, Mime::TEXT)
+ @part = find_preferred_part(request.format, Mime[:html], Mime[:text])
render action: 'email', layout: false, formats: %w[html]
end
else
- raise AbstractController::ActionNotFound, "Email '#{email}' not found in #{@preview.name}"
+ raise AbstractController::ActionNotFound, "Email '#{@email_action}' not found in #{@preview.name}"
end
end
end
protected
+ def show_previews?
+ ActionMailer::Base.show_previews
+ end
+
def find_preview
candidates = []
params[:path].to_s.scan(%r{/|$}){ candidates << $` }
@@ -54,18 +58,20 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc:
end
def find_preferred_part(*formats)
- if @email.multipart?
- formats.each do |format|
- return find_part(format) if @email.parts.any?{ |p| p.mime_type == format }
+ formats.each do |format|
+ if part = @email.find_first_mime_type(format)
+ return part
end
- else
+ end
+
+ if formats.any?{ |f| @email.mime_type == f }
@email
end
end
def find_part(format)
- if @email.multipart?
- @email.parts.find{ |p| p.mime_type == format }
+ if part = @email.find_first_mime_type(format)
+ part
elsif @email.mime_type == format
@email
end
diff --git a/railties/lib/rails/paths.rb b/railties/lib/rails/paths.rb
index 5458036219..e47616a87f 100644
--- a/railties/lib/rails/paths.rb
+++ b/railties/lib/rails/paths.rb
@@ -7,7 +7,7 @@ module Rails
# root = Root.new "/rails"
# root.add "app/controllers", eager_load: true
#
- # The command above creates a new root object and add "app/controllers" as a path.
+ # The command above 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"]
@@ -123,6 +123,10 @@ module Rails
options[:load_path] ? load_path! : skip_load_path!
end
+ def absolute_current # :nodoc:
+ File.expand_path(@current, @root.path)
+ end
+
def children
keys = @root.keys.find_all { |k|
k.start_with?(@current) && k != @current
@@ -175,6 +179,10 @@ module Rails
@paths
end
+ def extensions # :nodoc:
+ $1.split(',') if @glob =~ /\{([\S]+)\}/
+ end
+
# Expands all paths against the root and return all unique values.
def expanded
raise "You need to set a path root" unless @root.path
diff --git a/railties/lib/rails/rack/logger.rb b/railties/lib/rails/rack/logger.rb
index 9962e6d943..12676b18bc 100644
--- a/railties/lib/rails/rack/logger.rb
+++ b/railties/lib/rails/rack/logger.rb
@@ -7,6 +7,10 @@ require 'rack/body_proxy'
module Rails
module Rack
# Sets log tags, logs the request, calls the app, and flushes the logs.
+ #
+ # Log tags (+taggers+) can be an Array containing: methods that the +request+
+ # object responds to, objects that respond to +to_s+ or Proc objects that accept
+ # an instance of the +request+ object.
class Logger < ActiveSupport::LogSubscriber
def initialize(app, taggers = nil)
@app = app
diff --git a/railties/lib/rails/ruby_version_check.rb b/railties/lib/rails/ruby_version_check.rb
index aea3d2339c..67a19d8a94 100644
--- a/railties/lib/rails/ruby_version_check.rb
+++ b/railties/lib/rails/ruby_version_check.rb
@@ -1,13 +1,13 @@
-if RUBY_VERSION < '2.2.0'
+if RUBY_VERSION < '2.2.2' && RUBY_ENGINE == 'ruby'
desc = defined?(RUBY_DESCRIPTION) ? RUBY_DESCRIPTION : "ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE})"
abort <<-end_message
- Rails 5 requires to run on Ruby 2.2.0 or newer.
+ Rails 5 requires Ruby 2.2.2 or newer.
You're running
#{desc}
- Please upgrade to Ruby 2.2.0 or newer to continue.
+ Please upgrade to Ruby 2.2.2 or newer to continue.
end_message
end
diff --git a/railties/lib/rails/source_annotation_extractor.rb b/railties/lib/rails/source_annotation_extractor.rb
index 9b058a1848..8dd87b6cc5 100644
--- a/railties/lib/rails/source_annotation_extractor.rb
+++ b/railties/lib/rails/source_annotation_extractor.rb
@@ -3,7 +3,7 @@
# rake notes
# rake notes:optimize
#
-# and friends. See <tt>rake -T notes</tt> and <tt>railties/lib/tasks/annotations.rake</tt>.
+# and friends. See <tt>rake -T notes</tt> and <tt>railties/lib/rails/tasks/annotations.rake</tt>.
#
# Annotation objects are triplets <tt>:line</tt>, <tt>:tag</tt>, <tt>:text</tt> that
# represent the line where the annotation lives, its tag, and its text. Note
diff --git a/railties/lib/rails/tasks.rb b/railties/lib/rails/tasks.rb
index 2f82d1285d..d3e33584d7 100644
--- a/railties/lib/rails/tasks.rb
+++ b/railties/lib/rails/tasks.rb
@@ -3,14 +3,17 @@ require 'rake'
# Load Rails Rakefile extensions
%w(
annotations
- documentation
+ dev
framework
+ initializers
log
middleware
misc
+ restart
routes
- statistics
tmp
-).each do |task|
+).tap { |arr|
+ arr << 'statistics' if Rake.application.current_scope.empty?
+}.each do |task|
load "rails/tasks/#{task}.rake"
end
diff --git a/railties/lib/rails/tasks/dev.rake b/railties/lib/rails/tasks/dev.rake
new file mode 100644
index 0000000000..e949172d3f
--- /dev/null
+++ b/railties/lib/rails/tasks/dev.rake
@@ -0,0 +1,15 @@
+namespace :dev do
+ task :cache do
+ desc 'Toggle development mode caching on/off'
+
+ if File.exist? 'tmp/caching-dev.txt'
+ File.delete 'tmp/caching-dev.txt'
+ puts 'Development mode is no longer being cached.'
+ else
+ FileUtils.touch 'tmp/caching-dev.txt'
+ puts 'Development mode is now being cached.'
+ end
+
+ FileUtils.touch 'tmp/restart.txt'
+ end
+end
diff --git a/railties/lib/rails/tasks/documentation.rake b/railties/lib/rails/tasks/documentation.rake
deleted file mode 100644
index 8544890553..0000000000
--- a/railties/lib/rails/tasks/documentation.rake
+++ /dev/null
@@ -1,70 +0,0 @@
-begin
- require 'rdoc/task'
-rescue LoadError
- # Rubinius installs RDoc as a gem, and for this interpreter "rdoc/task" is
- # available only if the application bundle includes "rdoc" (normally as a
- # dependency of the "sdoc" gem.)
- #
- # If RDoc is not available it is fine that we do not generate the tasks that
- # depend on it. Just be robust to this gotcha and go on.
-else
- require 'rails/api/task'
-
- # Monkey-patch to remove redoc'ing and clobber descriptions to cut down on rake -T noise
- class RDocTaskWithoutDescriptions < RDoc::Task
- include ::Rake::DSL
-
- def define
- task rdoc_task_name
-
- task rerdoc_task_name => [clobber_task_name, rdoc_task_name]
-
- task clobber_task_name do
- rm_r rdoc_dir rescue nil
- end
-
- task :clobber => [clobber_task_name]
-
- directory @rdoc_dir
- task rdoc_task_name => [rdoc_target]
- file rdoc_target => @rdoc_files + [Rake.application.rakefile] do
- rm_r @rdoc_dir rescue nil
- @before_running_rdoc.call if @before_running_rdoc
- args = option_list + @rdoc_files
- if @external
- argstring = args.join(' ')
- sh %{ruby -Ivendor vendor/rd #{argstring}}
- else
- require 'rdoc/rdoc'
- RDoc::RDoc.new.document(args)
- end
- end
- self
- end
- end
-
- namespace :doc do
- RDocTaskWithoutDescriptions.new("app") { |rdoc|
- rdoc.rdoc_dir = 'doc/app'
- rdoc.template = ENV['template'] if ENV['template']
- rdoc.title = ENV['title'] || "Rails Application Documentation"
- rdoc.options << '--line-numbers'
- rdoc.options << '--charset' << 'utf-8'
- rdoc.rdoc_files.include('README.rdoc')
- rdoc.rdoc_files.include('app/**/*.rb')
- rdoc.rdoc_files.include('lib/**/*.rb')
- }
- Rake::Task['doc:app'].comment = "Generate docs for the app -- also available doc:rails, doc:guides (options: TEMPLATE=/rdoc-template.rb, TITLE=\"Custom Title\")"
-
- # desc 'Generate documentation for the Rails framework.'
- Rails::API::AppTask.new('rails')
- end
-end
-
-namespace :doc do
- task :guides do
- rails_gem_dir = Gem::Specification.find_by_name("rails").gem_dir
- require File.expand_path(File.join(rails_gem_dir, "/guides/rails_guides"))
- RailsGuides::Generator.new(Rails.root.join("doc/guides")).generate
- end
-end
diff --git a/railties/lib/rails/tasks/engine.rake b/railties/lib/rails/tasks/engine.rake
index 16ad1bfc84..c51524f8f6 100644
--- a/railties/lib/rails/tasks/engine.rake
+++ b/railties/lib/rails/tasks/engine.rake
@@ -40,7 +40,7 @@ namespace :db do
desc "Rolls the schema back to the previous version (specify steps w/ STEP=n)."
app_task "rollback"
- desc "Create a db/schema.rb file that can be portably used against any DB supported by AR"
+ desc "Create a db/schema.rb file that can be portably used against any DB supported by Active Record"
app_task "schema:dump"
desc "Load a schema.rb file into the database"
diff --git a/railties/lib/rails/tasks/framework.rake b/railties/lib/rails/tasks/framework.rake
index a1c805f8aa..904b9d9ad6 100644
--- a/railties/lib/rails/tasks/framework.rake
+++ b/railties/lib/rails/tasks/framework.rake
@@ -32,35 +32,37 @@ namespace :rails do
FileUtils.cp_r src_name, dst_name
end
end
- end
+ end
end
namespace :update do
- def invoke_from_app_generator(method)
- app_generator.send(method)
- end
+ class RailsUpdate
+ def self.invoke_from_app_generator(method)
+ app_generator.send(method)
+ end
- def app_generator
- @app_generator ||= begin
- require 'rails/generators'
- require 'rails/generators/rails/app/app_generator'
- gen = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true },
- destination_root: Rails.root
- File.exist?(Rails.root.join("config", "application.rb")) ?
- gen.send(:app_const) : gen.send(:valid_const?)
- gen
+ def self.app_generator
+ @app_generator ||= begin
+ require 'rails/generators'
+ require 'rails/generators/rails/app/app_generator'
+ gen = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true },
+ destination_root: Rails.root
+ File.exist?(Rails.root.join("config", "application.rb")) ?
+ gen.send(:app_const) : gen.send(:valid_const?)
+ gen
+ end
end
end
# desc "Update config/boot.rb from your current rails install"
task :configs do
- invoke_from_app_generator :create_boot_file
- invoke_from_app_generator :update_config_files
+ RailsUpdate.invoke_from_app_generator :create_boot_file
+ RailsUpdate.invoke_from_app_generator :update_config_files
end
# desc "Adds new executables to the application bin/ directory"
task :bin do
- invoke_from_app_generator :create_bin_files
+ RailsUpdate.invoke_from_app_generator :create_bin_files
end
end
end
diff --git a/railties/lib/rails/tasks/initializers.rake b/railties/lib/rails/tasks/initializers.rake
new file mode 100644
index 0000000000..2968b5cb53
--- /dev/null
+++ b/railties/lib/rails/tasks/initializers.rake
@@ -0,0 +1,6 @@
+desc "Print out all defined initializers in the order they are invoked by Rails."
+task initializers: :environment do
+ Rails.application.initializers.tsort_each do |initializer|
+ puts initializer.name
+ end
+end
diff --git a/railties/lib/rails/tasks/restart.rake b/railties/lib/rails/tasks/restart.rake
new file mode 100644
index 0000000000..f36c86d81b
--- /dev/null
+++ b/railties/lib/rails/tasks/restart.rake
@@ -0,0 +1,5 @@
+desc "Restart app by touching tmp/restart.txt"
+task :restart do
+ FileUtils.mkdir_p('tmp')
+ FileUtils.touch('tmp/restart.txt')
+end
diff --git a/railties/lib/rails/tasks/tmp.rake b/railties/lib/rails/tasks/tmp.rake
index b33ae9862b..9162ef234a 100644
--- a/railties/lib/rails/tasks/tmp.rake
+++ b/railties/lib/rails/tasks/tmp.rake
@@ -11,7 +11,7 @@ namespace :tmp do
tmp_dirs.each { |d| directory d }
- desc "Creates tmp directories for sessions, cache, sockets, and pids"
+ desc "Creates tmp directories for cache, sockets, and pids"
task create: tmp_dirs
namespace :cache do
diff --git a/railties/lib/rails/templates/rails/mailers/email.html.erb b/railties/lib/rails/templates/rails/mailers/email.html.erb
index 0b08a01896..fed96fbc85 100644
--- a/railties/lib/rails/templates/rails/mailers/email.html.erb
+++ b/railties/lib/rails/templates/rails/mailers/email.html.erb
@@ -39,6 +39,10 @@
padding: 1px;
}
+ dd:empty:before {
+ content: "\00a0"; // &nbsp;
+ }
+
iframe {
border: 0;
width: 100%;
@@ -84,22 +88,43 @@
<% unless @email.attachments.nil? || @email.attachments.empty? %>
<dt>Attachments:</dt>
<dd>
- <%= @email.attachments.map { |a| a.respond_to?(:original_filename) ? a.original_filename : a.filename }.inspect %>
+ <%= @email.attachments.map { |a| a.respond_to?(:original_filename) ? a.original_filename : a.filename }.join(', ') %>
</dd>
<% end %>
<% if @email.multipart? %>
<dd>
- <select onchange="document.getElementsByName('messageBody')[0].src=this.options[this.selectedIndex].value;">
- <option <%= request.format == Mime::HTML ? 'selected' : '' %> value="?part=text%2Fhtml">View as HTML email</option>
- <option <%= request.format == Mime::TEXT ? 'selected' : '' %> value="?part=text%2Fplain">View as plain-text email</option>
+ <select onchange="formatChanged(this);">
+ <option <%= request.format == Mime[:html] ? 'selected' : '' %> value="?part=text%2Fhtml">View as HTML email</option>
+ <option <%= request.format == Mime[:text] ? 'selected' : '' %> value="?part=text%2Fplain">View as plain-text email</option>
</select>
</dd>
<% end %>
</dl>
</header>
-<iframe seamless name="messageBody" src="?part=<%= Rack::Utils.escape(@part.mime_type) %>"></iframe>
+<% if @part && @part.mime_type %>
+ <iframe seamless name="messageBody" src="?part=<%= Rack::Utils.escape(@part.mime_type) %>"></iframe>
+<% else %>
+ <p>
+ You are trying to preview an email that does not have any content.
+ This is probably because the <em>mail</em> method has not been called in <em><%= @preview.preview_name %>#<%= @email_action %></em>.
+ </p>
+<% end %>
+
+<script>
+ function formatChanged(form) {
+ var part_name = form.options[form.selectedIndex].value
+ var iframe =document.getElementsByName('messageBody')[0];
+ iframe.contentWindow.location.replace(part_name);
+
+ if (history.replaceState) {
+ var url = location.pathname.replace(/\.(txt|html)$/, '');
+ var format = /html/.test(part_name) ? '.html' : '.txt';
+ window.history.replaceState({}, '', url + format);
+ }
+ }
+</script>
</body>
</html>
diff --git a/railties/lib/rails/templates/rails/mailers/index.html.erb b/railties/lib/rails/templates/rails/mailers/index.html.erb
index c4c9757d57..000930c039 100644
--- a/railties/lib/rails/templates/rails/mailers/index.html.erb
+++ b/railties/lib/rails/templates/rails/mailers/index.html.erb
@@ -1,8 +1,8 @@
<% @previews.each do |preview| %>
-<h3><%= link_to preview.preview_name.titleize, "/rails/mailers/#{preview.preview_name}" %></h3>
+<h3><%= link_to preview.preview_name.titleize, url_for(controller: "rails/mailers", action: "preview", path: preview.preview_name) %></h3>
<ul>
<% preview.emails.each do |email| %>
-<li><%= link_to email, "/rails/mailers/#{preview.preview_name}/#{email}" %></li>
+<li><%= link_to email, url_for(controller: "rails/mailers", action: "preview", path: "#{preview.preview_name}/#{email}") %></li>
<% end %>
</ul>
<% end %>
diff --git a/railties/lib/rails/templates/rails/mailers/mailer.html.erb b/railties/lib/rails/templates/rails/mailers/mailer.html.erb
index 607c8d1677..c12ead0f90 100644
--- a/railties/lib/rails/templates/rails/mailers/mailer.html.erb
+++ b/railties/lib/rails/templates/rails/mailers/mailer.html.erb
@@ -1,6 +1,6 @@
<h3><%= @preview.preview_name.titleize %></h3>
<ul>
<% @preview.emails.each do |email| %>
-<li><%= link_to email, "/rails/mailers/#{@preview.preview_name}/#{email}" %></li>
+<li><%= link_to email, url_for(controller: "rails/mailers", action: "preview", path: "#{@preview.preview_name}/#{email}") %></li>
<% end %>
</ul>
diff --git a/railties/lib/rails/templates/rails/welcome/index.html.erb b/railties/lib/rails/templates/rails/welcome/index.html.erb
index 6726c23fc9..acf04af416 100644
--- a/railties/lib/rails/templates/rails/welcome/index.html.erb
+++ b/railties/lib/rails/templates/rails/welcome/index.html.erb
@@ -18,7 +18,9 @@
color: #000;
}
- a {color: #03c}
+ a {
+ color: #03c;
+ }
a:hover {
background-color: #03c;
@@ -64,7 +66,10 @@
height: 64px;
}
- #header h1, #header h2 {margin: 0}
+ #header h1,
+ #header h2 {
+ margin: 0;
+ }
#header h2 {
color: #888;
@@ -104,7 +109,9 @@
color: #555;
}
- #about-content td.value {color: #000}
+ #about-content td.value {
+ color: #000;
+ }
#about-content ul {
padding: 0;
diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb
index c837fadb40..5cc1b5b219 100644
--- a/railties/lib/rails/test_help.rb
+++ b/railties/lib/rails/test_help.rb
@@ -2,18 +2,14 @@
# so fixtures aren't loaded into that environment
abort("Abort testing: Your Rails environment is running in production mode!") if Rails.env.production?
-require 'active_support/testing/autorun'
+require "rails/test_unit/minitest_plugin"
require 'active_support/test_case'
require 'action_controller'
require 'action_controller/test_case'
require 'action_dispatch/testing/integration'
require 'rails/generators/test_case'
-# Config Rails backtrace in tests.
-require 'rails/backtrace_cleaner'
-if ENV["BACKTRACE"].nil?
- Minitest.backtrace_filter = Rails.backtrace_cleaner
-end
+require 'active_support/testing/autorun'
if defined?(ActiveRecord::Base)
ActiveRecord::Migration.maintain_test_schema!
@@ -21,6 +17,7 @@ if defined?(ActiveRecord::Base)
class ActiveSupport::TestCase
include ActiveRecord::TestFixtures
self.fixture_path = "#{Rails.root}/test/fixtures/"
+ self.file_fixture_path = self.fixture_path + "files"
end
ActionDispatch::IntegrationTest.fixture_path = ActiveSupport::TestCase.fixture_path
@@ -31,13 +28,15 @@ if defined?(ActiveRecord::Base)
end
class ActionController::TestCase
- setup do
+ def before_setup # :nodoc:
@routes = Rails.application.routes
+ super
end
end
class ActionDispatch::IntegrationTest
- setup do
+ def before_setup # :nodoc:
@routes = Rails.application.routes
+ super
end
end
diff --git a/railties/lib/rails/test_unit/minitest_plugin.rb b/railties/lib/rails/test_unit/minitest_plugin.rb
new file mode 100644
index 0000000000..d1ba35a5ec
--- /dev/null
+++ b/railties/lib/rails/test_unit/minitest_plugin.rb
@@ -0,0 +1,88 @@
+require "active_support/core_ext/module/attribute_accessors"
+require "rails/test_unit/reporter"
+require "rails/test_unit/test_requirer"
+
+module Minitest
+ mattr_accessor(:hide_aggregated_results) { false }
+
+ module AggregatedResultSuppresion
+ def aggregated_results
+ super unless Minitest.hide_aggregated_results
+ end
+ end
+
+ SummaryReporter.prepend AggregatedResultSuppresion
+
+ def self.plugin_rails_options(opts, options)
+ opts.separator ""
+ opts.separator "Usage: bin/rails test [options] [files or directories]"
+ opts.separator "You can run a single test by appending a line number to a filename:"
+ opts.separator ""
+ opts.separator " bin/rails test test/models/user_test.rb:27"
+ opts.separator ""
+ opts.separator "You can run multiple files and directories at the same time:"
+ opts.separator ""
+ opts.separator " bin/rails test test/controllers test/integration/login_test.rb"
+ opts.separator ""
+ opts.separator "By default test failures and errors are reported inline during a run."
+ opts.separator ""
+
+ opts.separator "Rails options:"
+ opts.on("-e", "--environment ENV",
+ "Run tests in the ENV environment") do |env|
+ options[:environment] = env.strip
+ end
+
+ opts.on("-b", "--backtrace",
+ "Show the complete backtrace") do
+ options[:full_backtrace] = true
+ end
+
+ opts.on("-d", "--defer-output",
+ "Output test failures and errors after the test run") do
+ options[:output_inline] = false
+ end
+
+ opts.on("-f", "--fail-fast",
+ "Abort test run on first failure") do
+ options[:fail_fast] = true
+ end
+
+ options[:output_inline] = true
+ options[:patterns] = opts.order!
+ 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
+ run
+ end
+
+ def self.plugin_rails_init(options)
+ self.run_with_rails_extension = true
+
+ ENV["RAILS_ENV"] = options[:environment] || "test"
+
+ unless run_with_autorun
+ patterns = defined?(@rake_patterns) ? @rake_patterns : options[:patterns]
+ ::Rails::TestRequirer.require_files(patterns)
+ end
+
+ unless options[:full_backtrace] || ENV["BACKTRACE"]
+ # Plugin can run without Rails loaded, check before filtering.
+ Minitest.backtrace_filter = ::Rails.backtrace_cleaner if ::Rails.respond_to?(:backtrace_cleaner)
+ end
+
+ # Disable the extra failure output after a run, unless output is deferred.
+ self.hide_aggregated_results = options[:output_inline]
+
+ self.reporter << ::Rails::TestUnitReporter.new(options[:io], options)
+ end
+
+ mattr_accessor(:run_with_autorun) { false }
+ mattr_accessor(:run_with_rails_extension) { false }
+end
+
+Minitest.load_plugins
+Minitest.extensions << 'rails'
diff --git a/railties/lib/rails/test_unit/reporter.rb b/railties/lib/rails/test_unit/reporter.rb
new file mode 100644
index 0000000000..e1fe92a11b
--- /dev/null
+++ b/railties/lib/rails/test_unit/reporter.rb
@@ -0,0 +1,64 @@
+require "active_support/core_ext/class/attribute"
+require "minitest"
+
+module Rails
+ class TestUnitReporter < Minitest::StatisticsReporter
+ class_attribute :executable
+ self.executable = "bin/rails test"
+
+ def record(result)
+ super
+
+ if output_inline? && result.failure && (!result.skipped? || options[:verbose])
+ io.puts
+ io.puts
+ io.puts result.failures.map(&:message)
+ io.puts
+ io.puts format_rerun_snippet(result)
+ io.puts
+ end
+
+ if fail_fast? && result.failure && !result.error? && !result.skipped?
+ raise Interrupt
+ end
+ end
+
+ def report
+ return if output_inline? || filtered_results.empty?
+ io.puts
+ io.puts "Failed tests:"
+ io.puts
+ io.puts aggregated_results
+ end
+
+ def aggregated_results # :nodoc:
+ filtered_results.map { |result| format_rerun_snippet(result) }.join "\n"
+ end
+
+ def filtered_results
+ if options[:verbose]
+ results
+ else
+ results.reject(&:skipped?)
+ end
+ end
+
+ def relative_path_for(file)
+ file.sub(/^#{Rails.root}\/?/, '')
+ end
+
+ private
+ def output_inline?
+ options[:output_inline]
+ end
+
+ def fail_fast?
+ options[:fail_fast]
+ end
+
+ def format_rerun_snippet(result)
+ location, line = result.method(result.name).source_location
+ "#{self.executable} #{relative_path_for(location)}:#{line}"
+ end
+ end
+end
diff --git a/railties/lib/rails/test_unit/sub_test_task.rb b/railties/lib/rails/test_unit/sub_test_task.rb
deleted file mode 100644
index 6fa96d2ced..0000000000
--- a/railties/lib/rails/test_unit/sub_test_task.rb
+++ /dev/null
@@ -1,126 +0,0 @@
-require 'rake/testtask'
-
-module Rails
- class TestTask < Rake::TestTask # :nodoc: all
- # A utility class which is used primarily in "rails/test_unit/testing.rake"
- # to help define rake tasks corresponding to <tt>rake test</tt>.
- #
- # This class takes a TestInfo class and defines the appropriate rake task
- # based on the information, then invokes it.
- class TestCreator # :nodoc:
- def initialize(info)
- @info = info
- end
-
- def invoke_rake_task
- if @info.files.any?
- create_and_run_single_test
- reset_application_tasks
- else
- Rake::Task[ENV['TEST'] ? 'test:single' : 'test:run'].invoke
- end
- end
-
- private
-
- def create_and_run_single_test
- Rails::TestTask.new('test:single') { |t|
- t.test_files = @info.files
- }
- ENV['TESTOPTS'] ||= @info.opts
- Rake::Task['test:single'].invoke
- end
-
- def reset_application_tasks
- Rake.application.top_level_tasks.replace @info.tasks
- end
- end
-
- # This is a utility class used by the <tt>TestTask::TestCreator</tt> class.
- # This class takes a set of test tasks and checks to see if they correspond
- # to test files (or can be transformed into test files). Calling <tt>files</tt>
- # provides the set of test files and is used when initializing tests after
- # a call to <tt>rake test</tt>.
- class TestInfo # :nodoc:
- def initialize(tasks)
- @tasks = tasks
- @files = nil
- end
-
- def files
- @files ||= @tasks.map { |task|
- [task, translate(task)].find { |file| test_file?(file) }
- }.compact
- end
-
- def translate(file)
- if file =~ /^app\/(.*)$/
- "test/#{$1.sub(/\.rb$/, '')}_test.rb"
- else
- "test/#{file}_test.rb"
- end
- end
-
- def tasks
- @tasks - test_file_tasks - opt_names
- end
-
- def opts
- opts = opt_names
- if opts.any?
- "-n #{opts.join ' '}"
- end
- end
-
- private
-
- def test_file_tasks
- @tasks.find_all { |task|
- [task, translate(task)].any? { |file| test_file?(file) }
- }
- end
-
- def test_file?(file)
- file =~ /^test/ && File.file?(file) && !File.directory?(file)
- end
-
- def opt_names
- (@tasks - test_file_tasks).reject { |t| task_defined? t }
- end
-
- def task_defined?(task)
- Rake::Task.task_defined? task
- end
- end
-
- def self.test_creator(tasks)
- info = TestInfo.new(tasks)
- TestCreator.new(info)
- end
-
- def initialize(name = :test)
- super
- @libs << "test" # lib *and* test seem like a better default
- end
-
- def define
- task @name do
- if ENV['TESTOPTS']
- ARGV.replace Shellwords.split ENV['TESTOPTS']
- end
- libs = @libs - $LOAD_PATH
- $LOAD_PATH.unshift(*libs)
- file_list.each { |fl|
- FileList[fl].to_a.each { |f| require File.expand_path f }
- }
- end
- end
- end
-
- # Silence the default description to cut down on `rake -T` noise.
- class SubTestTask < Rake::TestTask # :nodoc:
- def desc(string)
- # Ignore the description.
- end
- end
-end
diff --git a/railties/lib/rails/test_unit/test_requirer.rb b/railties/lib/rails/test_unit/test_requirer.rb
new file mode 100644
index 0000000000..83d2c55ffd
--- /dev/null
+++ b/railties/lib/rails/test_unit/test_requirer.rb
@@ -0,0 +1,28 @@
+require 'active_support/core_ext/object/blank'
+require 'rake/file_list'
+
+module Rails
+ class TestRequirer # :nodoc:
+ class << self
+ def require_files(patterns)
+ patterns = expand_patterns(patterns)
+
+ Rake::FileList[patterns.compact.presence || 'test/**/*_test.rb'].to_a.each do |file|
+ require File.expand_path(file)
+ end
+ end
+
+ private
+ def expand_patterns(patterns)
+ patterns.map do |arg|
+ arg = arg.gsub(/:(\d+)?$/, '')
+ if Dir.exist?(arg)
+ "#{arg}/**/*_test.rb"
+ else
+ arg
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/railties/lib/rails/test_unit/testing.rake b/railties/lib/rails/test_unit/testing.rake
index d836c0d6d6..6676c6a079 100644
--- a/railties/lib/rails/test_unit/testing.rake
+++ b/railties/lib/rails/test_unit/testing.rake
@@ -1,11 +1,13 @@
-require 'rake/testtask'
-require 'rails/test_unit/sub_test_task'
+gem 'minitest'
+require 'minitest'
+require 'rails/test_unit/minitest_plugin'
task default: :test
desc "Runs all tests in test folder"
task :test do
- Rails::TestTask.test_creator(Rake.application.top_level_tasks).invoke_rake_task
+ $: << "test"
+ Minitest.rake_run(["test"])
end
namespace :test do
@@ -14,30 +16,30 @@ namespace :test do
# If used with Active Record, this task runs before the database schema is synchronized.
end
- Rails::TestTask.new(:run) do |t|
- t.pattern = "test/**/*_test.rb"
- end
+ task :run => %w[test]
desc "Run tests quickly, but also reset db"
task :db => %w[db:test:prepare test]
- Rails::TestTask.new(single: "test:prepare")
-
["models", "helpers", "controllers", "mailers", "integration", "jobs"].each do |name|
- Rails::TestTask.new(name => "test:prepare") do |t|
- t.pattern = "test/#{name}/**/*_test.rb"
+ task name => "test:prepare" do
+ $: << "test"
+ Minitest.rake_run(["test/#{name}"])
end
end
- Rails::TestTask.new(generators: "test:prepare") do |t|
- t.pattern = "test/lib/generators/**/*_test.rb"
+ task :generators => "test:prepare" do
+ $: << "test"
+ Minitest.rake_run(["test/lib/generators"])
end
- Rails::TestTask.new(units: "test:prepare") do |t|
- t.pattern = 'test/{models,helpers,unit}/**/*_test.rb'
+ task :units => "test:prepare" do
+ $: << "test"
+ Minitest.rake_run(["test/models", "test/helpers", "test/unit"])
end
- Rails::TestTask.new(functionals: "test:prepare") do |t|
- t.pattern = 'test/{controllers,mailers,functional}/**/*_test.rb'
+ task :functionals => "test:prepare" do
+ $: << "test"
+ Minitest.rake_run(["test/controllers", "test/mailers", "test/functional"])
end
end