diff options
Diffstat (limited to 'railties')
118 files changed, 2338 insertions, 803 deletions
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index 3822486412..afbebf5b95 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,187 +1,51 @@ -* Instrument an `load_config_initializer.railties` event on each load of configuration initializer - from `config/initializers`. Subscribers should be attached before `load_config_initializers` - initializer completed. +* Do not set the Rails environment to test by default when using test_unit Railtie. - Registering subscriber examples: + *Konstantin Shabanov* - # config/application.rb - module RailsApp - class Application < Rails::Application - ActiveSupport::Notifications.subscribe('load_config_initializer.railties') do |*args| - event = ActiveSupport::Notifications::Event.new(*args) - puts "Loaded initializer #{event.payload[:initializer]} (#{event.duration}ms)" - end - end - end +* Remove sqlite3 lines from `.gitignore` if the application is not using sqlite3. - # my_engine/lib/my_engine/engine.rb - module MyEngine - class Engine < ::Rails::Engine - config.before_initialize do - ActiveSupport::Notifications.subscribe('load_config_initializer.railties') do |*args| - event = ActiveSupport::Notifications::Event.new(*args) - puts "Loaded initializer #{event.payload[:initializer]} (#{event.duration}ms)" - end - end - end - end + *Dmitrii Golub* - *Paul Nikitochkin* - -* Support for Pathnames in eager load paths. - - *Mike Pack* - -* Fixed missing line and shadow on service pages(404, 422, 500). - - *Dmitry Korotkov* - -* `BACKTRACE` environment variable to show unfiltered backtraces for - test failures. +* Add public API to register new extensions for `rake notes`. Example: - $ BACKTRACE=1 ruby -Itest ... - # or with rake - $ BACKTRACE=1 bin/rake + config.annotations.register_extensions("scss", "sass") { |tag| /\/\/\s*(#{tag}):?\s*(.*)$/ } - *Yves Senn* + *Roberto Miranda* -* Removal of all javascript stuff (gems and files) when generating a new - application using the `--skip-javascript` option. +* Removed unnecessary `rails application` command. - *Robin Dupret* + *Arun Agrawal* -* Make the application name snake cased when it contains spaces +* Make the `rails:template` rake task load the application's initializers. - The application name is used to fill the `database.yml` and - `session_store.rb` files ; previously, if the provided name - contained whitespaces, it led to unexpected names in these files. + Fixes #12133. *Robin Dupret* -* Added `--model-name` option to `ScaffoldControllerGenerator`. - - *yalab* - -* Expose MiddlewareStack#unshift to environment configuration. - - *Ben Pickles* - -* `rails server` will only extend the logger to output to STDOUT - in development environment. - - *Richard Schneeman* - -* Don't require passing path to app before options in `rails new` - and `rails plugin new` - - *Piotr Sarnacki* - -* rake notes now searches *.less files - - *Josh Crowder* - -* Generate nested route for namespaced controller generated using - `rails g controller`. - Fixes #11532. +* Introduce `Rails.gem_version` as a convenience method to return + `Gem::Version.new(Rails.version)`, suggesting a more reliable way to perform + version comparison. Example: - rails g controller admin/dashboard index - - # Before: - get "dashboard/index" - - # After: - namespace :admin do - get "dashboard/index" - end - - *Prathamesh Sonpatki* - -* Fix the event name of action_dispatch requests. - - *Rafael Mendonça França* - -* Make `config.log_level` work with custom loggers. - - *Max Shytikov* - -* Changed stylesheet load order in the stylesheet manifest generator. - Fixes #11639. - - *Pawel Janiak* - -* Added generated unit test for generator generator using new - `test:generators` rake task. + Rails.version #=> "4.1.2" + Rails.gem_version #=> #<Gem::Version "4.1.2"> - *Josef Šimánek* + Rails.version > "4.1.10" #=> false + Rails.gem_version > Gem::Version.new("4.1.10") #=> true + Gem::Requirement.new("~> 4.1.2") =~ Rails.gem_version #=> true -* Removed `update:application_controller` rake task. - - *Josef Šimánek* - -* Fix `rake environment` to do not eager load modules - - *Paul Nikitochkin* - -* Fix `rake notes` to look into `*.sass` files - - *Yuri Artemev* - -* Removed deprecated `Rails.application.railties.engines`. - - *Arun Agrawal* - -* Removed deprecated threadsafe! from Rails Config. - - *Paul Nikitochkin* - -* Remove deprecated `ActiveRecord::Generators::ActiveModel#update_attributes` in - favor of `ActiveRecord::Generators::ActiveModel#update` - - *Vipul A M* - -* Remove deprecated `config.whiny_nils` option - - *Vipul A M* - -* Rename `commands/plugin_new.rb` to `commands/plugin.rb` and fix references - - *Richard Schneeman* - -* Fix `rails plugin --help` command. - - *Richard Schneeman* - -* Omit turbolinks configuration completely on skip_javascript generator option. - - *Nikita Fedyashev* - -* Removed deprecated rake tasks for running tests: `rake test:uncommitted` and - `rake test:recent`. - - *John Wang* - -* Clearing autoloaded constants triggers routes reloading. - Fixes #10685. - - *Xavier Noria* - -* Fixes bug with scaffold generator with `--assets=false --resource-route=false`. - Fixes #9525. - - *Arun Agrawal* + *Prem Sichanugrist* -* Rails::Railtie no longer forces the Rails::Configurable module on everything - that subclasses it. Instead, the methods from Rails::Configurable have been - moved to class methods in Railtie and the Railtie has been made abstract. +* Avoid namespacing routes inside engines. - *John Wang* + Mountable engines are namespaced by default so the generated routes + were too while they should not. -* Changes repetitive th tags to use colspan attribute in `index.html.erb` template. + Fixes #14079. - *Sıtkı Bağdat* + *Yves Senn*, *Carlos Antonio da Silva*, *Robin Dupret* -Please check [4-0-stable](https://github.com/rails/rails/blob/4-0-stable/railties/CHANGELOG.md) for previous changes. +Please check [4-1-stable](https://github.com/rails/rails/blob/4-1-stable/railties/CHANGELOG.md) for previous changes. diff --git a/railties/MIT-LICENSE b/railties/MIT-LICENSE index 0d7fb865e2..2950f05b11 100644 --- a/railties/MIT-LICENSE +++ b/railties/MIT-LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2013 David Heinemeier Hansson +Copyright (c) 2004-2014 David Heinemeier Hansson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb index ea82327365..ecd8c22dd8 100644 --- a/railties/lib/rails.rb +++ b/railties/lib/rails.rb @@ -25,6 +25,7 @@ module Rails autoload :Info autoload :InfoController + autoload :MailersController autoload :WelcomeController class << self @@ -79,10 +80,6 @@ module Rails groups end - def version - VERSION::STRING - end - def public_path application && Pathname.new(application.paths["public"].first) end diff --git a/railties/lib/rails/app_rails_loader.rb b/railties/lib/rails/app_rails_loader.rb index 1610751844..56f05b3844 100644 --- a/railties/lib/rails/app_rails_loader.rb +++ b/railties/lib/rails/app_rails_loader.rb @@ -55,7 +55,7 @@ EOS end def self.find_executable - EXECUTABLES.find { |exe| File.exist?(exe) } + EXECUTABLES.find { |exe| File.file?(exe) } end end end diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index d1e88cfafd..8d080feb04 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -1,6 +1,8 @@ require 'fileutils' +require 'active_support/core_ext/hash/keys' require 'active_support/core_ext/object/blank' require 'active_support/key_generator' +require 'active_support/message_verifier' require 'rails/engine' module Rails @@ -85,7 +87,7 @@ module Rails class << self def inherited(base) super - Rails.application ||= base.instance + base.instance end # Makes the +new+ method public. @@ -103,16 +105,19 @@ module Rails delegate :default_url_options, :default_url_options=, to: :routes INITIAL_VARIABLES = [:config, :railties, :routes_reloader, :reloaders, - :routes, :helpers, :app_env_config] # :nodoc: + :routes, :helpers, :app_env_config, :secrets] # :nodoc: def initialize(initial_variable_values = {}, &block) super() - @initialized = false - @reloaders = [] - @routes_reloader = nil - @app_env_config = nil - @ordered_railties = nil - @railties = nil + @initialized = false + @reloaders = [] + @routes_reloader = nil + @app_env_config = nil + @ordered_railties = nil + @railties = nil + @message_verifiers = {} + + Rails.application ||= self add_lib_to_load_path! ActiveSupport.run_load_hooks(:before_configuration, self) @@ -148,13 +153,37 @@ module Rails 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 ||= begin - if config.secret_key_base - key_generator = ActiveSupport::KeyGenerator.new(config.secret_key_base, iterations: 1000) + @caching_key_generator ||= + if secrets.secret_key_base + key_generator = ActiveSupport::KeyGenerator.new(secrets.secret_key_base, iterations: 1000) ActiveSupport::CachingKeyGenerator.new(key_generator) else ActiveSupport::LegacyKeyGenerator.new(config.secret_token) end + end + + # Returns a message verifier object. + # + # This verifier can be used to generate and verify signed messages in the application. + # + # It is recommended not to use the same verifier for different things, so you can get different + # verifiers passing the +verifier_name+ argument. + # + # ==== Parameters + # + # * +verifier_name+ - the name of the message verifier. + # + # ==== Examples + # + # message = Rails.application.message_verifier('sensitive_data').generate('my sensible data') + # Rails.application.message_verifier('sensitive_data').verify(message) + # # => 'my sensible data' + # + # See the +ActiveSupport::MessageVerifier+ documentation for more information. + def message_verifier(verifier_name) + @message_verifiers[verifier_name] ||= begin + secret = key_generator.generate_key(verifier_name.to_s) + ActiveSupport::MessageVerifier.new(secret) end end @@ -168,7 +197,7 @@ module Rails "action_dispatch.parameter_filter" => config.filter_parameters, "action_dispatch.redirect_filter" => config.filter_redirect, "action_dispatch.secret_token" => config.secret_token, - "action_dispatch.secret_key_base" => config.secret_key_base, + "action_dispatch.secret_key_base" => secrets.secret_key_base, "action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions, "action_dispatch.show_detailed_exceptions" => config.consider_all_requests_local, "action_dispatch.logger" => Rails.logger, @@ -177,7 +206,8 @@ module Rails "action_dispatch.http_auth_salt" => config.action_dispatch.http_auth_salt, "action_dispatch.signed_cookie_salt" => config.action_dispatch.signed_cookie_salt, "action_dispatch.encrypted_cookie_salt" => config.action_dispatch.encrypted_cookie_salt, - "action_dispatch.encrypted_signed_cookie_salt" => config.action_dispatch.encrypted_signed_cookie_salt + "action_dispatch.encrypted_signed_cookie_salt" => config.action_dispatch.encrypted_signed_cookie_salt, + "action_dispatch.cookies_serializer" => config.action_dispatch.cookies_serializer }) end end @@ -273,6 +303,28 @@ module Rails @config = configuration end + def secrets #:nodoc: + @secrets ||= begin + secrets = ActiveSupport::OrderedOptions.new + yaml = config.paths["config/secrets"].first + if File.exist?(yaml) + require "erb" + all_secrets = YAML.load(ERB.new(IO.read(yaml)).result) || {} + env_secrets = all_secrets[Rails.env] + secrets.merge!(env_secrets.symbolize_keys) if env_secrets + end + + # Fallback to config.secret_key_base if secrets.secret_key_base isn't set + secrets.secret_key_base ||= config.secret_key_base + + secrets + end + end + + def secrets=(secrets) #:nodoc: + @secrets = secrets + end + def to_app #:nodoc: self end @@ -281,6 +333,25 @@ module Rails config.helpers_paths end + console do + require "pp" + end + + console do + unless ::Kernel.private_method_defined?(:y) + if RUBY_VERSION >= '2.0' + require "psych/y" + else + module ::Kernel + def y(*objects) + puts ::Psych.dump_stream(*objects) + end + private :y + end + end + end + end + protected alias :build_middleware_stack :app @@ -364,8 +435,8 @@ module Rails end def validate_secret_key_config! #:nodoc: - if config.secret_key_base.blank? && config.secret_token.blank? - raise "You must set config.secret_key_base in your app's config." + if secrets.secret_key_base.blank? && config.secret_token.blank? + raise "Missing `secret_key_base` for '#{Rails.env}' environment, set this value in `config/secrets.yml`" end end end diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index dd0b9c6d70..4c449d2c57 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -1,6 +1,7 @@ require 'active_support/core_ext/kernel/reporting' require 'active_support/file_update_checker' require 'rails/engine/configuration' +require 'rails/source_annotation_extractor' module Rails class Application @@ -76,6 +77,7 @@ module Rails @paths ||= begin paths = super paths.add "config/database", with: "config/database.yml" + paths.add "config/secrets", with: "config/secrets.yml" paths.add "config/environment", with: "config/environment.rb" paths.add "lib/templates" paths.add "log", with: "log/#{Rails.env}.log" @@ -87,21 +89,30 @@ module Rails end end - # Loads and returns the configuration of the database. + # Loads and returns the entire raw configuration of database from + # values stored in `config/database.yml`. def database_configuration - yaml = paths["config/database"].first - if File.exist?(yaml) + yaml = Pathname.new(paths["config/database"].first || "") + + config = if yaml.exist? + require "yaml" require "erb" - YAML.load ERB.new(IO.read(yaml)).result + YAML.load(ERB.new(yaml.read).result) || {} elsif ENV['DATABASE_URL'] - nil + # Value from ENV['DATABASE_URL'] is set to default database connection + # by Active Record. + {} else raise "Could not load database configuration. No such file - #{yaml}" end + + config rescue Psych::SyntaxError => e raise "YAML syntax error occurred while parsing #{paths["config/database"].first}. " \ "Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \ "Error: #{e.message}" + rescue => e + raise e, "Cannot load `Rails.application.database_configuration`:\n#{e.message}", e.backtrace end def log_level @@ -140,6 +151,9 @@ module Rails end end + def annotations + SourceAnnotationExtractor::Annotation + end end end end diff --git a/railties/lib/rails/application/default_middleware_stack.rb b/railties/lib/rails/application/default_middleware_stack.rb index 570ff02c83..a00afe008c 100644 --- a/railties/lib/rails/application/default_middleware_stack.rb +++ b/railties/lib/rails/application/default_middleware_stack.rb @@ -11,11 +11,6 @@ module Rails def build_stack ActionDispatch::MiddlewareStack.new.tap do |middleware| - if rack_cache = load_rack_cache - require "action_dispatch/http/rack_cache" - middleware.use ::Rack::Cache, rack_cache - end - if config.force_ssl middleware.use ::ActionDispatch::SSL, config.ssl_options end @@ -26,6 +21,11 @@ module Rails middleware.use ::ActionDispatch::Static, paths["public"].first, config.static_cache_control end + if rack_cache = load_rack_cache + require "action_dispatch/http/rack_cache" + middleware.use ::Rack::Cache, rack_cache + end + middleware.use ::Rack::Lock unless allow_concurrency? middleware.use ::Rack::Runtime middleware.use ::Rack::MethodOverride diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index 7a1bb1e25c..5b8509b2e9 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -22,6 +22,8 @@ module Rails initializer :add_builtin_route do |app| if Rails.env.development? app.routes.append do + get '/rails/mailers' => "rails/mailers#index" + get '/rails/mailers/*path' => "rails/mailers#preview" get '/rails/info/properties' => "rails/info#properties" get '/rails/info/routes' => "rails/info#routes" get '/rails/info' => "rails/info#index" diff --git a/railties/lib/rails/application_controller.rb b/railties/lib/rails/application_controller.rb new file mode 100644 index 0000000000..9a29ec21cf --- /dev/null +++ b/railties/lib/rails/application_controller.rb @@ -0,0 +1,16 @@ +class Rails::ApplicationController < ActionController::Base # :nodoc: + self.view_paths = File.expand_path('../templates', __FILE__) + layout 'application' + + protected + + def require_local! + unless local_request? + render text: '<p>For security purposes, this information is only available to local requests.</p>', status: :forbidden + end + end + + def local_request? + Rails.application.config.consider_all_requests_local || request.local? + end +end diff --git a/railties/lib/rails/commands/commands_tasks.rb b/railties/lib/rails/commands/commands_tasks.rb index de60423784..6cfbc70c51 100644 --- a/railties/lib/rails/commands/commands_tasks.rb +++ b/railties/lib/rails/commands/commands_tasks.rb @@ -20,7 +20,6 @@ The most common rails commands are: new application called MyApp in "./my_app" In addition to those, there are: - application Generate the Rails application code destroy Undo code generated with "generate" (short-cut alias: "d") plugin new Generates skeleton for developing a Rails plugin runner Run a piece of code in the application environment (short-cut alias: "r") @@ -28,7 +27,7 @@ In addition to those, there are: All commands can be run with -h (or --help) for more information. EOT - COMMAND_WHITELIST = %(plugin generate destroy console server dbconsole application runner new version help) + COMMAND_WHITELIST = %w(plugin generate destroy console server dbconsole runner new version help) def initialize(argv) @argv = argv @@ -87,10 +86,6 @@ EOT Rails::DBConsole.start end - def application - require_command!("application") - end - def runner require_command!("runner") end diff --git a/railties/lib/rails/commands/dbconsole.rb b/railties/lib/rails/commands/dbconsole.rb index 3e4cc787c4..f6d8aec30d 100644 --- a/railties/lib/rails/commands/dbconsole.rb +++ b/railties/lib/rails/commands/dbconsole.rb @@ -81,14 +81,11 @@ module Rails def config @config ||= begin - cfg = begin - YAML.load(ERB.new(IO.read("config/database.yml")).result) - rescue SyntaxError, StandardError - require APP_PATH - Rails.application.config.database_configuration + if configurations[environment].blank? + raise ActiveRecord::AdapterNotSpecified, "'#{environment}' database is not configured. Available configuration: #{configurations.inspect}" + else + configurations[environment] end - - cfg[environment] || abort("No database is configured for the environment '#{environment}'") end end @@ -102,6 +99,12 @@ module Rails protected + def configurations + require APP_PATH + ActiveRecord::Base.configurations = Rails.application.config.database_configuration + ActiveRecord::Base.configurations + end + def parse_arguments(arguments) options = {} diff --git a/railties/lib/rails/commands/plugin.rb b/railties/lib/rails/commands/plugin.rb index 837fe0ec10..95bbdd4cdf 100644 --- a/railties/lib/rails/commands/plugin.rb +++ b/railties/lib/rails/commands/plugin.rb @@ -2,6 +2,20 @@ if ARGV.first != "new" ARGV[0] = "--help" else ARGV.shift + unless ARGV.delete("--no-rc") + customrc = ARGV.index{ |x| x.include?("--rc=") } + railsrc = if customrc + File.expand_path(ARGV.delete_at(customrc).gsub(/--rc=/, "")) + else + File.join(File.expand_path("~"), '.railsrc') + end + if File.exist?(railsrc) + extra_args_string = File.read(railsrc) + extra_args = extra_args_string.split(/\n+/).flat_map {|l| l.split} + puts "Using #{extra_args.join(" ")} from #{railsrc}" + ARGV.insert(1, *extra_args) + end + end end require 'rails/generators' diff --git a/railties/lib/rails/commands/runner.rb b/railties/lib/rails/commands/runner.rb index 2b77d5d387..3a71f8d3f8 100644 --- a/railties/lib/rails/commands/runner.rb +++ b/railties/lib/rails/commands/runner.rb @@ -9,7 +9,7 @@ if ARGV.first.nil? end ARGV.clone.options do |opts| - opts.banner = "Usage: rails runner [options] ('Some.ruby(code)' or a filename)" + opts.banner = "Usage: rails runner [options] [<'Some.ruby(code)'> | <filename.rb>]" opts.separator "" @@ -22,14 +22,23 @@ ARGV.clone.options do |opts| opts.on("-h", "--help", "Show this help message.") { $stdout.puts opts; exit } + opts.separator "" + opts.separator "Examples: " + + opts.separator " rails runner 'puts Rails.env'" + opts.separator " This runs the code `puts Rails.env` after loading the app" + opts.separator "" + opts.separator " rails runner path/to/filename.rb" + opts.separator " This runs the Ruby file located at `path/to/filename.rb` after loading the app" + if RbConfig::CONFIG['host_os'] !~ /mswin|mingw/ opts.separator "" opts.separator "You can also use runner as a shebang line for your executables:" - opts.separator "-------------------------------------------------------------" - opts.separator "#!/usr/bin/env #{File.expand_path($0)} runner" + opts.separator " -------------------------------------------------------------" + opts.separator " #!/usr/bin/env #{File.expand_path($0)} runner" opts.separator "" - opts.separator "Product.all.each { |p| p.price *= 2 ; p.save! }" - opts.separator "-------------------------------------------------------------" + opts.separator " Product.all.each { |p| p.price *= 2 ; p.save! }" + opts.separator " -------------------------------------------------------------" end opts.order! { |o| code_or_file ||= o } rescue retry @@ -50,5 +59,5 @@ elsif File.exist?(code_or_file) $0 = code_or_file Kernel.load code_or_file else - eval(code_or_file) + eval(code_or_file, binding, __FILE__, __LINE__) end diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 3f109debdc..b36ab3d0d5 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -2,7 +2,6 @@ require 'rails/railtie' require 'rails/engine/railties' require 'active_support/core_ext/module/delegation' require 'pathname' -require 'rbconfig' module Rails # <tt>Rails::Engine</tt> allows you to wrap a specific Rails application or subset of @@ -260,7 +259,7 @@ module Rails # # class FooController < ApplicationController # def index - # my_engine.root_url #=> /my_engine/ + # my_engine.root_url # => /my_engine/ # end # end # @@ -269,7 +268,7 @@ module Rails # module MyEngine # class BarController # def index - # main_app.foo_path #=> /foo + # main_app.foo_path # => /foo # end # end # end @@ -372,7 +371,7 @@ module Rails end def isolate_namespace(mod) - engine_name(generate_railtie_name(mod)) + engine_name(generate_railtie_name(mod.name)) self.routes.default_scope = { module: ActiveSupport::Inflector.underscore(mod.name) } self.isolated = true @@ -430,7 +429,6 @@ module Rails # Load console and invoke the registered hooks. # Check <tt>Rails::Railtie.console</tt> for more info. def load_console(app=self) - require "pp" require "rails/console/app" require "rails/console/helpers" run_console_blocks(app) diff --git a/railties/lib/rails/gem_version.rb b/railties/lib/rails/gem_version.rb new file mode 100644 index 0000000000..c7397c4f15 --- /dev/null +++ b/railties/lib/rails/gem_version.rb @@ -0,0 +1,15 @@ +module Rails + # Returns the version of the currently loaded Rails as a <tt>Gem::Version</tt> + def self.gem_version + Gem::Version.new VERSION::STRING + end + + module VERSION + MAJOR = 4 + MINOR = 2 + TINY = 0 + PRE = "alpha" + + STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") + end +end diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb index 366c72ebaa..625f031c94 100644 --- a/railties/lib/rails/generators/actions.rb +++ b/railties/lib/rails/generators/actions.rb @@ -9,7 +9,7 @@ module Rails @in_group = nil end - # Adds an entry into Gemfile for the supplied gem. + # Adds an entry into +Gemfile+ for the supplied gem. # # gem "rspec", group: :test # gem "technoweenie-restful-authentication", lib: "restful-authentication", source: "http://gems.github.com/" @@ -61,7 +61,7 @@ module Rails end end - # Add the given source to Gemfile + # Add the given source to +Gemfile+ # # add_source "http://gems.github.com/" def add_source(source, options={}) @@ -72,10 +72,10 @@ module Rails end end - # Adds a line inside the Application class for config/application.rb. + # Adds a line inside the Application class for <tt>config/application.rb</tt>. # - # If options :env is specified, the line is appended to the corresponding - # file in config/environments. + # If options <tt>:env</tt> is specified, the line is appended to the corresponding + # file in <tt>config/environments</tt>. # # environment do # "config.autoload_paths += %W(#{config.root}/extras)" @@ -116,7 +116,7 @@ module Rails end end - # Create a new file in the vendor/ directory. Code can be specified + # Create a new file in the <tt>vendor/</tt> directory. Code can be specified # in a block or a data string can be given. # # vendor("sekrit.rb") do @@ -143,7 +143,7 @@ module Rails create_file("lib/#{filename}", data, verbose: false, &block) end - # Create a new Rakefile with the provided code (either in a block or a string). + # Create a new +Rakefile+ with the provided code (either in a block or a string). # # rakefile("bootstrap.rake") do # project = ask("What is the UNIX name of your project?") @@ -188,7 +188,7 @@ module Rails # generate(:authenticated, "user session") def generate(what, *args) log :generate, what - argument = args.map {|arg| arg.to_s }.flatten.join(" ") + argument = args.flat_map {|arg| arg.to_s }.join(" ") in_root { run_ruby_script("bin/rails generate #{what} #{argument}", verbose: false) } end @@ -213,7 +213,7 @@ module Rails in_root { run("#{extify(:capify)} .", verbose: false) } end - # Make an entry in Rails routing file config/routes.rb + # Make an entry in Rails routing file <tt>config/routes.rb</tt> # # route "root 'welcome#index'" def route(routing_code) diff --git a/railties/lib/rails/generators/actions/create_migration.rb b/railties/lib/rails/generators/actions/create_migration.rb new file mode 100644 index 0000000000..cf3b7acfff --- /dev/null +++ b/railties/lib/rails/generators/actions/create_migration.rb @@ -0,0 +1,68 @@ +require 'thor/actions' + +module Rails + module Generators + module Actions + class CreateMigration < Thor::Actions::CreateFile + + def migration_dir + File.dirname(@destination) + end + + def migration_file_name + @base.migration_file_name + end + + def identical? + exists? && File.binread(existing_migration) == render + end + + def revoke! + say_destination = exists? ? relative_existing_migration : relative_destination + say_status :remove, :red, say_destination + return unless exists? + ::FileUtils.rm_rf(existing_migration) unless pretend? + existing_migration + end + + def relative_existing_migration + base.relative_to_original_destination_root(existing_migration) + end + + def existing_migration + @existing_migration ||= begin + @base.class.migration_exists?(migration_dir, migration_file_name) || + File.exist?(@destination) && @destination + end + end + alias :exists? :existing_migration + + protected + + def on_conflict_behavior(&block) + options = base.options.merge(config) + if identical? + say_status :identical, :blue, relative_existing_migration + elsif options[:force] + say_status :remove, :green, relative_existing_migration + say_status :create, :green + unless pretend? + ::FileUtils.rm_rf(existing_migration) + block.call + end + elsif options[:skip] + say_status :skip, :yellow + else + say_status :conflict, :red + raise Error, "Another migration is already named #{migration_file_name}: " + + "#{existing_migration}. Use --force to replace this migration file." + end + end + + def say_status(status, color, message = relative_destination) + base.shell.say_status(status, message, color) if config[:verbose] + end + end + end + end +end diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index d79cf2b2f0..c066f748ee 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -47,6 +47,9 @@ module Rails class_option :skip_sprockets, type: :boolean, aliases: '-S', default: false, desc: 'Skip Sprockets files' + class_option :skip_spring, type: :boolean, default: false, + desc: "Don't install Spring application preloader" + class_option :database, type: :string, aliases: '-d', default: 'sqlite3', desc: "Preconfigure for selected database (options: #{DATABASES.join('/')})" @@ -108,12 +111,12 @@ module Rails javascript_gemfile_entry, jbuilder_gemfile_entry, sdoc_gemfile_entry, - platform_dependent_gemfile_entry, + spring_gemfile_entry, @extra_entries].flatten.find_all(&@gem_filter) end def add_gem_entry_filter - @gem_filter = lambda { |next_filter,entry| + @gem_filter = lambda { |next_filter, entry| yield(entry) && next_filter.call(entry) }.curry[@gem_filter] end @@ -137,73 +140,12 @@ module Rails FileUtils.cd(destination_root) unless options[:pretend] end - class TemplateRecorder < ::BasicObject # :nodoc: - attr_reader :gems - - def initialize(target) - @target = target - # unfortunately, instance eval has access to these ivars - @app_const = target.send :app_const if target.respond_to?(:app_const, true) - @app_const_base = target.send :app_const_base if target.respond_to?(:app_const_base, true) - @app_name = target.send :app_name if target.respond_to?(:app_name, true) - @commands = [] - @gems = [] - end - - def gemfile_entry(*args) - @target.send :gemfile_entry, *args - end - - def add_gem_entry_filter(*args, &block) - @target.send :add_gem_entry_filter, *args, &block - end - - def method_missing(name, *args, &block) - @commands << [name, args, block] - end - - def respond_to_missing?(method, priv = false) - super || @target.respond_to?(method, priv) - end - - def replay! - @commands.each do |name, args, block| - @target.send name, *args, &block - end - end - end - def apply_rails_template - @recorder = TemplateRecorder.new self - - apply(rails_template, target: @recorder) if rails_template + apply rails_template if rails_template rescue Thor::Error, LoadError, Errno::ENOENT => e raise Error, "The template [#{rails_template}] could not be loaded. Error: #{e}" end - def replay_template - @recorder.replay! if @recorder - end - - def apply(path, config={}) - verbose = config.fetch(:verbose, true) - target = config.fetch(:target, self) - is_uri = path =~ /^https?\:\/\// - path = find_in_source_paths(path) unless is_uri - - say_status :apply, path, verbose - shell.padding += 1 if verbose - - if is_uri - contents = open(path, "Accept" => "application/x-thor-template") {|io| io.read } - else - contents = open(path) {|io| io.read } - end - - target.instance_eval(contents, path) - shell.padding -= 1 if verbose - end - def set_default_accessors! self.destination_root = File.expand_path(app_path, destination_root) self.rails_template = case options[:template] @@ -230,6 +172,10 @@ module Rails options[value] ? '# ' : '' end + def sqlite3? + !options[:skip_active_record] && options[:database] == 'sqlite3' + end + class GemfileEntry < Struct.new(:name, :version, :comment, :options, :commented_out) def initialize(name, version, comment, options = {}, commented_out = false) super @@ -257,8 +203,7 @@ module Rails [GemfileEntry.path('rails', Rails::Generators::RAILS_DEV_PATH), GemfileEntry.github('arel', 'rails/arel')] elsif options.edge? - [GemfileEntry.github('rails', 'rails/rails'), - GemfileEntry.github('arel', 'rails/arel')] + [GemfileEntry.github('rails', 'rails/rails')] else [GemfileEntry.version('rails', Rails::VERSION::STRING, @@ -304,7 +249,7 @@ module Rails 'Use SCSS for stylesheets') else gems << GemfileEntry.version('sass-rails', - '~> 4.0.0.rc1', + '~> 4.0.3', 'Use SCSS for stylesheets') end @@ -315,22 +260,14 @@ module Rails gems end - def platform_dependent_gemfile_entry - gems = [] - if RUBY_ENGINE == 'rbx' - gems << GemfileEntry.version('rubysl', nil) - end - gems - end - def jbuilder_gemfile_entry comment = 'Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder' - GemfileEntry.version('jbuilder', '~> 1.2', comment) + 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', nil, comment, { group: :doc, require: false }) + GemfileEntry.new('sdoc', '~> 0.4.0', comment, group: :doc) end def coffee_gemfile_entry @@ -365,6 +302,12 @@ module Rails end end + def spring_gemfile_entry + return [] unless spring_install? + comment = 'Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring' + GemfileEntry.new('spring', nil, comment, group: :development) + end + def bundle_command(command) say_status :run, "bundle #{command}" @@ -384,12 +327,27 @@ module Rails require 'bundler' Bundler.with_clean_env do - print `"#{Gem.ruby}" "#{_bundle_command}" #{command}` + output = `"#{Gem.ruby}" "#{_bundle_command}" #{command}` + print output unless options[:quiet] end end + def bundle_install? + !(options[:skip_gemfile] || options[:skip_bundle] || options[:pretend]) + end + + def spring_install? + !options[:skip_spring] && Process.respond_to?(:fork) + end + def run_bundle - bundle_command('install') unless options[:skip_gemfile] || options[:skip_bundle] || options[:pretend] + bundle_command('install') if bundle_install? + end + + def generate_spring_binstubs + if bundle_install? && spring_install? + bundle_command("exec spring binstub --all") + end end def empty_directory_with_keep_file(destination, config = {}) diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb index cf33b13fd8..67bab96a22 100644 --- a/railties/lib/rails/generators/base.rb +++ b/railties/lib/rails/generators/base.rb @@ -296,7 +296,7 @@ module Rails end end - # Return the default value for the option name given doing a lookup in + # Returns the default value for the option name given doing a lookup in # Rails::Generators.options. def self.default_value_for_option(name, options) default_for_option(Rails::Generators.options, name, options, options[:default]) diff --git a/railties/lib/rails/generators/erb.rb b/railties/lib/rails/generators/erb.rb index 73e986ee7f..0755ac335c 100644 --- a/railties/lib/rails/generators/erb.rb +++ b/railties/lib/rails/generators/erb.rb @@ -5,6 +5,10 @@ module Erb # :nodoc: class Base < Rails::Generators::NamedBase #:nodoc: protected + def formats + [format] + end + def format :html end @@ -13,7 +17,7 @@ module Erb # :nodoc: :erb end - def filename_with_extensions(name) + def filename_with_extensions(name, format = self.format) [name, format, handler].compact.join(".") end end diff --git a/railties/lib/rails/generators/erb/controller/controller_generator.rb b/railties/lib/rails/generators/erb/controller/controller_generator.rb index 5f06734ab8..94c1b835d1 100644 --- a/railties/lib/rails/generators/erb/controller/controller_generator.rb +++ b/railties/lib/rails/generators/erb/controller/controller_generator.rb @@ -11,8 +11,10 @@ module Erb # :nodoc: actions.each do |action| @action = action - @path = File.join(base_path, filename_with_extensions(action)) - template filename_with_extensions(:view), @path + formats.each do |format| + @path = File.join(base_path, filename_with_extensions(action, format)) + template filename_with_extensions(:view, format), @path + end end end end diff --git a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb index 7bcac30dde..66b17bd10e 100644 --- a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb +++ b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb @@ -5,8 +5,8 @@ module Erb # :nodoc: class MailerGenerator < ControllerGenerator # :nodoc: protected - def format - :text + def formats + [:text, :html] end end end diff --git a/railties/lib/rails/generators/erb/mailer/templates/view.html.erb b/railties/lib/rails/generators/erb/mailer/templates/view.html.erb new file mode 100644 index 0000000000..b5045671b3 --- /dev/null +++ b/railties/lib/rails/generators/erb/mailer/templates/view.html.erb @@ -0,0 +1,5 @@ +<h1><%= class_name %>#<%= @action %></h1> + +<p> + <%%= @greeting %>, find me in <%= @path %> +</p> diff --git a/railties/lib/rails/generators/erb/mailer/templates/view.text.erb b/railties/lib/rails/generators/erb/mailer/templates/view.text.erb index 6d597256a6..342285df19 100644 --- a/railties/lib/rails/generators/erb/mailer/templates/view.text.erb +++ b/railties/lib/rails/generators/erb/mailer/templates/view.text.erb @@ -1,3 +1,3 @@ <%= class_name %>#<%= @action %> -<%%= @greeting %>, find me in app/views/<%= @path %> +<%%= @greeting %>, find me in <%= @path %> diff --git a/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb index bacbc2d280..c94829a0ae 100644 --- a/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb @@ -14,8 +14,10 @@ module Erb # :nodoc: def copy_view_files available_views.each do |view| - filename = filename_with_extensions(view) - template filename, File.join("app/views", controller_file_path, filename) + formats.each do |format| + filename = filename_with_extensions(view, format) + template filename, File.join("app/views", controller_file_path, filename) + 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 69c10efa47..10f80abb15 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb @@ -4,8 +4,8 @@ <h2><%%= pluralize(@<%= singular_table_name %>.errors.count, "error") %> prohibited this <%= singular_table_name %> from being saved:</h2> <ul> - <%% @<%= singular_table_name %>.errors.full_messages.each do |msg| %> - <li><%%= msg %></li> + <%% @<%= singular_table_name %>.errors.full_messages.each do |message| %> + <li><%%= message %></li> <%% end %> </ul> </div> diff --git a/railties/lib/rails/generators/generated_attribute.rb b/railties/lib/rails/generators/generated_attribute.rb index 5e2784c4b0..c5326d70d1 100644 --- a/railties/lib/rails/generators/generated_attribute.rb +++ b/railties/lib/rails/generators/generated_attribute.rb @@ -94,6 +94,10 @@ module Rails name.sub(/_id$/, '').pluralize end + def singular_name + name.sub(/_id$/, '').singularize + end + def human_name name.humanize end diff --git a/railties/lib/rails/generators/migration.rb b/railties/lib/rails/generators/migration.rb index 3566f96f5e..cd388e590a 100644 --- a/railties/lib/rails/generators/migration.rb +++ b/railties/lib/rails/generators/migration.rb @@ -1,4 +1,5 @@ require 'active_support/concern' +require 'rails/generators/actions/create_migration' module Rails module Generators @@ -29,6 +30,19 @@ module Rails end end + def create_migration(destination, data, config = {}, &block) + action Rails::Generators::Actions::CreateMigration.new(self, destination, block || data.to_s, config) + end + + def set_migration_assigns!(destination) + destination = File.expand_path(destination, self.destination_root) + + migration_dir = File.dirname(destination) + @migration_number = self.class.next_migration_number(migration_dir) + @migration_file_name = File.basename(destination, '.rb') + @migration_class_name = @migration_file_name.camelize + end + # Creates a migration template at the given destination. The difference # to the default template method is that the migration version is appended # to the destination file name. @@ -37,26 +51,18 @@ module Rails # available as instance variables in the template to be rendered. # # migration_template "migration.rb", "db/migrate/add_foo_to_bar.rb" - def migration_template(source, destination=nil, config={}) - destination = File.expand_path(destination || source, self.destination_root) + def migration_template(source, destination, config = {}) + source = File.expand_path(find_in_source_paths(source.to_s)) - migration_dir = File.dirname(destination) - @migration_number = self.class.next_migration_number(migration_dir) - @migration_file_name = File.basename(destination).sub(/\.rb$/, '') - @migration_class_name = @migration_file_name.camelize + set_migration_assigns!(destination) + context = instance_eval('binding') - destination = self.class.migration_exists?(migration_dir, @migration_file_name) + dir, base = File.split(destination) + numbered_destination = File.join(dir, ["%migration_number%", base].join('_')) - if !(destination && options[:skip]) && behavior == :invoke - if destination && options.force? - remove_file(destination) - elsif destination - raise Error, "Another migration is already named #{@migration_file_name}: #{destination}. Use --force to remove the old migration file and replace it." - end - destination = File.join(migration_dir, "#{@migration_number}_#{@migration_file_name}.rb") + create_migration numbered_destination, nil, config do + ERB.new(::File.binread(source), nil, '-', '@output_buffer').result(context) end - - template(source, destination, config) end end end diff --git a/railties/lib/rails/generators/model_helpers.rb b/railties/lib/rails/generators/model_helpers.rb new file mode 100644 index 0000000000..42c646543e --- /dev/null +++ b/railties/lib/rails/generators/model_helpers.rb @@ -0,0 +1,28 @@ +require 'rails/generators/active_model' + +module Rails + module Generators + module ModelHelpers # :nodoc: + PLURAL_MODEL_NAME_WARN_MESSAGE = "[WARNING] The model name '%s' was recognized as a plural, using the singular '%s' instead. " \ + "Override with --force-plural or setup custom inflection rules for this noun before running the generator." + mattr_accessor :skip_warn + + def self.included(base) #:nodoc: + base.class_option :force_plural, type: :boolean, default: false, desc: 'Forces the use of the given model name' + end + + def initialize(args, *_options) + super + if name == name.pluralize && name.singularize != name.pluralize && !options[:force_plural] + singular = name.singularize + unless ModelHelpers.skip_warn + say PLURAL_MODEL_NAME_WARN_MESSAGE % [name, singular] + ModelHelpers.skip_warn = true + end + name.replace singular + assign_names!(name) + end + end + end + end +end diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index a2023886cd..abf6909a7f 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -50,7 +50,7 @@ module Rails end def gitignore - copy_file "gitignore", ".gitignore" + template "gitignore", ".gitignore" end def app @@ -78,6 +78,7 @@ module Rails template "routes.rb" template "application.rb" template "environment.rb" + template "secrets.yml" directory "environments" directory "initializers" @@ -165,7 +166,6 @@ module Rails end public_task :set_default_accessors! - public_task :apply_rails_template public_task :create_root def create_root_files @@ -225,18 +225,18 @@ module Rails build(:vendor) end - def finish_template - build(:leftovers) - end - def delete_js_folder_skipping_javascript if options[:skip_javascript] remove_dir 'app/assets/javascripts' end end - public_task :run_bundle - public_task :replay_template + def finish_template + build(:leftovers) + end + + public_task :apply_rails_template, :run_bundle + public_task :generate_spring_binstubs protected diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile index 68bd62d4b1..a9b6787894 100644 --- a/railties/lib/rails/generators/rails/app/templates/Gemfile +++ b/railties/lib/rails/generators/rails/app/templates/Gemfile @@ -6,17 +6,15 @@ source 'https://rubygems.org' # <%= gem.comment %> <% end -%> -<%= gem.commented_out ? '# ' : '' %>gem '<%= gem.name %>'<% if gem.version -%> -, '<%= gem.version %>' -<% elsif gem.options.any? -%> +<%= gem.commented_out ? '# ' : '' %>gem '<%= gem.name %>'<%= %(, '#{gem.version}') if gem.version -%> +<% if gem.options.any? -%> ,<%= gem.padding(max_width) %><%= gem.options.map { |k,v| "#{k}: #{v.inspect}" }.join(', ') %> -<% else %> <% end -%> <% end -%> # Use ActiveModel has_secure_password -# gem 'bcrypt-ruby', '~> 3.1.2' +# gem 'bcrypt', '~> 3.1.7' # Use unicorn as the app server # gem 'unicorn' 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 8b91313e51..07ea09cdbd 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 @@ -13,6 +13,8 @@ <% unless options[:skip_javascript] -%> //= require <%= options[:javascript] %> //= require <%= options[:javascript] %>_ujs +<% if gemfile_entries.any? { |m| m.name == "turbolinks" } -%> //= require turbolinks <% end -%> +<% end -%> //= require_tree . diff --git a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt index fe71f7122c..75ea52828e 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +++ b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt @@ -3,14 +3,14 @@ <head> <title><%= camelized %></title> <%- if options[:skip_javascript] -%> - <%%= stylesheet_link_tag "application", media: "all" %> + <%%= stylesheet_link_tag 'application', media: 'all' %> <%- else -%> - <%- if gemfile_entries.any? { |m| m.name == "turbolinks" } -%> - <%%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true %> - <%%= javascript_include_tag "application", "data-turbolinks-track" => true %> + <%- if gemfile_entries.any? { |m| m.name == 'turbolinks' } -%> + <%%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %> + <%%= javascript_include_tag 'application', 'data-turbolinks-track' => true %> <%- else -%> - <%%= stylesheet_link_tag "application", media: "all" %> - <%%= javascript_include_tag "application" %> + <%%= stylesheet_link_tag 'application', media: 'all' %> + <%%= javascript_include_tag 'application' %> <%- end -%> <%- end -%> <%%= csrf_meta_tags %> 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 ac41a0cadb..16fe50bab8 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/application.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb @@ -15,7 +15,7 @@ require "action_mailer/railtie" # Require the gems listed in Gemfile, including any gems # you've limited to :test, :development, or :production. -Bundler.require(:default, Rails.env) +Bundler.require(*Rails.groups) module <%= app_const_base %> class Application < Rails::Application @@ -30,10 +30,5 @@ module <%= app_const_base %> # 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.skip_sprockets? -%> - - # Disable the asset pipeline. - config.assets.enabled = false -<% end -%> end end diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/frontbase.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/frontbase.yml index c6dfd50d40..34fc0e3465 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/frontbase.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/frontbase.yml @@ -23,6 +23,27 @@ test: <<: *default database: <%= app_name %>_test +# As with config/secrets.yml, you never want to store sensitive information, +# like your database password, in your source code. If your source code is +# ever seen by anyone, they now have access to your database. +# +# Instead, provide the password as a unix environment variable when you boot +# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database +# for a full rundown on how to provide these environment variables in a +# production deployment. +# +# On Heroku and other platform providers, you may have a full connection URL +# available as an environment variable. For example: +# +# DATABASE_URL="frontbase://myuser:mypass@localhost/somedatabase" +# +# You can use this database configuration with: +# +# production: +# url: <%%= ENV['DATABASE_URL'] %> +# production: <<: *default database: <%= app_name %>_production + username: <%= app_name %> + password: <%%= ENV['<%= app_name.upcase %>_DATABASE_PASSWORD'] %> diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/ibm_db.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/ibm_db.yml index fe53cd0ea2..d088dd62bf 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/ibm_db.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/ibm_db.yml @@ -61,6 +61,27 @@ test: <<: *default database: <%= app_name[0,4] %>_tst +# As with config/secrets.yml, you never want to store sensitive information, +# like your database password, in your source code. If your source code is +# ever seen by anyone, they now have access to your database. +# +# Instead, provide the password as a unix environment variable when you boot +# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database +# for a full rundown on how to provide these environment variables in a +# production deployment. +# +# On Heroku and other platform providers, you may have a full connection URL +# available as an environment variable. For example: +# +# DATABASE_URL="ibm-db://myuser:mypass@localhost/somedatabase" +# +# You can use this database configuration with: +# +# production: +# url: <%%= ENV['DATABASE_URL'] %> +# production: <<: *default - database: <%= app_name[0,8] %> + database: <%= app_name %>_production + username: <%= app_name %> + password: <%%= ENV['<%= app_name.upcase %>_DATABASE_PASSWORD'] %> diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbc.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbc.yml index 2a6cd4f3f4..db0a429753 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbc.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbc.yml @@ -5,35 +5,35 @@ # Configure using Gemfile: # gem 'activerecord-jdbcmssql-adapter' # -#development: -# adapter: mssql -# username: <%= app_name %> -# password: -# host: localhost -# database: <%= app_name %>_development +# development: +# adapter: mssql +# username: <%= app_name %> +# password: +# host: localhost +# database: <%= app_name %>_development # # Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. # -#test: -# adapter: mssql -# username: <%= app_name %> -# password: -# host: localhost -# database: <%= app_name %>_test +# test: +# adapter: mssql +# username: <%= app_name %> +# password: +# host: localhost +# database: <%= app_name %>_test # -#production: -# adapter: mssql -# username: <%= app_name %> -# password: -# host: localhost -# database: <%= app_name %>_production +# production: +# adapter: mssql +# username: <%= app_name %> +# password: +# host: localhost +# database: <%= app_name %>_production # If you are using oracle, db2, sybase, informix or prefer to use the plain # JDBC adapter, configure your database setting as the example below (requires # you to download and manually install the database vendor's JDBC driver .jar -# file). See your driver documentation for the apropriate driver class and +# file). See your driver documentation for the appropriate driver class and # connection string: default: &default @@ -53,6 +53,16 @@ test: <<: *default url: jdbc:db://localhost/<%= app_name %>_test +# As with config/secrets.yml, you never want to store sensitive information, +# like your database password, in your source code. If your source code is +# ever seen by anyone, they now have access to your database. +# +# Instead, provide the password as a unix environment variable when you boot +# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database +# for a full rundown on how to provide these environment variables in a +# production deployment. +# production: - <<: *default url: jdbc:db://localhost/<%= app_name %>_production + username: <%= app_name %> + password: <%%= ENV['<%= app_name.upcase %>_DATABASE_PASSWORD'] %> 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 26e2a5976c..acb93939e1 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 @@ -26,6 +26,27 @@ test: <<: *default database: <%= app_name %>_test +# As with config/secrets.yml, you never want to store sensitive information, +# like your database password, in your source code. If your source code is +# ever seen by anyone, they now have access to your database. +# +# Instead, provide the password as a unix environment variable when you boot +# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database +# for a full rundown on how to provide these environment variables in a +# production deployment. +# +# On Heroku and other platform providers, you may have a full connection URL +# available as an environment variable. For example: +# +# DATABASE_URL="mysql://myuser:mypass@localhost/somedatabase" +# +# You can use this database configuration with: +# +# production: +# url: <%%= ENV['DATABASE_URL'] %> +# production: <<: *default database: <%= app_name %>_production + username: <%= app_name %> + password: <%%= ENV['<%= app_name.upcase %>_DATABASE_PASSWORD'] %> diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml index ccd44cf54b..9e99264d33 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml @@ -6,13 +6,20 @@ default: &default adapter: postgresql encoding: unicode - username: <%= app_name %> - password: development: <<: *default database: <%= app_name %>_development + # The specified database role being used to connect to postgres. + # To create additional roles in postgres see `$ createuser --help`. + # When left blank, postgres will use the default role. This is + # the same name as the operating system user that initialized the database. + #username: <%= app_name %> + + # The password associated with the postgres role (username). + #password: + # Connect on a TCP socket. Omitted by default since the client uses a # domain socket that doesn't need configuration. Windows does not have # domain sockets, so uncomment these lines. @@ -35,6 +42,27 @@ test: <<: *default database: <%= app_name %>_test +# As with config/secrets.yml, you never want to store sensitive information, +# like your database password, in your source code. If your source code is +# ever seen by anyone, they now have access to your database. +# +# Instead, provide the password as a unix environment variable when you boot +# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database +# for a full rundown on how to provide these environment variables in a +# production deployment. +# +# On Heroku and other platform providers, you may have a full connection URL +# available as an environment variable. For example: +# +# DATABASE_URL="postgres://myuser:mypass@localhost/somedatabase" +# +# You can use this database configuration with: +# +# production: +# url: <%%= ENV['DATABASE_URL'] %> +# production: <<: *default database: <%= app_name %>_production + username: <%= app_name %> + password: <%%= ENV['<%= app_name.upcase %>_DATABASE_PASSWORD'] %> 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 3fc7ce28a1..4b2e6646c7 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml @@ -1,4 +1,4 @@ -# MySQL. Versions 4.1 and 5.0 are recommended. +# MySQL. Versions 5.0+ are recommended. # # Install the MYSQL driver # gem install mysql2 @@ -32,6 +32,27 @@ test: <<: *default database: <%= app_name %>_test +# As with config/secrets.yml, you never want to store sensitive information, +# like your database password, in your source code. If your source code is +# ever seen by anyone, they now have access to your database. +# +# Instead, provide the password as a unix environment variable when you boot +# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database +# for a full rundown on how to provide these environment variables in a +# production deployment. +# +# On Heroku and other platform providers, you may have a full connection URL +# available as an environment variable. For example: +# +# DATABASE_URL="mysql2://myuser:mypass@localhost/somedatabase" +# +# You can use this database configuration with: +# +# production: +# url: <%%= ENV['DATABASE_URL'] %> +# production: <<: *default database: <%= app_name %>_production + username: <%= app_name %> + password: <%%= ENV['<%= app_name.upcase %>_DATABASE_PASSWORD'] %> diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/oracle.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/oracle.yml index d5b52c969b..10ab4c02e2 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/oracle.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/oracle.yml @@ -32,6 +32,27 @@ test: <<: *default database: <%= app_name %>_test +# As with config/secrets.yml, you never want to store sensitive information, +# like your database password, in your source code. If your source code is +# ever seen by anyone, they now have access to your database. +# +# Instead, provide the password as a unix environment variable when you boot +# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database +# for a full rundown on how to provide these environment variables in a +# production deployment. +# +# On Heroku and other platform providers, you may have a full connection URL +# available as an environment variable. For example: +# +# DATABASE_URL="oracle://myuser:mypass@localhost/somedatabase" +# +# You can use this database configuration with: +# +# production: +# url: <%%= ENV['DATABASE_URL'] %> +# production: <<: *default database: <%= app_name %>_production + username: <%= app_name %> + password: <%%= ENV['<%= app_name.upcase %>_DATABASE_PASSWORD'] %> diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml index eaeb82bddd..feb25bbc6b 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml @@ -17,16 +17,23 @@ default: &default adapter: postgresql encoding: unicode - # For details on connection pooling, see rails configration guide + # For details on connection pooling, see rails configuration guide # http://guides.rubyonrails.org/configuring.html#database-pooling pool: 5 - username: <%= app_name %> - password: development: <<: *default database: <%= app_name %>_development + # The specified database role being used to connect to postgres. + # To create additional roles in postgres see `$ createuser --help`. + # When left blank, postgres will use the default role. This is + # the same name as the operating system user that initialized the database. + #username: <%= app_name %> + + # The password associated with the postgres role (username). + #password: + # Connect on a TCP socket. Omitted by default since the client uses a # domain socket that doesn't need configuration. Windows does not have # domain sockets, so uncomment these lines. @@ -52,6 +59,27 @@ test: <<: *default database: <%= app_name %>_test +# As with config/secrets.yml, you never want to store sensitive information, +# like your database password, in your source code. If your source code is +# ever seen by anyone, they now have access to your database. +# +# Instead, provide the password as a unix environment variable when you boot +# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database +# for a full rundown on how to provide these environment variables in a +# production deployment. +# +# On Heroku and other platform providers, you may have a full connection URL +# available as an environment variable. For example: +# +# DATABASE_URL="postgres://myuser:mypass@localhost/somedatabase" +# +# You can use this database configuration with: +# +# production: +# url: <%%= ENV['DATABASE_URL'] %> +# production: <<: *default database: <%= app_name %>_production + username: <%= app_name %> + password: <%%= ENV['<%= app_name.upcase %>_DATABASE_PASSWORD'] %> diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml index 4855f66c0d..30b0df34a8 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml @@ -42,6 +42,27 @@ test: <<: *default database: <%= app_name %>_test +# As with config/secrets.yml, you never want to store sensitive information, +# like your database password, in your source code. If your source code is +# ever seen by anyone, they now have access to your database. +# +# Instead, provide the password as a unix environment variable when you boot +# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database +# for a full rundown on how to provide these environment variables in a +# production deployment. +# +# On Heroku and other platform providers, you may have a full connection URL +# available as an environment variable. For example: +# +# DATABASE_URL="sqlserver://myuser:mypass@localhost/somedatabase" +# +# You can use this database configuration with: +# +# production: +# url: <%%= ENV['DATABASE_URL'] %> +# production: <<: *default database: <%= app_name %>_production + username: <%= app_name %> + password: <%%= ENV['<%= app_name.upcase %>_DATABASE_PASSWORD'] %> 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 b724d468a2..de12565a73 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 @@ -29,5 +29,13 @@ Rails.application.configure do # This option may cause significant delays in view rendering with a large # number of complex assets. config.assets.debug = true + + # Adds additional error checking when serving assets at runtime. + # Checks for improperly declared sprockets dependencies. + # Raises helpful error messages. + config.assets.raise_runtime_errors = true <%- end -%> + + # Raises error for missing translations + # config.action_view.raise_on_missing_translations = true end diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt index 1dfc9f136b..b789ed9a94 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 @@ -5,7 +5,7 @@ Rails.application.configure do config.cache_classes = true # Eager load code on boot. This eager loads most of Rails and - # your application in memory, allowing both thread web servers + # your application in memory, allowing both threaded web servers # and those relying on copy on write to perform better. # Rake tasks automatically ignore this option for performance. config.eager_load = true @@ -35,6 +35,10 @@ Rails.application.configure do # Version of your assets, change this if you want to expire all your assets. config.assets.version = '1.0' + + # Precompile additional assets. + # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. + # config.assets.precompile += %w( search.js ) <%- end -%> # Specifies the header that your server uses for sending files. @@ -59,18 +63,12 @@ Rails.application.configure do # Enable serving of images, stylesheets, and JavaScripts from an asset server. # config.action_controller.asset_host = "http://assets.example.com" - <%- unless options.skip_sprockets? -%> - # Precompile additional assets. - # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. - # config.assets.precompile += %w( search.js ) - <%- end -%> - # Ignore bad email addresses and do not raise email delivery errors. # Set this to true and configure the email server for immediate delivery to raise delivery errors. # config.action_mailer.raise_delivery_errors = false # Enable locale fallbacks for I18n (makes lookups for any locale fall back to - # the I18n.default_locale when a translation can not be found). + # the I18n.default_locale when a translation cannot be found). config.i18n.fallbacks = true # Send deprecation notices to registered listeners. @@ -81,4 +79,9 @@ Rails.application.configure do # Use default logging formatter so that PID and timestamp are not suppressed. config.log_formatter = ::Logger::Formatter.new + <%- unless options.skip_active_record? -%> + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false + <%- end -%> end 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 ba0742f97f..053f5b66d7 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 @@ -14,7 +14,7 @@ Rails.application.configure do # Configure static asset server for tests with Cache-Control for performance. config.serve_static_assets = true - config.static_cache_control = "public, max-age=3600" + config.static_cache_control = 'public, max-age=3600' # Show full error reports and disable caching. config.consider_all_requests_local = true @@ -33,4 +33,7 @@ Rails.application.configure do # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr + + # Raises error for missing translations + # config.action_view.raise_on_missing_translations = true end diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/cookies_serializer.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/cookies_serializer.rb new file mode 100644 index 0000000000..7f70458dee --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/cookies_serializer.rb @@ -0,0 +1,3 @@ +# Be sure to restart your server when you modify this file. + +Rails.application.config.action_dispatch.cookies_serializer = :json diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/mime_types.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/mime_types.rb index 72aca7e441..dc1899682b 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/mime_types.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/mime_types.rb @@ -2,4 +2,3 @@ # Add new mime types for use in respond_to blocks: # Mime::Type.register "text/richtext", :rtf -# Mime::Type.register_alias "text/html", :iphone diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/secret_token.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/secrets.yml index f3cc6098a3..b2669a0f79 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/secret_token.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/secrets.yml @@ -7,6 +7,16 @@ # no regular words or you'll be exposed to dictionary attacks. # You can use `rake secret` to generate a secure secret key. -# Make sure your secret_key_base is kept private +# Make sure the secrets in this file are kept private # if you're sharing your code publicly. -Rails.application.config.secret_key_base = '<%= app_secret %>' + +development: + secret_key_base: <%= app_secret %> + +test: + secret_key_base: <%= app_secret %> + +# Do not keep production secrets in the repository, +# instead read values from the environment. +production: + secret_key_base: <%%= ENV["SECRET_KEY_BASE"] %> diff --git a/railties/lib/rails/generators/rails/app/templates/gitignore b/railties/lib/rails/generators/rails/app/templates/gitignore index 6a502e997f..8775e5e235 100644 --- a/railties/lib/rails/generators/rails/app/templates/gitignore +++ b/railties/lib/rails/generators/rails/app/templates/gitignore @@ -7,10 +7,12 @@ # Ignore bundler config. /.bundle +<% if sqlite3? -%> # Ignore the default SQLite database. /db/*.sqlite3 /db/*.sqlite3-journal +<% end -%> # Ignore all logfiles and tempfiles. /log/*.log /tmp diff --git a/railties/lib/rails/generators/rails/app/templates/public/404.html b/railties/lib/rails/generators/rails/app/templates/public/404.html index 7d99be2ecf..b612547fc2 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/404.html +++ b/railties/lib/rails/generators/rails/app/templates/public/404.html @@ -58,10 +58,10 @@ <!-- This file lives in public/404.html --> <div class="dialog"> <div> - <h1>The page you were looking for doesn't exist.</h1> - <p>You may have mistyped the address or the page may have moved.</p> + <h1>The page you were looking for doesn't exist.</h1> + <p>You may have mistyped the address or the page may have moved.</p> </div> - <p>If you are the application owner check the logs for more information.</p> + <p>If you are the application owner check the logs for more information.</p> </div> </body> </html> diff --git a/railties/lib/rails/generators/rails/app/templates/public/422.html b/railties/lib/rails/generators/rails/app/templates/public/422.html index ee18eeb10c..a21f82b3bd 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/422.html +++ b/railties/lib/rails/generators/rails/app/templates/public/422.html @@ -58,10 +58,10 @@ <!-- This file lives in public/422.html --> <div class="dialog"> <div> - <h1>The change you wanted was rejected.</h1> - <p>Maybe you tried to change something you didn't have access to.</p> + <h1>The change you wanted was rejected.</h1> + <p>Maybe you tried to change something you didn't have access to.</p> </div> - <p>If you are the application owner check the logs for more information.</p> + <p>If you are the application owner check the logs for more information.</p> </div> </body> </html> diff --git a/railties/lib/rails/generators/rails/app/templates/public/500.html b/railties/lib/rails/generators/rails/app/templates/public/500.html index e4161c3ce5..061abc587d 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/500.html +++ b/railties/lib/rails/generators/rails/app/templates/public/500.html @@ -58,9 +58,9 @@ <!-- This file lives in public/500.html --> <div class="dialog"> <div> - <h1>We're sorry, but something went wrong.</h1> + <h1>We're sorry, but something went wrong.</h1> </div> - <p>If you are the application owner check the logs for more information.</p> + <p>If you are the application owner check the logs for more information.</p> </div> </body> </html> diff --git a/railties/lib/rails/generators/rails/app/templates/public/robots.txt b/railties/lib/rails/generators/rails/app/templates/public/robots.txt index 1a3a5e4dd2..3c9c7c01f3 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/robots.txt +++ b/railties/lib/rails/generators/rails/app/templates/public/robots.txt @@ -1,4 +1,4 @@ -# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file +# See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file # # To ban all spiders from the entire site uncomment the next two lines: # User-agent: * diff --git a/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb index 4fd060341e..6b011e577a 100644 --- a/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb +++ b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb @@ -1,11 +1,9 @@ -ENV["RAILS_ENV"] ||= "test" +ENV['RAILS_ENV'] ||= 'test' require File.expand_path('../../config/environment', __FILE__) require 'rails/test_help' class ActiveSupport::TestCase <% unless options[:skip_active_record] -%> - ActiveRecord::Migration.check_pending! - # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. # # Note: You'll currently still have to declare fixtures explicitly in integration tests diff --git a/railties/lib/rails/generators/rails/controller/controller_generator.rb b/railties/lib/rails/generators/rails/controller/controller_generator.rb index ef84447df9..7588a558e7 100644 --- a/railties/lib/rails/generators/rails/controller/controller_generator.rb +++ b/railties/lib/rails/generators/rails/controller/controller_generator.rb @@ -23,21 +23,21 @@ module Rails # Will generate - # namespace :foo do # namespace :bar do - # get "baz/index" + # get 'baz/index' # end # end def generate_routing_code(action) - depth = class_path.length + depth = regular_class_path.length # Create 'namespace' ladder # namespace :foo do # namespace :bar do - namespace_ladder = class_path.each_with_index.map do |ns, i| + namespace_ladder = regular_class_path.each_with_index.map do |ns, i| indent("namespace :#{ns} do\n", i * 2) end.join # Create route - # get "baz/index" - route = indent(%{get "#{file_name}/#{action}"\n}, depth * 2) + # get 'baz/index' + route = indent(%{get '#{file_name}/#{action}'\n}, depth * 2) # Create `end` ladder # end diff --git a/railties/lib/rails/generators/rails/model/model_generator.rb b/railties/lib/rails/generators/rails/model/model_generator.rb index ea3d69d7c9..87bab129bb 100644 --- a/railties/lib/rails/generators/rails/model/model_generator.rb +++ b/railties/lib/rails/generators/rails/model/model_generator.rb @@ -1,6 +1,10 @@ +require 'rails/generators/model_helpers' + module Rails module Generators class ModelGenerator < NamedBase # :nodoc: + include Rails::Generators::ModelHelpers + argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]" hook_for :orm, required: true end diff --git a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb index dbe1e37d8e..f6f529b80a 100644 --- a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb +++ b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb @@ -185,7 +185,6 @@ task default: :test end public_task :set_default_accessors! - public_task :apply_rails_template public_task :create_root def create_root_files @@ -242,6 +241,7 @@ task default: :test build(:leftovers) end + public_task :apply_rails_template, :run_bundle def name @name ||= begin @@ -255,9 +255,6 @@ task default: :test end end - public_task :run_bundle - public_task :replay_template - protected def app_templates_dir diff --git a/railties/lib/rails/generators/rails/plugin/templates/Gemfile b/railties/lib/rails/generators/rails/plugin/templates/Gemfile index d576784415..f0a832f783 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/Gemfile +++ b/railties/lib/rails/generators/rails/plugin/templates/Gemfile @@ -29,15 +29,15 @@ end # <%= gem.comment %> <% end -%> -<%= gem.commented_out ? '# ' : '' %>gem '<%= gem.name %>'<% if gem.version -%> -, '<%= gem.version %>' -<% elsif gem.options.any? -%> +<%= gem.commented_out ? '# ' : '' %>gem '<%= gem.name %>'<%= %(, '#{gem.version}') if gem.version -%> +<% if gem.options.any? -%> ,<%= gem.padding(max_width) %><%= gem.options.map { |k,v| "#{k}: #{v.inspect}" }.join(', ') %> -<% else %> <% end -%> <% end -%> <% end -%> +<% unless defined?(JRUBY_VERSION) -%> # To use debugger # gem 'debugger' +<% end -%> 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 c8de9f3e0f..c3314d7e68 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt @@ -3,5 +3,9 @@ ENGINE_ROOT = File.expand_path('../..', __FILE__) ENGINE_PATH = File.expand_path('../../lib/<%= name -%>/engine', __FILE__) +# Set up gems listed in the Gemfile. +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) +require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) + require 'rails/all' require 'rails/engine/commands' 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 a0e5553e44..e4a2bc2b0f 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 @@ -9,7 +9,7 @@ module Rails # should give you # # namespace :admin do - # namespace :users + # namespace :users do # resources :products # 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 0e69aa101f..2c3b04043f 100644 --- a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb +++ b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb @@ -31,7 +31,7 @@ class <%= controller_class_name %>Controller < ApplicationController if @<%= orm_instance.save %> redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully created.'" %> else - render action: 'new' + render :new end end @@ -40,7 +40,7 @@ class <%= controller_class_name %>Controller < ApplicationController if @<%= orm_instance.update("#{singular_table_name}_params") %> redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully updated.'" %> else - render action: 'edit' + render :edit end end diff --git a/railties/lib/rails/generators/resource_helpers.rb b/railties/lib/rails/generators/resource_helpers.rb index a01eb57651..4669935156 100644 --- a/railties/lib/rails/generators/resource_helpers.rb +++ b/railties/lib/rails/generators/resource_helpers.rb @@ -1,35 +1,24 @@ require 'rails/generators/active_model' +require 'rails/generators/model_helpers' module Rails module Generators # Deal with controller names on scaffold and add some helpers to deal with # ActiveModel. module ResourceHelpers # :nodoc: - mattr_accessor :skip_warn def self.included(base) #:nodoc: - base.class_option :force_plural, type: :boolean, desc: "Forces the use of a plural ModelName" + base.send :include, Rails::Generators::ModelHelpers base.class_option :model_name, type: :string, desc: "ModelName to be used" end # Set controller variables on initialization. def initialize(*args) #:nodoc: super + controller_name = name if options[:model_name] - controller_name = name self.name = options[:model_name] assign_names!(self.name) - else - controller_name = name - end - - if name == name.pluralize && name.singularize != name.pluralize && !options[:force_plural] - unless ResourceHelpers.skip_warn - say "Plural version of the model detected, using singularized version. Override with --force-plural." - ResourceHelpers.skip_warn = true - end - name.replace name.singularize - assign_names!(name) end assign_controller_names!(controller_name.pluralize) 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 3334b189bf..85dee1a066 100644 --- a/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb +++ b/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb @@ -4,11 +4,18 @@ module TestUnit # :nodoc: module Generators # :nodoc: class MailerGenerator < Base # :nodoc: argument :actions, type: :array, default: [], banner: "method method" - check_class_collision suffix: "Test" + + def check_class_collision + class_collisions "#{class_name}Test", "#{class_name}Preview" + end def create_test_files template "functional_test.rb", File.join('test/mailers', class_path, "#{file_name}_test.rb") end + + def create_preview_files + template "preview.rb", File.join('test/mailers/previews', class_path, "#{file_name}_preview.rb") + end end end end diff --git a/railties/lib/rails/generators/test_unit/mailer/templates/preview.rb b/railties/lib/rails/generators/test_unit/mailer/templates/preview.rb new file mode 100644 index 0000000000..3bfd5426e8 --- /dev/null +++ b/railties/lib/rails/generators/test_unit/mailer/templates/preview.rb @@ -0,0 +1,13 @@ +<% module_namespacing do -%> +# Preview all emails at http://localhost:3000/rails/mailers/<%= file_path %> +class <%= class_name %>Preview < ActionMailer::Preview +<% actions.each do |action| -%> + + # Preview this email at http://localhost:3000/rails/mailers/<%= file_path %>/<%= action %> + def <%= action %> + <%= class_name %>.<%= action %> + end +<% end -%> + +end +<% end -%> diff --git a/railties/lib/rails/info.rb b/railties/lib/rails/info.rb index edadeaca0e..9502876ebb 100644 --- a/railties/lib/rails/info.rb +++ b/railties/lib/rails/info.rb @@ -23,7 +23,7 @@ module Rails end def frameworks - %w( active_record action_pack action_view action_mailer active_support ) + %w( active_record action_pack action_view action_mailer active_support active_model ) end def framework_version(framework) diff --git a/railties/lib/rails/info_controller.rb b/railties/lib/rails/info_controller.rb index fa5668a5b5..908c4ce65e 100644 --- a/railties/lib/rails/info_controller.rb +++ b/railties/lib/rails/info_controller.rb @@ -1,9 +1,9 @@ +require 'rails/application_controller' require 'action_dispatch/routing/inspector' -class Rails::InfoController < ActionController::Base # :nodoc: - self.view_paths = File.expand_path('../templates', __FILE__) +class Rails::InfoController < Rails::ApplicationController # :nodoc: prepend_view_path ActionDispatch::DebugExceptions::RESCUES_TEMPLATE_PATH - layout -> { request.xhr? ? nil : 'application' } + layout -> { request.xhr? ? false : 'application' } before_filter :require_local! @@ -13,21 +13,11 @@ class Rails::InfoController < ActionController::Base # :nodoc: def properties @info = Rails::Info.to_html + @page_title = 'Properties' end def routes @routes_inspector = ActionDispatch::Routing::RoutesInspector.new(_routes.routes) - end - - protected - - def require_local! - unless local_request? - render text: '<p>For security purposes, this information is only available to local requests.</p>', status: :forbidden - end - end - - def local_request? - Rails.application.config.consider_all_requests_local || request.local? + @page_title = 'Routes' end end diff --git a/railties/lib/rails/mailers_controller.rb b/railties/lib/rails/mailers_controller.rb new file mode 100644 index 0000000000..dd318f52e5 --- /dev/null +++ b/railties/lib/rails/mailers_controller.rb @@ -0,0 +1,73 @@ +require 'rails/application_controller' + +class Rails::MailersController < Rails::ApplicationController # :nodoc: + prepend_view_path ActionDispatch::DebugExceptions::RESCUES_TEMPLATE_PATH + + before_filter :require_local! + before_filter :find_preview, only: :preview + + def index + @previews = ActionMailer::Preview.all + @page_title = "Mailer Previews" + end + + def preview + if params[:path] == @preview.preview_name + @page_title = "Mailer Previews for #{@preview.preview_name}" + render action: 'mailer' + else + email = File.basename(params[:path]) + + if @preview.email_exists?(email) + @email = @preview.call(email) + + 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 + else + raise AbstractController::ActionNotFound, "Email part '#{part_type}' not found in #{@preview.name}##{email}" + end + else + @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}" + end + end + end + + protected + def find_preview + candidates = [] + params[:path].to_s.scan(%r{/|$}){ candidates << $` } + preview = candidates.detect{ |candidate| ActionMailer::Preview.exists?(candidate) } + + if preview + @preview = ActionMailer::Preview.find(preview) + else + raise AbstractController::ActionNotFound, "Mailer preview '#{params[:path]}' not found" + end + 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 } + end + else + @email + end + end + + def find_part(format) + if @email.multipart? + @email.parts.find{ |p| p.mime_type == format } + elsif @email.mime_type == format + @email + end + end +end
\ No newline at end of file diff --git a/railties/lib/rails/paths.rb b/railties/lib/rails/paths.rb index f512aefb23..3eb66c07af 100644 --- a/railties/lib/rails/paths.rb +++ b/railties/lib/rails/paths.rb @@ -24,7 +24,7 @@ module Rails # # Notice that when you add a path using +add+, the path object created already # contains the path with the same path value given to +add+. In some situations, - # you may not want this behavior, so you can give :with as option. + # you may not want this behavior, so you can give <tt>:with</tt> as option. # # root.add "config/routes", with: "config/routes.rb" # root["config/routes"].inspect # => ["config/routes.rb"] @@ -101,7 +101,7 @@ module Rails def filter_by(&block) all_paths.find_all(&block).flat_map { |path| paths = path.existent - paths - path.children.map { |p| yield(p) ? [] : p.existent }.flatten + paths - path.children.flat_map { |p| yield(p) ? [] : p.existent } }.uniq end end diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb index 89ca8cbe11..2b33beaa2b 100644 --- a/railties/lib/rails/railtie.rb +++ b/railties/lib/rails/railtie.rb @@ -22,7 +22,7 @@ module Rails # # * creating initializers # * configuring a Rails framework for the application, like setting a generator - # * +adding config.*+ keys to the environment + # * adding <tt>config.*</tt> keys to the environment # * setting up a subscriber with ActiveSupport::Notifications # * adding rake tasks # @@ -63,8 +63,8 @@ module Rails # end # end # - # Finally, you can also pass :before and :after as option to initializer, in case - # you want to couple it with a specific step in the initialization process. + # Finally, you can also pass <tt>:before</tt> and <tt>:after</tt> as option to initializer, + # in case you want to couple it with a specific step in the initialization process. # # == Configuration # @@ -183,8 +183,8 @@ module Rails end protected - def generate_railtie_name(class_or_module) - ActiveSupport::Inflector.underscore(class_or_module).tr("/", "_") + def generate_railtie_name(string) + ActiveSupport::Inflector.underscore(string).tr("/", "_") end # If the class method does not have a method, then send the method call @@ -221,26 +221,28 @@ module Rails protected def run_console_blocks(app) #:nodoc: - self.class.console.each { |block| block.call(app) } + each_registered_block(:console) { |block| block.call(app) } end def run_generators_blocks(app) #:nodoc: - self.class.generators.each { |block| block.call(app) } + each_registered_block(:generators) { |block| block.call(app) } end def run_runner_blocks(app) #:nodoc: - self.class.runner.each { |block| block.call(app) } + each_registered_block(:runner) { |block| block.call(app) } end def run_tasks_blocks(app) #:nodoc: extend Rake::DSL - self.class.rake_tasks.each { |block| instance_exec(app, &block) } + each_registered_block(:rake_tasks) { |block| instance_exec(app, &block) } + end - # Load also tasks from all superclasses - klass = self.class.superclass + private - while klass.respond_to?(:rake_tasks) - klass.rake_tasks.each { |t| instance_exec(app, &t) } + def each_registered_block(type, &block) + klass = self.class + while klass.respond_to?(type) + klass.public_send(type).each(&block) klass = klass.superclass end end diff --git a/railties/lib/rails/source_annotation_extractor.rb b/railties/lib/rails/source_annotation_extractor.rb index b806b922b7..201532d299 100644 --- a/railties/lib/rails/source_annotation_extractor.rb +++ b/railties/lib/rails/source_annotation_extractor.rb @@ -18,6 +18,20 @@ class SourceAnnotationExtractor @@directories ||= %w(app config db lib test) + (ENV['SOURCE_ANNOTATION_DIRECTORIES'] || '').split(',') end + def self.extensions + @@extensions ||= {} + end + + # Registers new Annotations File Extensions + # SourceAnnotationExtractor::Annotation.register_extensions("css", "scss", "sass", "less", "js") { |tag| /\/\/\s*(#{tag}):?\s*(.*)$/ } + def self.register_extensions(*exts, &block) + extensions[/\.(#{exts.join("|")})$/] = block + end + + register_extensions("builder", "rb", "rake", "yml", "yaml", "ruby") { |tag| /#\s*(#{tag}):?\s*(.*)$/ } + register_extensions("css", "js") { |tag| /\/\/\s*(#{tag}):?\s*(.*)$/ } + register_extensions("erb") { |tag| /<%\s*#\s*(#{tag}):?\s*(.*?)\s*%>/ } + # Returns a representation of the annotation that looks like this: # # [126] [TODO] This algorithm is simple and clearly correct, make it faster. @@ -67,7 +81,7 @@ class SourceAnnotationExtractor # Returns a hash that maps filenames under +dir+ (recursively) to arrays # with their annotations. Only files with annotations are included. Files # with extension +.builder+, +.rb+, +.erb+, +.haml+, +.slim+, +.css+, - # +.scss+, +.js+, +.coffee+, and +.rake+ + # +.scss+, +.js+, +.coffee+, +.rake+, +.sass+ and +.less+ # are taken into account. def find_in(dir) results = {} @@ -78,21 +92,14 @@ class SourceAnnotationExtractor if File.directory?(item) results.update(find_in(item)) else - pattern = - case item - when /\.(builder|rb|coffee|rake)$/ - /#\s*(#{tag}):?\s*(.*)$/ - when /\.(css|scss|sass|less|js)$/ - /\/\/\s*(#{tag}):?\s*(.*)$/ - when /\.erb$/ - /<%\s*#\s*(#{tag}):?\s*(.*?)\s*%>/ - when /\.haml$/ - /-\s*#\s*(#{tag}):?\s*(.*)$/ - when /\.slim$/ - /\/\s*\s*(#{tag}):?\s*(.*)$/ - else nil - end - results.update(extract_annotations_from(item, pattern)) if pattern + extension = Annotation.extensions.detect do |regexp, _block| + regexp.match(item) + end + + if extension + pattern = extension.last.call(tag) + results.update(extract_annotations_from(item, pattern)) if pattern + end end end @@ -115,7 +122,7 @@ class SourceAnnotationExtractor # Prints the mapping from filenames to annotations in +results+ ordered by filename. # The +options+ hash is passed to each annotation's +to_s+. def display(results, options={}) - options[:indent] = results.map { |f, a| a.map(&:line) }.flatten.max.to_s.size + options[:indent] = results.flat_map { |f, a| a.map(&:line) }.max.to_s.size results.keys.sort.each do |file| puts "#{file}:" results[file].each do |note| diff --git a/railties/lib/rails/tasks/framework.rake b/railties/lib/rails/tasks/framework.rake index e669315934..3c8f8c6b87 100644 --- a/railties/lib/rails/tasks/framework.rake +++ b/railties/lib/rails/tasks/framework.rake @@ -3,7 +3,7 @@ namespace :rails do task update: [ "update:configs", "update:bin" ] desc "Applies the template supplied by LOCATION=(/path/to/template) or URL" - task :template do + task template: :environment do template = ENV["LOCATION"] raise "No LOCATION value given. Please set LOCATION either as path to a file or a URL" if template.blank? template = File.expand_path(template) if template !~ %r{\A[A-Za-z][A-Za-z0-9+\-\.]*://} diff --git a/railties/lib/rails/templates/layouts/application.html.erb b/railties/lib/rails/templates/layouts/application.html.erb index 7352d48e7b..5aecaa712a 100644 --- a/railties/lib/rails/templates/layouts/application.html.erb +++ b/railties/lib/rails/templates/layouts/application.html.erb @@ -2,7 +2,7 @@ <html lang="en"> <head> <meta charset="utf-8" /> - <title>Routes</title> + <title><%= @page_title %></title> <style> body { background-color: #fff; color: #333; } @@ -29,7 +29,7 @@ </style> </head> <body> -<h2>Your App: <%= link_to 'properties', '/rails/info/properties' %> | <%= link_to 'routes', '/rails/info/routes' %></h2> + <%= yield %> </body> diff --git a/railties/lib/rails/templates/rails/mailers/email.html.erb b/railties/lib/rails/templates/rails/mailers/email.html.erb new file mode 100644 index 0000000000..977feb922b --- /dev/null +++ b/railties/lib/rails/templates/rails/mailers/email.html.erb @@ -0,0 +1,98 @@ +<!DOCTYPE html> +<html><head> +<meta name="viewport" content="width=device-width" /> +<style type="text/css"> + header { + width: 100%; + padding: 10px 0 0 0; + margin: 0; + background: white; + font: 12px "Lucida Grande", sans-serif; + border-bottom: 1px solid #dedede; + overflow: hidden; + } + + dl { + margin: 0 0 10px 0; + padding: 0; + } + + dt { + width: 80px; + padding: 1px; + float: left; + clear: left; + text-align: right; + color: #7f7f7f; + } + + dd { + margin-left: 90px; /* 80px + 10px */ + padding: 1px; + } + + iframe { + border: 0; + width: 100%; + height: 800px; + } +</style> +</head> + +<body> +<header> + <dl> + <% if @email.respond_to?(:smtp_envelope_from) && Array(@email.from) != Array(@email.smtp_envelope_from) %> + <dt>SMTP-From:</dt> + <dd><%= @email.smtp_envelope_from %></dd> + <% end %> + + <% if @email.respond_to?(:smtp_envelope_to) && @email.to != @email.smtp_envelope_to %> + <dt>SMTP-To:</dt> + <dd><%= @email.smtp_envelope_to %></dd> + <% end %> + + <dt>From:</dt> + <dd><%= @email.header['from'] %></dd> + + <% if @email.reply_to %> + <dt>Reply-To:</dt> + <dd><%= @email.header['reply-to'] %></dd> + <% end %> + + <dt>To:</dt> + <dd><%= @email.header['to'] %></dd> + + <% if @email.cc %> + <dt>CC:</dt> + <dd><%= @email.header['cc'] %></dd> + <% end %> + + <dt>Date:</dt> + <dd><%= Time.current.rfc2822 %></dd> + + <dt>Subject:</dt> + <dd><strong><%= @email.subject %></strong></dd> + + <% 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 %> + </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> + </dd> + <% end %> + </dl> +</header> + +<iframe seamless name="messageBody" src="?part=<%= Rack::Utils.escape(@part.mime_type) %>"></iframe> + +</body> +</html>
\ No newline at end of file diff --git a/railties/lib/rails/templates/rails/mailers/index.html.erb b/railties/lib/rails/templates/rails/mailers/index.html.erb new file mode 100644 index 0000000000..c4c9757d57 --- /dev/null +++ b/railties/lib/rails/templates/rails/mailers/index.html.erb @@ -0,0 +1,8 @@ +<% @previews.each do |preview| %> +<h3><%= link_to preview.preview_name.titleize, "/rails/mailers/#{preview.preview_name}" %></h3> +<ul> +<% preview.emails.each do |email| %> +<li><%= link_to email, "/rails/mailers/#{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 new file mode 100644 index 0000000000..607c8d1677 --- /dev/null +++ b/railties/lib/rails/templates/rails/mailers/mailer.html.erb @@ -0,0 +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> +<% end %> +</ul> diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb index be801befc2..c837fadb40 100644 --- a/railties/lib/rails/test_help.rb +++ b/railties/lib/rails/test_help.rb @@ -4,6 +4,7 @@ abort("Abort testing: Your Rails environment is running in production mode!") if require 'active_support/testing/autorun' require 'active_support/test_case' +require 'action_controller' require 'action_controller/test_case' require 'action_dispatch/testing/integration' require 'rails/generators/test_case' @@ -11,10 +12,12 @@ require 'rails/generators/test_case' # Config Rails backtrace in tests. require 'rails/backtrace_cleaner' if ENV["BACKTRACE"].nil? - MiniTest.backtrace_filter = Rails.backtrace_cleaner + Minitest.backtrace_filter = Rails.backtrace_cleaner end if defined?(ActiveRecord::Base) + ActiveRecord::Migration.maintain_test_schema! + class ActiveSupport::TestCase include ActiveRecord::TestFixtures self.fixture_path = "#{Rails.root}/test/fixtures/" diff --git a/railties/lib/rails/test_unit/railtie.rb b/railties/lib/rails/test_unit/railtie.rb index 75180ff978..878b9b7930 100644 --- a/railties/lib/rails/test_unit/railtie.rb +++ b/railties/lib/rails/test_unit/railtie.rb @@ -1,4 +1,4 @@ -if defined?(Rake.application) && Rake.application.top_level_tasks.grep(/^(default$|test(:|$))/).any? +if defined?(Rake.application) && Rake.application.top_level_tasks.grep(/^test(?::|$)/).any? ENV['RAILS_ENV'] ||= 'test' end diff --git a/railties/lib/rails/test_unit/testing.rake b/railties/lib/rails/test_unit/testing.rake index 38107e77b2..285e2ce846 100644 --- a/railties/lib/rails/test_unit/testing.rake +++ b/railties/lib/rails/test_unit/testing.rake @@ -1,4 +1,3 @@ -require 'rbconfig' require 'rake/testtask' require 'rails/test_unit/sub_test_task' diff --git a/railties/lib/rails/version.rb b/railties/lib/rails/version.rb index 5a6d8d0983..df351c4238 100644 --- a/railties/lib/rails/version.rb +++ b/railties/lib/rails/version.rb @@ -1,10 +1,8 @@ -module Rails - module VERSION - MAJOR = 4 - MINOR = 1 - TINY = 0 - PRE = "beta" +require_relative 'gem_version' - STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") +module Rails + # Returns the version of the currently loaded Rails as a string. + def self.version + VERSION::STRING end end diff --git a/railties/lib/rails/welcome_controller.rb b/railties/lib/rails/welcome_controller.rb index 45b764fa6b..de9cd18b01 100644 --- a/railties/lib/rails/welcome_controller.rb +++ b/railties/lib/rails/welcome_controller.rb @@ -1,6 +1,7 @@ -class Rails::WelcomeController < ActionController::Base # :nodoc: - self.view_paths = File.expand_path('../templates', __FILE__) - layout nil +require 'rails/application_controller' + +class Rails::WelcomeController < Rails::ApplicationController # :nodoc: + layout false def index end diff --git a/railties/test/abstract_unit.rb b/railties/test/abstract_unit.rb index 643cc6b0ee..9ccc286b4e 100644 --- a/railties/test/abstract_unit.rb +++ b/railties/test/abstract_unit.rb @@ -14,6 +14,15 @@ require 'rails/all' module TestApp class Application < Rails::Application config.root = File.dirname(__FILE__) - config.secret_key_base = 'b3c631c314c0bbca50c1b2843150fe33' + secrets.secret_key_base = 'b3c631c314c0bbca50c1b2843150fe33' end end + +# Skips the current run on Rubinius using Minitest::Assertions#skip +def rubinius_skip(message = '') + skip message if RUBY_ENGINE == 'rbx' +end +# Skips the current run on JRuby using Minitest::Assertions#skip +def jruby_skip(message = '') + skip message if defined?(JRUBY_VERSION) +end diff --git a/railties/test/app_rails_loader_test.rb b/railties/test/app_rails_loader_test.rb index 92cb3233d8..1d3b80253a 100644 --- a/railties/test/app_rails_loader_test.rb +++ b/railties/test/app_rails_loader_test.rb @@ -22,8 +22,14 @@ class AppRailsLoaderTest < ActiveSupport::TestCase exe = "#{script_dir}/rails" test "is not in a Rails application if #{exe} is not found in the current or parent directories" do - File.stubs(:exist?).with('bin/rails').returns(false) - File.stubs(:exist?).with('script/rails').returns(false) + File.stubs(:file?).with('bin/rails').returns(false) + File.stubs(:file?).with('script/rails').returns(false) + + assert !Rails::AppRailsLoader.exec_app_rails + end + + test "is not in a Rails application if #{exe} exists but is a folder" do + FileUtils.mkdir_p(exe) assert !Rails::AppRailsLoader.exec_app_rails end diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb index b235b51d90..51f55a560f 100644 --- a/railties/test/application/assets_test.rb +++ b/railties/test/application/assets_test.rb @@ -199,6 +199,7 @@ module ApplicationTests end test "precompile creates a manifest file with all the assets listed" do + app_file "app/assets/images/rails.png", "notactuallyapng" app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>" app_file "app/assets/javascripts/application.js", "alert();" # digest is default in false, we must enable it for test environment @@ -260,7 +261,7 @@ module ApplicationTests test "precompile shouldn't use the digests present in manifest.json" do app_file "app/assets/images/rails.png", "notactuallyapng" - app_file "app/assets/stylesheets/application.css.erb", "//= depend_on rails.png\np { url: <%= asset_path('rails.png') %> }" + app_file "app/assets/stylesheets/application.css.erb", "p { url: <%= asset_path('rails.png') %> }" ENV["RAILS_ENV"] = "production" precompile! @@ -448,23 +449,23 @@ module ApplicationTests test "asset urls should be protocol-relative if no request is in scope" do app_file "app/assets/images/rails.png", "notreallyapng" - app_file "app/assets/javascripts/image_loader.js.erb", 'var src="<%= image_path("rails.png") %>";' + app_file "app/assets/javascripts/image_loader.js.erb", "var src='<%= image_path('rails.png') %>';" add_to_config "config.assets.precompile = %w{image_loader.js}" add_to_config "config.asset_host = 'example.com'" precompile! - assert_match 'src="//example.com/assets/rails.png"', File.read(Dir["#{app_path}/public/assets/image_loader-*.js"].first) + assert_match "src='//example.com/assets/rails.png'", File.read(Dir["#{app_path}/public/assets/image_loader-*.js"].first) end test "asset paths should use RAILS_RELATIVE_URL_ROOT by default" do ENV["RAILS_RELATIVE_URL_ROOT"] = "/sub/uri" app_file "app/assets/images/rails.png", "notreallyapng" - app_file "app/assets/javascripts/app.js.erb", 'var src="<%= image_path("rails.png") %>";' + app_file "app/assets/javascripts/app.js.erb", "var src='<%= image_path('rails.png') %>';" add_to_config "config.assets.precompile = %w{app.js}" precompile! - assert_match 'src="/sub/uri/assets/rails.png"', File.read(Dir["#{app_path}/public/assets/app-*.js"].first) + assert_match "src='/sub/uri/assets/rails.png'", File.read(Dir["#{app_path}/public/assets/app-*.js"].first) end test "assets:cache:clean should clean cache" do diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index 03a735b1c1..b11fd55170 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -250,7 +250,7 @@ module ApplicationTests test "Use key_generator when secret_key_base is set" do make_basic_app do |app| - app.config.secret_key_base = 'b3c631c314c0bbca50c1b2843150fe33' + app.secrets.secret_key_base = 'b3c631c314c0bbca50c1b2843150fe33' app.config.session_store :disabled end @@ -268,6 +268,82 @@ module ApplicationTests assert_equal 'some_value', verifier.verify(last_response.body) end + test "application verifier can be used in the entire application" do + make_basic_app do |app| + app.secrets.secret_key_base = 'b3c631c314c0bbca50c1b2843150fe33' + app.config.session_store :disabled + end + + message = app.message_verifier(:sensitive_value).generate("some_value") + + assert_equal 'some_value', Rails.application.message_verifier(:sensitive_value).verify(message) + + secret = app.key_generator.generate_key('sensitive_value') + verifier = ActiveSupport::MessageVerifier.new(secret) + assert_equal 'some_value', verifier.verify(message) + end + + test "application verifier can build different verifiers" do + make_basic_app do |app| + app.secrets.secret_key_base = 'b3c631c314c0bbca50c1b2843150fe33' + app.config.session_store :disabled + end + + default_verifier = app.message_verifier(:sensitive_value) + text_verifier = app.message_verifier(:text) + + message = text_verifier.generate('some_value') + + assert_equal 'some_value', text_verifier.verify(message) + assert_raises ActiveSupport::MessageVerifier::InvalidSignature do + default_verifier.verify(message) + end + + assert_equal default_verifier.object_id, app.message_verifier(:sensitive_value).object_id + assert_not_equal default_verifier.object_id, text_verifier.object_id + end + + test "secrets.secret_key_base is used when config/secrets.yml is present" do + app_file 'config/secrets.yml', <<-YAML + development: + secret_key_base: 3b7cd727ee24e8444053437c36cc66c3 + YAML + + require "#{app_path}/config/environment" + assert_equal '3b7cd727ee24e8444053437c36cc66c3', app.secrets.secret_key_base + end + + test "secret_key_base is copied from config to secrets when not set" do + remove_file "config/secrets.yml" + app_file 'config/initializers/secret_token.rb', <<-RUBY + Rails.application.config.secret_key_base = "3b7cd727ee24e8444053437c36cc66c3" + RUBY + + require "#{app_path}/config/environment" + assert_equal '3b7cd727ee24e8444053437c36cc66c3', app.secrets.secret_key_base + end + + test "custom secrets saved in config/secrets.yml are loaded in app secrets" do + app_file 'config/secrets.yml', <<-YAML + development: + secret_key_base: 3b7cd727ee24e8444053437c36cc66c3 + aws_access_key_id: myamazonaccesskeyid + aws_secret_access_key: myamazonsecretaccesskey + YAML + + require "#{app_path}/config/environment" + assert_equal 'myamazonaccesskeyid', app.secrets.aws_access_key_id + assert_equal 'myamazonsecretaccesskey', app.secrets.aws_secret_access_key + end + + test "blank config/secrets.yml does not crash the loading process" do + app_file 'config/secrets.yml', <<-YAML + YAML + require "#{app_path}/config/environment" + + assert_nil app.secrets.not_defined + end + test "protect from forgery is the default in a new app" do make_basic_app @@ -459,7 +535,7 @@ module ApplicationTests require "#{app_path}/config/environment" require 'action_view/base' - assert ActionView::Resolver.caching? + assert_equal true, ActionView::Resolver.caching? end test "config.action_view.cache_template_loading without cache_classes default" do @@ -467,7 +543,7 @@ module ApplicationTests require "#{app_path}/config/environment" require 'action_view/base' - assert !ActionView::Resolver.caching? + assert_equal false, ActionView::Resolver.caching? end test "config.action_view.cache_template_loading = false" do @@ -478,7 +554,7 @@ module ApplicationTests require "#{app_path}/config/environment" require 'action_view/base' - assert !ActionView::Resolver.caching? + assert_equal false, ActionView::Resolver.caching? end test "config.action_view.cache_template_loading = true" do @@ -489,7 +565,21 @@ module ApplicationTests require "#{app_path}/config/environment" require 'action_view/base' - assert ActionView::Resolver.caching? + assert_equal true, ActionView::Resolver.caching? + end + + test "config.action_view.cache_template_loading with cache_classes in an environment" do + build_app(initializers: true) + add_to_env_config "development", "config.cache_classes = false" + + # These requires are to emulate an engine loading Action View before the application + require 'action_view' + require 'action_view/railtie' + require 'action_view/base' + + require "#{app_path}/config/environment" + + assert_equal false, ActionView::Resolver.caching? end test "config.action_dispatch.show_exceptions is sent in env" do @@ -686,5 +776,32 @@ module ApplicationTests assert_not Rails.configuration.respond_to?(:method_missing) assert Rails.configuration.respond_to?(:method_missing, true) end + + test "config.active_record.dump_schema_after_migration is false on production" do + build_app + ENV["RAILS_ENV"] = "production" + + require "#{app_path}/config/environment" + + assert_not ActiveRecord::Base.dump_schema_after_migration + end + + test "config.active_record.dump_schema_after_migration is true by default on development" do + ENV["RAILS_ENV"] = "development" + + require "#{app_path}/config/environment" + + assert ActiveRecord::Base.dump_schema_after_migration + end + + test "config.annotations wrapping SourceAnnotationExtractor::Annotation class" do + make_basic_app do |app| + app.config.annotations.register_extensions("coffee") do |tag| + /#\s*(#{tag}):?\s*(.*)$/ + end + end + + assert_not_nil SourceAnnotationExtractor::Annotation.extensions[/\.(coffee)$/] + end end end diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb index 83104acf3c..8e76bf27f3 100644 --- a/railties/test/application/initializers/frameworks_test.rb +++ b/railties/test/application/initializers/frameworks_test.rb @@ -217,7 +217,7 @@ module ApplicationTests orig_database_url = ENV.delete("DATABASE_URL") orig_rails_env, Rails.env = Rails.env, 'development' database_url_db_name = "db/database_url_db.sqlite3" - ENV["DATABASE_URL"] = "sqlite3://:@localhost/#{database_url_db_name}" + ENV["DATABASE_URL"] = "sqlite3:#{database_url_db_name}" ActiveRecord::Base.establish_connection assert ActiveRecord::Base.connection assert_match(/#{database_url_db_name}/, ActiveRecord::Base.connection_config[:database]) diff --git a/railties/test/application/initializers/i18n_test.rb b/railties/test/application/initializers/i18n_test.rb index 97df073ec7..bc34897cdf 100644 --- a/railties/test/application/initializers/i18n_test.rb +++ b/railties/test/application/initializers/i18n_test.rb @@ -183,5 +183,50 @@ en: load_app assert_fallbacks ca: [:ca, :"es-ES", :es, :'en-US', :en] end + + test "config.i18n.enforce_available_locales is set to true by default and avoids I18n warnings" do + add_to_config <<-RUBY + config.i18n.default_locale = :it + RUBY + + output = capture(:stderr) { load_app } + assert_no_match %r{deprecated.*enforce_available_locales}, output + assert_equal true, I18n.enforce_available_locales + + assert_raise I18n::InvalidLocale do + I18n.locale = :es + end + end + + test "disable config.i18n.enforce_available_locales" do + add_to_config <<-RUBY + config.i18n.enforce_available_locales = false + config.i18n.default_locale = :fr + RUBY + + output = capture(:stderr) { load_app } + assert_no_match %r{deprecated.*enforce_available_locales}, output + assert_equal false, I18n.enforce_available_locales + + assert_nothing_raised do + I18n.locale = :es + end + end + + test "default config.i18n.enforce_available_locales does not override I18n.enforce_available_locales" do + I18n.enforce_available_locales = false + + add_to_config <<-RUBY + config.i18n.default_locale = :fr + RUBY + + output = capture(:stderr) { load_app } + assert_no_match %r{deprecated.*enforce_available_locales}, output + assert_equal false, I18n.enforce_available_locales + + assert_nothing_raised do + I18n.locale = :es + end + end end end diff --git a/railties/test/application/mailer_previews_test.rb b/railties/test/application/mailer_previews_test.rb new file mode 100644 index 0000000000..c588fd7012 --- /dev/null +++ b/railties/test/application/mailer_previews_test.rb @@ -0,0 +1,428 @@ +require 'isolation/abstract_unit' +require 'rack/test' +module ApplicationTests + class MailerPreviewsTest < ActiveSupport::TestCase + include ActiveSupport::Testing::Isolation + include Rack::Test::Methods + + def setup + build_app + boot_rails + end + + def teardown + teardown_app + end + + test "/rails/mailers is accessible in development" do + app("development") + get "/rails/mailers" + assert_equal 200, last_response.status + end + + test "/rails/mailers is not accessible in production" do + app("production") + get "/rails/mailers" + assert_equal 404, last_response.status + end + + test "mailer previews are loaded from the default preview_path" do + mailer 'notifier', <<-RUBY + class Notifier < ActionMailer::Base + default from: "from@example.com" + + def foo + mail to: "to@example.org" + end + end + RUBY + + text_template 'notifier/foo', <<-RUBY + Hello, World! + RUBY + + mailer_preview 'notifier', <<-RUBY + class NotifierPreview < ActionMailer::Preview + def foo + Notifier.foo + end + end + RUBY + + app('development') + + get "/rails/mailers" + assert_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body + assert_match '<li><a href="/rails/mailers/notifier/foo">foo</a></li>', last_response.body + end + + test "mailer previews are loaded from a custom preview_path" do + add_to_config "config.action_mailer.preview_path = '#{app_path}/lib/mailer_previews'" + + mailer 'notifier', <<-RUBY + class Notifier < ActionMailer::Base + default from: "from@example.com" + + def foo + mail to: "to@example.org" + end + end + RUBY + + text_template 'notifier/foo', <<-RUBY + Hello, World! + RUBY + + app_file 'lib/mailer_previews/notifier_preview.rb', <<-RUBY + class NotifierPreview < ActionMailer::Preview + def foo + Notifier.foo + end + end + RUBY + + app('development') + + get "/rails/mailers" + assert_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body + assert_match '<li><a href="/rails/mailers/notifier/foo">foo</a></li>', last_response.body + end + + test "mailer previews are reloaded across requests" do + app('development') + + get "/rails/mailers" + assert_no_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body + + mailer 'notifier', <<-RUBY + class Notifier < ActionMailer::Base + default from: "from@example.com" + + def foo + mail to: "to@example.org" + end + end + RUBY + + text_template 'notifier/foo', <<-RUBY + Hello, World! + RUBY + + mailer_preview 'notifier', <<-RUBY + class NotifierPreview < ActionMailer::Preview + def foo + Notifier.foo + end + end + RUBY + + get "/rails/mailers" + assert_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body + + remove_file 'test/mailers/previews/notifier_preview.rb' + sleep(1) + + get "/rails/mailers" + assert_no_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body + end + + test "mailer preview actions are added and removed" do + mailer 'notifier', <<-RUBY + class Notifier < ActionMailer::Base + default from: "from@example.com" + + def foo + mail to: "to@example.org" + end + end + RUBY + + text_template 'notifier/foo', <<-RUBY + Hello, World! + RUBY + + mailer_preview 'notifier', <<-RUBY + class NotifierPreview < ActionMailer::Preview + def foo + Notifier.foo + end + end + RUBY + + app('development') + + get "/rails/mailers" + assert_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body + assert_match '<li><a href="/rails/mailers/notifier/foo">foo</a></li>', last_response.body + assert_no_match '<li><a href="/rails/mailers/notifier/bar">bar</a></li>', last_response.body + + mailer 'notifier', <<-RUBY + class Notifier < ActionMailer::Base + default from: "from@example.com" + + def foo + mail to: "to@example.org" + end + + def bar + mail to: "to@example.net" + end + end + RUBY + + text_template 'notifier/foo', <<-RUBY + Hello, World! + RUBY + + text_template 'notifier/bar', <<-RUBY + Goodbye, World! + RUBY + + mailer_preview 'notifier', <<-RUBY + class NotifierPreview < ActionMailer::Preview + def foo + Notifier.foo + end + + def bar + Notifier.bar + end + end + RUBY + + sleep(1) + + get "/rails/mailers" + assert_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body + assert_match '<li><a href="/rails/mailers/notifier/foo">foo</a></li>', last_response.body + assert_match '<li><a href="/rails/mailers/notifier/bar">bar</a></li>', last_response.body + + mailer 'notifier', <<-RUBY + class Notifier < ActionMailer::Base + default from: "from@example.com" + + def foo + mail to: "to@example.org" + end + end + RUBY + + remove_file 'app/views/notifier/bar.text.erb' + + mailer_preview 'notifier', <<-RUBY + class NotifierPreview < ActionMailer::Preview + def foo + Notifier.foo + end + end + RUBY + + sleep(1) + + get "/rails/mailers" + assert_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body + assert_match '<li><a href="/rails/mailers/notifier/foo">foo</a></li>', last_response.body + assert_no_match '<li><a href="/rails/mailers/notifier/bar">bar</a></li>', last_response.body + end + + test "mailer previews are reloaded from a custom preview_path" do + add_to_config "config.action_mailer.preview_path = '#{app_path}/lib/mailer_previews'" + + app('development') + + get "/rails/mailers" + assert_no_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body + + mailer 'notifier', <<-RUBY + class Notifier < ActionMailer::Base + default from: "from@example.com" + + def foo + mail to: "to@example.org" + end + end + RUBY + + text_template 'notifier/foo', <<-RUBY + Hello, World! + RUBY + + app_file 'lib/mailer_previews/notifier_preview.rb', <<-RUBY + class NotifierPreview < ActionMailer::Preview + def foo + Notifier.foo + end + end + RUBY + + get "/rails/mailers" + assert_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body + + remove_file 'lib/mailer_previews/notifier_preview.rb' + sleep(1) + + get "/rails/mailers" + assert_no_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body + end + + test "mailer preview not found" do + app('development') + get "/rails/mailers/notifier" + assert last_response.not_found? + assert_match "Mailer preview 'notifier' not found", last_response.body + end + + test "mailer preview email not found" do + mailer 'notifier', <<-RUBY + class Notifier < ActionMailer::Base + default from: "from@example.com" + + def foo + mail to: "to@example.org" + end + end + RUBY + + text_template 'notifier/foo', <<-RUBY + Hello, World! + RUBY + + mailer_preview 'notifier', <<-RUBY + class NotifierPreview < ActionMailer::Preview + def foo + Notifier.foo + end + end + RUBY + + app('development') + + get "/rails/mailers/notifier/bar" + assert last_response.not_found? + assert_match "Email 'bar' not found in NotifierPreview", last_response.body + end + + test "mailer preview email part not found" do + mailer 'notifier', <<-RUBY + class Notifier < ActionMailer::Base + default from: "from@example.com" + + def foo + mail to: "to@example.org" + end + end + RUBY + + text_template 'notifier/foo', <<-RUBY + Hello, World! + RUBY + + mailer_preview 'notifier', <<-RUBY + class NotifierPreview < ActionMailer::Preview + def foo + Notifier.foo + end + end + RUBY + + app('development') + + get "/rails/mailers/notifier/foo?part=text%2Fhtml" + assert last_response.not_found? + assert_match "Email part 'text/html' not found in NotifierPreview#foo", last_response.body + end + + test "message header uses full display names" do + mailer 'notifier', <<-RUBY + class Notifier < ActionMailer::Base + default from: "Ruby on Rails <core@rubyonrails.org>" + + def foo + mail to: "Andrew White <andyw@pixeltrix.co.uk>", + cc: "David Heinemeier Hansson <david@heinemeierhansson.com>" + end + end + RUBY + + text_template 'notifier/foo', <<-RUBY + Hello, World! + RUBY + + mailer_preview 'notifier', <<-RUBY + class NotifierPreview < ActionMailer::Preview + def foo + Notifier.foo + end + end + RUBY + + app('development') + + get "/rails/mailers/notifier/foo" + assert_equal 200, last_response.status + assert_match "Ruby on Rails <core@rubyonrails.org>", last_response.body + assert_match "Andrew White <andyw@pixeltrix.co.uk>", last_response.body + assert_match "David Heinemeier Hansson <david@heinemeierhansson.com>", last_response.body + end + + test "part menu selects correct option" do + mailer 'notifier', <<-RUBY + class Notifier < ActionMailer::Base + default from: "from@example.com" + + def foo + mail to: "to@example.org" + end + end + RUBY + + html_template 'notifier/foo', <<-RUBY + <p>Hello, World!</p> + RUBY + + text_template 'notifier/foo', <<-RUBY + Hello, World! + RUBY + + mailer_preview 'notifier', <<-RUBY + class NotifierPreview < ActionMailer::Preview + def foo + Notifier.foo + end + end + RUBY + + app('development') + + get "/rails/mailers/notifier/foo.html" + assert_equal 200, last_response.status + assert_match '<option selected value="?part=text%2Fhtml">View as HTML email</option>', last_response.body + + get "/rails/mailers/notifier/foo.txt" + assert_equal 200, last_response.status + assert_match '<option selected value="?part=text%2Fplain">View as plain-text email</option>', last_response.body + end + + private + def build_app + super + app_file "config/routes.rb", "Rails.application.routes.draw do; end" + end + + def mailer(name, contents) + app_file("app/mailers/#{name}.rb", contents) + end + + def mailer_preview(name, contents) + app_file("test/mailers/previews/#{name}_preview.rb", contents) + end + + def html_template(name, contents) + app_file("app/views/#{name}.html.erb", contents) + end + + def text_template(name, contents) + app_file("app/views/#{name}.text.erb", contents) + end + end +end diff --git a/railties/test/application/middleware/exceptions_test.rb b/railties/test/application/middleware/exceptions_test.rb index 9145cb6936..42096cfec4 100644 --- a/railties/test/application/middleware/exceptions_test.rb +++ b/railties/test/application/middleware/exceptions_test.rb @@ -73,7 +73,7 @@ module ApplicationTests assert_nothing_raised(ActionController::RoutingError) do get '/foo' - assert_match "The page you were looking for doesn't exist.", last_response.body + assert_match "The page you were looking for doesn't exist.", last_response.body end end diff --git a/railties/test/application/middleware/session_test.rb b/railties/test/application/middleware/session_test.rb index 14a56176f5..31a64c2f5a 100644 --- a/railties/test/application/middleware/session_test.rb +++ b/railties/test/application/middleware/session_test.rb @@ -318,7 +318,7 @@ module ApplicationTests add_to_config <<-RUBY config.secret_token = "3b7cd727ee24e8444053437c36cc66c4" - config.secret_key_base = nil + secrets.secret_key_base = nil RUBY require "#{app_path}/config/environment" diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb index 20d1d76d78..1557b90d27 100644 --- a/railties/test/application/middleware_test.rb +++ b/railties/test/application/middleware_test.rb @@ -61,7 +61,7 @@ module ApplicationTests boot! - assert_equal "Rack::Cache", middleware.first + assert middleware.include?("Rack::Cache") end test "ActiveRecord::Migration::CheckPending is present when active_record.migration_error is set to :page_load" do diff --git a/railties/test/application/multiple_applications_test.rb b/railties/test/application/multiple_applications_test.rb index 5bfea599e0..42b319178d 100644 --- a/railties/test/application/multiple_applications_test.rb +++ b/railties/test/application/multiple_applications_test.rb @@ -21,6 +21,12 @@ module ApplicationTests assert_equal Rails.application.config.secret_key_base, clone.config.secret_key_base, "The base secret key on the config should be the same" end + def test_inheriting_multiple_times_from_application + new_application_class = Class.new(Rails::Application) + + assert_not_equal Rails.application.object_id, new_application_class.instance.object_id + end + def test_initialization_of_multiple_copies_of_same_application application1 = AppTemplate::Application.new application2 = AppTemplate::Application.new diff --git a/railties/test/application/rake/dbs_test.rb b/railties/test/application/rake/dbs_test.rb index 4d348c6b4b..15414db00f 100644 --- a/railties/test/application/rake/dbs_test.rb +++ b/railties/test/application/rake/dbs_test.rb @@ -1,4 +1,5 @@ require "isolation/abstract_unit" +require "active_support/core_ext/string/strip" module ApplicationTests module RakeTests @@ -20,62 +21,53 @@ module ApplicationTests end def set_database_url - ENV['DATABASE_URL'] = "sqlite3://:@localhost/#{database_url_db_name}" + ENV['DATABASE_URL'] = "sqlite3:#{database_url_db_name}" # ensure it's using the DATABASE_URL FileUtils.rm_rf("#{app_path}/config/database.yml") end - def expected - @expected ||= {} - end - - def db_create_and_drop + def db_create_and_drop(expected_database) Dir.chdir(app_path) do output = `bundle exec rake db:create` - assert_equal output, "" - assert File.exist?(expected[:database]) - assert_equal expected[:database], - ActiveRecord::Base.connection_config[:database] + assert_empty output + assert File.exist?(expected_database) + assert_equal expected_database, ActiveRecord::Base.connection_config[:database] output = `bundle exec rake db:drop` - assert_equal output, "" - assert !File.exist?(expected[:database]) + assert_empty output + assert !File.exist?(expected_database) end end test 'db:create and db:drop without database url' do require "#{app_path}/config/environment" - expected[:database] = ActiveRecord::Base.configurations[Rails.env]['database'] - db_create_and_drop - end + db_create_and_drop ActiveRecord::Base.configurations[Rails.env]['database'] + end test 'db:create and db:drop with database url' do require "#{app_path}/config/environment" set_database_url - expected[:database] = database_url_db_name - db_create_and_drop + db_create_and_drop database_url_db_name end - def db_migrate_and_status + def db_migrate_and_status(expected_database) Dir.chdir(app_path) do `rails generate model book title:string; bundle exec rake db:migrate` output = `bundle exec rake db:migrate:status` - assert_match(/database:\s+\S+#{expected[:database]}/, output) + assert_match(%r{database:\s+\S*#{Regexp.escape(expected_database)}}, output) assert_match(/up\s+\d{14}\s+Create books/, output) end end test 'db:migrate and db:migrate:status without database_url' do require "#{app_path}/config/environment" - expected[:database] = ActiveRecord::Base.configurations[Rails.env]['database'] - db_migrate_and_status + db_migrate_and_status ActiveRecord::Base.configurations[Rails.env]['database'] end test 'db:migrate and db:migrate:status with database_url' do require "#{app_path}/config/environment" set_database_url - expected[:database] = database_url_db_name - db_migrate_and_status + db_migrate_and_status database_url_db_name end def db_schema_dump @@ -96,12 +88,11 @@ module ApplicationTests db_schema_dump end - def db_fixtures_load + def db_fixtures_load(expected_database) Dir.chdir(app_path) do `rails generate model book title:string; bundle exec rake db:migrate db:fixtures:load` - assert_match(/#{expected[:database]}/, - ActiveRecord::Base.connection_config[:database]) + assert_match expected_database, ActiveRecord::Base.connection_config[:database] require "#{app_path}/app/models/book" assert_equal 2, Book.count end @@ -109,43 +100,50 @@ module ApplicationTests test 'db:fixtures:load without database_url' do require "#{app_path}/config/environment" - expected[:database] = ActiveRecord::Base.configurations[Rails.env]['database'] - db_fixtures_load + db_fixtures_load ActiveRecord::Base.configurations[Rails.env]['database'] end test 'db:fixtures:load with database_url' do require "#{app_path}/config/environment" set_database_url - expected[:database] = database_url_db_name - db_fixtures_load + db_fixtures_load database_url_db_name end - def db_structure_dump_and_load + def db_structure_dump_and_load(expected_database) Dir.chdir(app_path) do `rails generate model book title:string; bundle exec rake db:migrate db:structure:dump` structure_dump = File.read("db/structure.sql") assert_match(/CREATE TABLE \"books\"/, structure_dump) - `bundle exec rake db:drop db:structure:load` - assert_match(/#{expected[:database]}/, - ActiveRecord::Base.connection_config[:database]) + `bundle exec rake environment db:drop db:structure:load` + assert_match expected_database, ActiveRecord::Base.connection_config[:database] require "#{app_path}/app/models/book" #if structure is not loaded correctly, exception would be raised - assert Book.count, 0 + assert_equal 0, Book.count end end test 'db:structure:dump and db:structure:load without database_url' do require "#{app_path}/config/environment" - expected[:database] = ActiveRecord::Base.configurations[Rails.env]['database'] - db_structure_dump_and_load + db_structure_dump_and_load ActiveRecord::Base.configurations[Rails.env]['database'] end test 'db:structure:dump and db:structure:load with database_url' do require "#{app_path}/config/environment" set_database_url - expected[:database] = database_url_db_name - db_structure_dump_and_load + db_structure_dump_and_load database_url_db_name + end + + test 'db:structure:dump does not dump schema information when no migrations are used' do + Dir.chdir(app_path) do + # create table without migrations + `bundle exec rails runner 'ActiveRecord::Base.connection.create_table(:posts) {|t| t.string :title }'` + + stderr_output = capture(:stderr) { `bundle exec rake db:structure:dump` } + assert_empty stderr_output + structure_dump = File.read("db/structure.sql") + assert_match(/CREATE TABLE \"posts\"/, structure_dump) + end end def db_test_load_structure @@ -153,12 +151,12 @@ module ApplicationTests `rails generate model book title:string; bundle exec rake db:migrate db:structure:dump db:test:load_structure` ActiveRecord::Base.configurations = Rails.application.config.database_configuration - ActiveRecord::Base.establish_connection 'test' + ActiveRecord::Base.establish_connection :test require "#{app_path}/app/models/book" #if structure is not loaded correctly, exception would be raised - assert Book.count, 0 - assert_match(/#{ActiveRecord::Base.configurations['test']['database']}/, - ActiveRecord::Base.connection_config[:database]) + assert_equal 0, Book.count + assert_match ActiveRecord::Base.configurations['test']['database'], + ActiveRecord::Base.connection_config[:database] end end @@ -166,6 +164,15 @@ module ApplicationTests require "#{app_path}/config/environment" db_test_load_structure end + + test 'db:test deprecation' do + require "#{app_path}/config/environment" + Dir.chdir(app_path) do + output = `bundle exec rake db:migrate db:test:prepare 2>&1` + assert_equal "WARNING: db:test:prepare is deprecated. The Rails test helper now maintains " \ + "your test schema automatically, see the release notes for details.\n", output + end + end end end end diff --git a/railties/test/application/rake/migrations_test.rb b/railties/test/application/rake/migrations_test.rb index 33c753868c..b7fd5d02c5 100644 --- a/railties/test/application/rake/migrations_test.rb +++ b/railties/test/application/rake/migrations_test.rb @@ -153,6 +153,37 @@ module ApplicationTests assert_match(/up\s+\d{3,}\s+Add email to users/, output) end end + + test 'schema generation when dump_schema_after_migration is set' do + add_to_config('config.active_record.dump_schema_after_migration = false') + + Dir.chdir(app_path) do + `rails generate model book title:string; + bundle exec rake db:migrate` + + assert !File.exist?("db/schema.rb") + end + + add_to_config('config.active_record.dump_schema_after_migration = true') + + Dir.chdir(app_path) do + `rails generate model author name:string; + bundle exec rake db:migrate` + + structure_dump = File.read("db/schema.rb") + assert_match(/create_table "authors"/, structure_dump) + end + end + + test 'default schema generation after migration' do + Dir.chdir(app_path) do + `rails generate model book title:string; + bundle exec rake db:migrate` + + structure_dump = File.read("db/schema.rb") + assert_match(/create_table "books"/, structure_dump) + end + end end end end diff --git a/railties/test/application/rake/notes_test.rb b/railties/test/application/rake/notes_test.rb index 01d751e822..95087bf29f 100644 --- a/railties/test/application/rake/notes_test.rb +++ b/railties/test/application/rake/notes_test.rb @@ -1,4 +1,5 @@ require "isolation/abstract_unit" +require 'rails/source_annotation_extractor' module ApplicationTests module RakeTests @@ -18,46 +19,27 @@ module ApplicationTests test 'notes finds notes for certain file_types' do app_file "app/views/home/index.html.erb", "<% # TODO: note in erb %>" - app_file "app/views/home/index.html.haml", "-# TODO: note in haml" - app_file "app/views/home/index.html.slim", "/ TODO: note in slim" - app_file "app/assets/javascripts/application.js.coffee", "# TODO: note in coffee" app_file "app/assets/javascripts/application.js", "// TODO: note in js" app_file "app/assets/stylesheets/application.css", "// TODO: note in css" - app_file "app/assets/stylesheets/application.css.scss", "// TODO: note in scss" - app_file "app/assets/stylesheets/application.css.sass", "// TODO: note in sass" - app_file "app/assets/stylesheets/application.css.less", "// TODO: note in less" app_file "app/controllers/application_controller.rb", 1000.times.map { "" }.join("\n") << "# TODO: note in ruby" app_file "lib/tasks/task.rake", "# TODO: note in rake" + app_file 'app/views/home/index.html.builder', '# TODO: note in builder' + app_file 'config/locales/en.yml', '# TODO: note in yml' + app_file 'config/locales/en.yaml', '# TODO: note in yaml' + app_file "app/views/home/index.ruby", "# TODO: note in ruby" - boot_rails - require 'rake' - require 'rdoc/task' - require 'rake/testtask' - - Rails.application.load_tasks - - Dir.chdir(app_path) do - output = `bundle exec rake notes` - lines = output.scan(/\[([0-9\s]+)\](\s)/) - + run_rake_notes do |output, lines| assert_match(/note in erb/, output) - assert_match(/note in haml/, output) - assert_match(/note in slim/, output) - assert_match(/note in ruby/, output) - assert_match(/note in coffee/, output) assert_match(/note in js/, output) assert_match(/note in css/, output) - assert_match(/note in scss/, output) - assert_match(/note in sass/, output) - assert_match(/note in less/, output) assert_match(/note in rake/, output) + assert_match(/note in builder/, output) + assert_match(/note in yml/, output) + assert_match(/note in yaml/, output) + assert_match(/note in ruby/, output) - assert_equal 11, lines.size - - lines.each do |line| - assert_equal 4, line[0].size - assert_equal ' ', line[1] - end + assert_equal 9, lines.size + assert_equal [4], lines.map(&:size).uniq end end @@ -70,18 +52,7 @@ module ApplicationTests app_file "some_other_dir/blah.rb", "# TODO: note in some_other directory" - boot_rails - - require 'rake' - require 'rdoc/task' - require 'rake/testtask' - - Rails.application.load_tasks - - Dir.chdir(app_path) do - output = `bundle exec rake notes` - lines = output.scan(/\[([0-9\s]+)\]/).flatten - + run_rake_notes do |output, lines| assert_match(/note in app directory/, output) assert_match(/note in config directory/, output) assert_match(/note in db directory/, output) @@ -90,10 +61,7 @@ module ApplicationTests assert_no_match(/note in some_other directory/, output) assert_equal 5, lines.size - - lines.each do |line_number| - assert_equal 4, line_number.size - end + assert_equal [4], lines.map(&:size).uniq end end @@ -106,18 +74,7 @@ module ApplicationTests app_file "some_other_dir/blah.rb", "# TODO: note in some_other directory" - boot_rails - - require 'rake' - require 'rdoc/task' - require 'rake/testtask' - - Rails.application.load_tasks - - Dir.chdir(app_path) do - output = `SOURCE_ANNOTATION_DIRECTORIES='some_other_dir' bundle exec rake notes` - lines = output.scan(/\[([0-9\s]+)\]/).flatten - + run_rake_notes "SOURCE_ANNOTATION_DIRECTORIES='some_other_dir' bundle exec rake notes" do |output, lines| assert_match(/note in app directory/, output) assert_match(/note in config directory/, output) assert_match(/note in db directory/, output) @@ -127,10 +84,7 @@ module ApplicationTests assert_match(/note in some_other directory/, output) assert_equal 6, lines.size - - lines.each do |line_number| - assert_equal 4, line_number.size - end + assert_equal [4], lines.map(&:size).uniq end end @@ -148,32 +102,51 @@ module ApplicationTests end EOS - boot_rails - - require 'rake' - require 'rdoc/task' - require 'rake/testtask' - - Rails.application.load_tasks - - Dir.chdir(app_path) do - output = `bundle exec rake notes_custom` - lines = output.scan(/\[([0-9\s]+)\]/).flatten - + run_rake_notes "bundle exec rake notes_custom" do |output, lines| assert_match(/\[FIXME\] note in lib directory/, output) assert_match(/\[TODO\] note in test directory/, output) assert_no_match(/OPTIMIZE/, output) assert_no_match(/note in app directory/, output) assert_equal 2, lines.size + assert_equal [4], lines.map(&:size).uniq + end + end - lines.each do |line_number| - assert_equal 4, line_number.size - end + test 'register a new extension' do + add_to_config %q{ config.annotations.register_extensions("scss", "sass") { |annotation| /\/\/\s*(#{annotation}):?\s*(.*)$/ } } + app_file "app/assets/stylesheets/application.css.scss", "// TODO: note in scss" + app_file "app/assets/stylesheets/application.css.sass", "// TODO: note in sass" + + run_rake_notes do |output, lines| + assert_match(/note in scss/, output) + assert_match(/note in sass/, output) + assert_equal 2, lines.size end end private + + def run_rake_notes(command = 'bundle exec rake notes') + boot_rails + load_tasks + + Dir.chdir(app_path) do + output = `#{command}` + lines = output.scan(/\[([0-9\s]+)\]\s/).flatten + + yield output, lines + end + end + + def load_tasks + require 'rake' + require 'rdoc/task' + require 'rake/testtask' + + Rails.application.load_tasks + end + def boot_rails super require "#{app_path}/config/environment" diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb index 2169304aa4..e8c8de9f73 100644 --- a/railties/test/application/rake_test.rb +++ b/railties/test/application/rake_test.rb @@ -111,7 +111,7 @@ module ApplicationTests RUBY output = Dir.chdir(app_path){ `rake routes` } - assert_equal "Prefix Verb URI Pattern Controller#Action\ncart GET /cart(.:format) cart#show\n", output + assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output end def test_rake_routes_with_controller_environment @@ -124,7 +124,7 @@ module ApplicationTests ENV['CONTROLLER'] = 'cart' output = Dir.chdir(app_path){ `rake routes` } - assert_equal "Prefix Verb URI Pattern Controller#Action\ncart GET /cart(.:format) cart#show\n", output + assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output end def test_rake_routes_displays_message_when_no_routes_are_defined @@ -187,7 +187,7 @@ module ApplicationTests def test_scaffold_tests_pass_by_default output = Dir.chdir(app_path) do `rails generate scaffold user username:string password:string; - bundle exec rake db:migrate db:test:clone test` + bundle exec rake db:migrate test` end assert_match(/7 runs, 13 assertions, 0 failures, 0 errors/, output) @@ -197,7 +197,7 @@ module ApplicationTests def test_scaffold_with_references_columns_tests_pass_by_default output = Dir.chdir(app_path) do `rails generate scaffold LineItems product:references cart:belongs_to; - bundle exec rake db:migrate db:test:clone test` + bundle exec rake db:migrate test` end assert_match(/7 runs, 13 assertions, 0 failures, 0 errors/, output) @@ -208,7 +208,8 @@ module ApplicationTests add_to_config "config.active_record.schema_format = :sql" output = Dir.chdir(app_path) do `rails generate scaffold user username:string; - bundle exec rake db:migrate db:test:clone 2>&1 --trace` + bundle exec rake db:migrate; + bundle exec rake db:test:clone 2>&1 --trace` end assert_match(/Execute db:test:clone_structure/, output) end @@ -217,7 +218,8 @@ module ApplicationTests add_to_config "config.active_record.schema_format = :sql" output = Dir.chdir(app_path) do `rails generate scaffold user username:string; - bundle exec rake db:migrate db:test:prepare 2>&1 --trace` + bundle exec rake db:migrate; + bundle exec rake db:test:prepare 2>&1 --trace` end assert_match(/Execute db:test:load_structure/, output) end @@ -269,5 +271,16 @@ module ApplicationTests end end end + + def test_template_load_initializers + app_file "config/initializers/dummy.rb", "puts 'Hello, World!'" + app_file "template.rb", "" + + output = Dir.chdir(app_path) do + `bundle exec rake rails:template LOCATION=template.rb` + end + + assert_match(/Hello, World!/, output) + end end end diff --git a/railties/test/application/test_test.rb b/railties/test/application/test_test.rb index 6f2f328588..a223180169 100644 --- a/railties/test/application/test_test.rb +++ b/railties/test/application/test_test.rb @@ -67,10 +67,55 @@ module ApplicationTests assert_match %r{/app/test/unit/failing_test\.rb}, output end + test "migrations" do + output = script('generate model user name:string') + version = output.match(/(\d+)_create_users\.rb/)[1] + + app_file 'test/models/user_test.rb', <<-RUBY + require 'test_helper' + + class UserTest < ActiveSupport::TestCase + test "user" do + User.create! name: "Jon" + end + end + RUBY + app_file 'db/schema.rb', '' + + assert_unsuccessful_run "models/user_test.rb", "Migrations are pending" + + app_file 'db/schema.rb', <<-RUBY + ActiveRecord::Schema.define(version: #{version}) do + create_table :users do |t| + t.string :name + end + end + RUBY + + app_file 'config/initializers/disable_maintain_test_schema.rb', <<-RUBY + Rails.application.config.active_record.maintain_test_schema = false + RUBY + + assert_unsuccessful_run "models/user_test.rb", "Could not find table 'users'" + + File.delete "#{app_path}/config/initializers/disable_maintain_test_schema.rb" + + result = assert_successful_test_run('models/user_test.rb') + assert !result.include?("create_table(:users)") + end + private + def assert_unsuccessful_run(name, message) + result = run_test_file(name) + assert_not_equal 0, $?.to_i + assert result.include?(message) + result + end + def assert_successful_test_run(name) result = run_test_file(name) assert_equal 0, $?.to_i, result + result end def run_test_file(name, options = {}) @@ -83,7 +128,7 @@ module ApplicationTests env["RUBYLIB"] = $:.join(':') Dir.chdir(app_path) do - `#{env_string(env)} #{Gem.ruby} #{args.join(' ')}` + `#{env_string(env)} #{Gem.ruby} #{args.join(' ')} 2>&1` end end diff --git a/railties/test/commands/dbconsole_test.rb b/railties/test/commands/dbconsole_test.rb index edb92b3aa2..24db395e6e 100644 --- a/railties/test/commands/dbconsole_test.rb +++ b/railties/test/commands/dbconsole_test.rb @@ -2,29 +2,74 @@ require 'abstract_unit' require 'rails/commands/dbconsole' class Rails::DBConsoleTest < ActiveSupport::TestCase - def teardown - %w[PGUSER PGHOST PGPORT PGPASSWORD].each{|key| ENV.delete(key)} - end - def test_config - Rails::DBConsole.const_set(:APP_PATH, "erb") - - app_config({}) - capture_abort { Rails::DBConsole.new.config } - assert aborted - assert_match(/No database is configured for the environment '\w+'/, output) - app_config(test: "with_init") - assert_equal Rails::DBConsole.new.config, "with_init" - - app_db_file("test:\n without_init") - assert_equal Rails::DBConsole.new.config, "without_init" - - app_db_file("test:\n <%= Rails.something_app_specific %>") - assert_equal Rails::DBConsole.new.config, "with_init" + def setup + Rails::DBConsole.const_set('APP_PATH', 'rails/all') + end - app_db_file("test:\n\ninvalid") - assert_equal Rails::DBConsole.new.config, "with_init" + def teardown + Rails::DBConsole.send(:remove_const, 'APP_PATH') + %w[PGUSER PGHOST PGPORT PGPASSWORD DATABASE_URL].each{|key| ENV.delete(key)} + end + + def test_config_with_db_config_only + config_sample = { + "test"=> { + "adapter"=> "sqlite3", + "host"=> "localhost", + "port"=> "9000", + "database"=> "foo_test", + "user"=> "foo", + "password"=> "bar", + "pool"=> "5", + "timeout"=> "3000" + } + } + app_db_config(config_sample) + assert_equal Rails::DBConsole.new.config, config_sample["test"] + end + + def test_config_with_no_db_config + app_db_config(nil) + assert_raise(ActiveRecord::AdapterNotSpecified) { + Rails::DBConsole.new.config + } + end + + def test_config_with_database_url_only + ENV['DATABASE_URL'] = 'postgresql://foo:bar@localhost:9000/foo_test?pool=5&timeout=3000' + app_db_config(nil) + expected = { + "adapter" => "postgresql", + "host" => "localhost", + "port" => 9000, + "database" => "foo_test", + "username" => "foo", + "password" => "bar", + "pool" => "5", + "timeout" => "3000" + }.sort + assert_equal expected, Rails::DBConsole.new.config.sort + end + + def test_config_choose_database_url_if_exists + host = "database-url-host.com" + ENV['DATABASE_URL'] = "postgresql://foo:bar@#{host}:9000/foo_test?pool=5&timeout=3000" + sample_config = { + "test" => { + "adapter" => "postgresql", + "host" => "not-the-#{host}", + "port" => 9000, + "database" => "foo_test", + "username" => "foo", + "password" => "bar", + "pool" => "5", + "timeout" => "3000" + } + } + app_db_config(sample_config) + assert_equal host, Rails::DBConsole.new.config["host"] end def test_env @@ -177,6 +222,10 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase private + def app_db_config(results) + Rails.application.config.stubs(:database_configuration).returns(results || {}) + end + def dbconsole @dbconsole ||= Rails::DBConsole.new(nil) end @@ -197,11 +246,4 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase end end - def app_db_file(result) - IO.stubs(:read).with("config/database.yml").returns(result) - end - - def app_config(result) - Rails.application.config.stubs(:database_configuration).returns(result.stringify_keys) - end end diff --git a/railties/test/configuration/middleware_stack_proxy_test.rb b/railties/test/configuration/middleware_stack_proxy_test.rb index 2442cb995d..6f3e45f320 100644 --- a/railties/test/configuration/middleware_stack_proxy_test.rb +++ b/railties/test/configuration/middleware_stack_proxy_test.rb @@ -39,7 +39,7 @@ module Rails @stack.swap :foo @stack.delete :foo - mock = MiniTest::Mock.new + mock = Minitest::Mock.new mock.expect :send, nil, [:swap, :foo] mock.expect :send, nil, [:delete, :foo] @@ -50,7 +50,7 @@ module Rails private def assert_playback(msg_name, args) - mock = MiniTest::Mock.new + mock = Minitest::Mock.new mock.expect :send, nil, [msg_name, args] @stack.merge_into(mock) mock.verify diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index e6cda07ae5..8e1aeddb2b 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -29,6 +29,7 @@ DEFAULT_APP_FILES = %w( lib/tasks lib/assets log + test/test_helper.rb test/fixtures test/controllers test/models @@ -37,6 +38,8 @@ DEFAULT_APP_FILES = %w( test/integration vendor vendor/assets + vendor/assets/stylesheets + vendor/assets/javascripts tmp/cache tmp/cache/assets ) @@ -55,9 +58,10 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_assets run_generator - assert_file("app/views/layouts/application.html.erb", /stylesheet_link_tag\s+"application", media: "all", "data-turbolinks-track" => true/) - assert_file("app/views/layouts/application.html.erb", /javascript_include_tag\s+"application", "data-turbolinks-track" => true/) + assert_file("app/views/layouts/application.html.erb", /stylesheet_link_tag\s+'application', media: 'all', 'data-turbolinks-track' => true/) + assert_file("app/views/layouts/application.html.erb", /javascript_include_tag\s+'application', 'data-turbolinks-track' => true/) assert_file("app/assets/stylesheets/application.css") + assert_file("app/assets/javascripts/application.js") end def test_invalid_application_name_raises_an_error @@ -109,6 +113,9 @@ class AppGeneratorTest < Rails::Generators::TestCase FileUtils.mv(app_root, app_moved_root) + # make sure we are in correct dir + FileUtils.cd(app_moved_root) + generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: app_moved_root, shell: @shell generator.send(:app_const) @@ -156,52 +163,6 @@ class AppGeneratorTest < Rails::Generators::TestCase end end - def test_add_gemfile_entry - template = Tempfile.open 'my_template' - template.puts 'gemfile_entry "tenderlove"' - template.flush - - run_generator([destination_root, "-m", template.path]) - assert_file "Gemfile", /tenderlove/ - ensure - template.close - template.unlink - end - - def test_add_skip_entry - template = Tempfile.open 'my_template' - template.puts 'add_gem_entry_filter { |gem| gem.name != "jbuilder" }' - template.flush - - run_generator([destination_root, "-m", template.path]) - assert_file "Gemfile" do |contents| - assert_no_match 'jbuilder', contents - end - ensure - template.close - template.unlink - end - - def test_application_html_checks_gems - template = Tempfile.open 'my_template' - template.puts 'add_gem_entry_filter { |gem| gem.name != "turbolinks" }' - template.flush - - run_generator([destination_root, "-m", template.path]) - assert_file "Gemfile" do |contents| - assert_no_match 'turbolinks', contents - end - assert_file "Gemfile" do |contents| - assert_no_match 'turbolinks', contents - end - assert_file "app/views/layouts/application.html.erb" do |contents| - assert_no_match 'turbolinks', contents - end - ensure - template.close - template.unlink - end - def test_config_another_database run_generator([destination_root, "-d", "mysql"]) assert_file "config/database.yml", /mysql/ @@ -278,7 +239,6 @@ class AppGeneratorTest < Rails::Generators::TestCase run_generator [destination_root, "--skip-sprockets"] assert_file "config/application.rb" do |content| assert_match(/#\s+require\s+["']sprockets\/railtie["']/, content) - assert_match(/config\.assets\.enabled = false/, content) end assert_file "Gemfile" do |content| assert_no_match(/sass-rails/, content) @@ -305,40 +265,13 @@ class AppGeneratorTest < Rails::Generators::TestCase end end - def test_inclusion_of_plateform_dependent_gems - run_generator([destination_root]) - if RUBY_ENGINE == 'rbx' - assert_gem 'rubysl' - end - end - - def test_creation_of_a_test_directory - run_generator - assert_file 'test' - end - - def test_creation_of_app_assets_images_directory - run_generator - assert_file "app/assets/images" - end - - def test_creation_of_vendor_assets_javascripts_directory - run_generator - assert_file "vendor/assets/javascripts" - end - - def test_creation_of_vendor_assets_stylesheets_directory - run_generator - assert_file "vendor/assets/stylesheets" - end - def test_jquery_is_the_default_javascript_library run_generator assert_file "app/assets/javascripts/application.js" do |contents| assert_match %r{^//= require jquery}, contents assert_match %r{^//= require jquery_ujs}, contents end - assert_file "Gemfile", /^gem 'jquery-rails'/ + assert_gem "jquery-rails" end def test_other_javascript_libraries @@ -357,12 +290,13 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_no_file "vendor/assets/javascripts" assert_file "app/views/layouts/application.html.erb" do |contents| - assert_match(/stylesheet_link_tag\s+"application", media: "all" %>/, contents) - assert_no_match(/javascript_include_tag\s+"application" \%>/, contents) + assert_match(/stylesheet_link_tag\s+'application', media: 'all' %>/, contents) + assert_no_match(/javascript_include_tag\s+'application' \%>/, contents) end assert_file "Gemfile" do |content| assert_no_match(/coffee-rails/, content) + assert_no_match(/jquery-rails/, content) end end @@ -373,12 +307,18 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_inclusion_of_debugger run_generator - assert_file "Gemfile", /# gem 'debugger'/ + if defined?(JRUBY_VERSION) + assert_file "Gemfile" do |content| + assert_no_match(/debugger/, content) + end + else + assert_file "Gemfile", /# gem 'debugger'/ + end end - def test_inclusion_of_lazy_loaded_sdoc + def test_inclusion_of_doc run_generator - assert_file 'Gemfile', /gem 'sdoc', \s+group: :doc, require: false/ + assert_file 'Gemfile', /gem 'sdoc',\s+'~> 0.4.0',\s+group: :doc/ end def test_template_from_dir_pwd @@ -438,7 +378,61 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file "foo bar/config/initializers/session_store.rb", /key: '_foo_bar/ end -protected + def test_spring + run_generator + assert_file "Gemfile", /gem 'spring', \s+group: :development/ + end + + def test_spring_binstubs + jruby_skip "spring doesn't run on JRuby" + generator.stubs(:bundle_command).with('install') + generator.expects(:bundle_command).with('exec spring binstub --all').once + quietly { generator.invoke_all } + end + + def test_spring_no_fork + jruby_skip "spring doesn't run on JRuby" + Process.stubs(:respond_to?).with(:fork).returns(false) + run_generator + + assert_file "Gemfile" do |content| + assert_no_match(/spring/, content) + end + end + + def test_skip_spring + run_generator [destination_root, "--skip-spring"] + + assert_file "Gemfile" do |content| + assert_no_match(/spring/, content) + end + end + + def test_gitignore_when_sqlite3 + run_generator + + assert_file '.gitignore' do |content| + assert_match(/sqlite3/, content) + end + end + + def test_gitignore_when_no_active_record + run_generator [destination_root, '--skip-active-record'] + + assert_file '.gitignore' do |content| + assert_no_match(/sqlite/i, content) + end + end + + def test_gitignore_when_non_sqlite3_db + run_generator([destination_root, "-d", "mysql"]) + + assert_file '.gitignore' do |content| + assert_no_match(/sqlite/i, content) + end + end + + protected def action(*args, &block) silence(:stdout) { generator.send(*args, &block) } diff --git a/railties/test/generators/controller_generator_test.rb b/railties/test/generators/controller_generator_test.rb index 9c664a903a..4b2f8539d0 100644 --- a/railties/test/generators/controller_generator_test.rb +++ b/railties/test/generators/controller_generator_test.rb @@ -43,6 +43,12 @@ class ControllerGeneratorTest < Rails::Generators::TestCase assert_file "app/assets/stylesheets/account.css" end + def test_does_not_invoke_assets_if_required + run_generator ["account", "--skip-assets"] + assert_no_file "app/assets/javascripts/account.js" + assert_no_file "app/assets/stylesheets/account.css" + end + def test_invokes_default_test_framework run_generator assert_file "test/controllers/account_controller_test.rb" @@ -61,7 +67,7 @@ class ControllerGeneratorTest < Rails::Generators::TestCase def test_add_routes run_generator - assert_file "config/routes.rb", /get "account\/foo"/, /get "account\/bar"/ + assert_file "config/routes.rb", /get 'account\/foo'/, /get 'account\/bar'/ end def test_invokes_default_template_engine_even_with_no_action @@ -85,6 +91,6 @@ class ControllerGeneratorTest < Rails::Generators::TestCase def test_namespaced_routes_are_created_in_routes run_generator ["admin/dashboard", "index"] - assert_file "config/routes.rb", /namespace :admin do\n\s+get "dashboard\/index"\n/ + assert_file "config/routes.rb", /namespace :admin do\n\s+get 'dashboard\/index'\n/ end end diff --git a/railties/test/generators/create_migration_test.rb b/railties/test/generators/create_migration_test.rb new file mode 100644 index 0000000000..e16a77479a --- /dev/null +++ b/railties/test/generators/create_migration_test.rb @@ -0,0 +1,134 @@ +require 'generators/generators_test_helper' +require 'rails/generators/rails/migration/migration_generator' + +class CreateMigrationTest < Rails::Generators::TestCase + include GeneratorsTestHelper + + class Migrator < Rails::Generators::MigrationGenerator + include Rails::Generators::Migration + + def self.next_migration_number(dirname) + current_migration_number(dirname) + 1 + end + end + + tests Migrator + + def default_destination_path + "db/migrate/create_articles.rb" + end + + def create_migration(destination_path = default_destination_path, config = {}, generator_options = {}, &block) + migration_name = File.basename(destination_path, '.rb') + generator([migration_name], generator_options) + generator.set_migration_assigns!(destination_path) + + dir, base = File.split(destination_path) + timestamped_destination_path = File.join(dir, ["%migration_number%", base].join('_')) + + @migration = Rails::Generators::Actions::CreateMigration.new(generator, timestamped_destination_path, block || "contents", config) + end + + def migration_exists!(*args) + @existing_migration = create_migration(*args) + invoke! + @generator = nil + end + + def invoke! + capture(:stdout) { @migration.invoke! } + end + + def revoke! + capture(:stdout) { @migration.revoke! } + end + + def test_invoke + create_migration + + assert_match(/create db\/migrate\/1_create_articles.rb\n/, invoke!) + assert_file @migration.destination + end + + def test_invoke_pretended + create_migration(default_destination_path, {}, { pretend: true }) + + assert_no_file @migration.destination + end + + def test_invoke_when_exists + migration_exists! + create_migration + + assert_equal @existing_migration.destination, @migration.existing_migration + end + + def test_invoke_when_exists_identical + migration_exists! + create_migration + + assert_match(/identical db\/migrate\/1_create_articles.rb\n/, invoke!) + assert @migration.identical? + end + + def test_invoke_when_exists_not_identical + migration_exists! + create_migration { "different content" } + + assert_raise(Rails::Generators::Error) { invoke! } + end + + def test_invoke_forced_when_exists_not_identical + dest = "db/migrate/migration.rb" + migration_exists!(dest) + create_migration(dest, force: true) { "different content" } + + stdout = invoke! + assert_match(/remove db\/migrate\/1_migration.rb\n/, stdout) + assert_match(/create db\/migrate\/2_migration.rb\n/, stdout) + assert_file @migration.destination + assert_no_file @existing_migration.destination + end + + def test_invoke_forced_pretended_when_exists_not_identical + migration_exists! + create_migration(default_destination_path, { force: true }, { pretend: true }) do + "different content" + end + + stdout = invoke! + assert_match(/remove db\/migrate\/1_create_articles.rb\n/, stdout) + assert_match(/create db\/migrate\/2_create_articles.rb\n/, stdout) + assert_no_file @migration.destination + end + + def test_invoke_skipped_when_exists_not_identical + migration_exists! + create_migration(default_destination_path, {}, { skip: true }) { "different content" } + + assert_match(/skip db\/migrate\/2_create_articles.rb\n/, invoke!) + assert_no_file @migration.destination + end + + def test_revoke + migration_exists! + create_migration + + assert_match(/remove db\/migrate\/1_create_articles.rb\n/, revoke!) + assert_no_file @existing_migration.destination + end + + def test_revoke_pretended + migration_exists! + create_migration(default_destination_path, {}, { pretend: true }) + + assert_match(/remove db\/migrate\/1_create_articles.rb\n/, revoke!) + assert_file @existing_migration.destination + end + + def test_revoke_when_no_exists + create_migration + + assert_match(/remove db\/migrate\/1_create_articles.rb\n/, revoke!) + end +end diff --git a/railties/test/generators/generator_test.rb b/railties/test/generators/generator_test.rb index 94d2c1bf50..7871399dd7 100644 --- a/railties/test/generators/generator_test.rb +++ b/railties/test/generators/generator_test.rb @@ -1,7 +1,6 @@ require 'active_support/test_case' require 'active_support/testing/autorun' require 'rails/generators/app_base' -require 'rails/generators/rails/app/app_generator' module Rails module Generators diff --git a/railties/test/generators/generators_test_helper.rb b/railties/test/generators/generators_test_helper.rb index 32a3d072c9..77ec2f1c0c 100644 --- a/railties/test/generators/generators_test_helper.rb +++ b/railties/test/generators/generators_test_helper.rb @@ -1,10 +1,14 @@ require 'abstract_unit' +require 'active_support/core_ext/module/remove_method' require 'rails/generators' require 'rails/generators/test_case' module Rails - def self.root - @root ||= File.expand_path(File.join(File.dirname(__FILE__), '..', 'fixtures')) + class << self + remove_possible_method :root + def root + @root ||= File.expand_path(File.join(File.dirname(__FILE__), '..', 'fixtures')) + end end end Rails.application.config.root = Rails.root diff --git a/railties/test/generators/mailer_generator_test.rb b/railties/test/generators/mailer_generator_test.rb index 6b2351fc1a..25649881eb 100644 --- a/railties/test/generators/mailer_generator_test.rb +++ b/railties/test/generators/mailer_generator_test.rb @@ -1,7 +1,6 @@ require 'generators/generators_test_helper' require 'rails/generators/mailer/mailer_generator' - class MailerGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper arguments %w(notifier foo bar) @@ -23,8 +22,11 @@ class MailerGeneratorTest < Rails::Generators::TestCase end def test_check_class_collision - content = capture(:stderr){ run_generator ["object"] } - assert_match(/The name 'Object' is either already used in your application or reserved/, content) + Object.send :const_set, :Notifier, Class.new + content = capture(:stderr){ run_generator } + assert_match(/The name 'Notifier' is either already used in your application or reserved/, content) + ensure + Object.send :remove_const, :Notifier end def test_invokes_default_test_framework @@ -34,17 +36,58 @@ class MailerGeneratorTest < Rails::Generators::TestCase assert_match(/test "foo"/, test) assert_match(/test "bar"/, test) end + assert_file "test/mailers/previews/notifier_preview.rb" do |preview| + assert_match(/\# Preview all emails at http:\/\/localhost\:3000\/rails\/mailers\/notifier/, preview) + assert_match(/class NotifierPreview < ActionMailer::Preview/, preview) + assert_match(/\# Preview this email at http:\/\/localhost\:3000\/rails\/mailers\/notifier\/foo/, preview) + assert_instance_method :foo, preview do |foo| + assert_match(/Notifier.foo/, foo) + end + assert_match(/\# Preview this email at http:\/\/localhost\:3000\/rails\/mailers\/notifier\/bar/, preview) + assert_instance_method :bar, preview do |bar| + assert_match(/Notifier.bar/, bar) + end + end end - def test_invokes_default_template_engine + def test_check_test_class_collision + Object.send :const_set, :NotifierTest, Class.new + content = capture(:stderr){ run_generator } + assert_match(/The name 'NotifierTest' is either already used in your application or reserved/, content) + ensure + Object.send :remove_const, :NotifierTest + end + + def test_check_preview_class_collision + Object.send :const_set, :NotifierPreview, Class.new + content = capture(:stderr){ run_generator } + assert_match(/The name 'NotifierPreview' is either already used in your application or reserved/, content) + ensure + Object.send :remove_const, :NotifierPreview + end + + def test_invokes_default_text_template_engine run_generator assert_file "app/views/notifier/foo.text.erb" do |view| - assert_match(%r(app/views/notifier/foo\.text\.erb), view) + assert_match(%r(\sapp/views/notifier/foo\.text\.erb), view) assert_match(/<%= @greeting %>/, view) end assert_file "app/views/notifier/bar.text.erb" do |view| - assert_match(%r(app/views/notifier/bar\.text\.erb), view) + assert_match(%r(\sapp/views/notifier/bar\.text\.erb), view) + assert_match(/<%= @greeting %>/, view) + end + end + + def test_invokes_default_html_template_engine + run_generator + assert_file "app/views/notifier/foo.html.erb" do |view| + assert_match(%r(\sapp/views/notifier/foo\.html\.erb), view) + assert_match(/<%= @greeting %>/, view) + end + + assert_file "app/views/notifier/bar.html.erb" do |view| + assert_match(%r(\sapp/views/notifier/bar\.html\.erb), view) assert_match(/<%= @greeting %>/, view) end end @@ -65,7 +108,13 @@ class MailerGeneratorTest < Rails::Generators::TestCase assert_match(/class Farm::Animal < ActionMailer::Base/, mailer) assert_match(/en\.farm\.animal\.moos\.subject/, mailer) end + assert_file "test/mailers/previews/farm/animal_preview.rb" do |preview| + assert_match(/\# Preview all emails at http:\/\/localhost\:3000\/rails\/mailers\/farm\/animal/, preview) + assert_match(/class Farm::AnimalPreview < ActionMailer::Preview/, preview) + assert_match(/\# Preview this email at http:\/\/localhost\:3000\/rails\/mailers\/farm\/animal\/moos/, preview) + end assert_file "app/views/farm/animal/moos.text.erb" + assert_file "app/views/farm/animal/moos.html.erb" end def test_actions_are_turned_into_methods diff --git a/railties/test/generators/migration_generator_test.rb b/railties/test/generators/migration_generator_test.rb index d876597944..6fac643ed0 100644 --- a/railties/test/generators/migration_generator_test.rb +++ b/railties/test/generators/migration_generator_test.rb @@ -197,4 +197,54 @@ class MigrationGeneratorTest < Rails::Generators::TestCase def test_properly_identifies_usage_file assert generator_class.send(:usage_path) end + + def test_migration_with_singular_table_name + with_singular_table_name do + migration = "add_title_body_to_post" + run_generator [migration, 'title:string'] + assert_migration "db/migrate/#{migration}.rb" do |content| + assert_method :change, content do |change| + assert_match(/add_column :post, :title, :string/, change) + end + end + end + end + + def test_create_join_table_migration_with_singular_table_name + with_singular_table_name do + migration = "add_media_join_table" + run_generator [migration, "artist_id", "music:uniq"] + + assert_migration "db/migrate/#{migration}.rb" do |content| + assert_method :change, content do |change| + assert_match(/create_join_table :artist, :music/, change) + assert_match(/# t.index \[:artist_id, :music_id\]/, change) + assert_match(/ t.index \[:music_id, :artist_id\], unique: true/, change) + end + end + end + end + + def test_create_table_migration_with_singular_table_name + with_singular_table_name do + run_generator ["create_book", "title:string", "content:text"] + assert_migration "db/migrate/create_book.rb" do |content| + assert_method :change, content do |change| + assert_match(/create_table :book/, change) + assert_match(/ t\.string :title/, change) + assert_match(/ t\.text :content/, change) + end + end + end + end + + private + + def with_singular_table_name + old_state = ActiveRecord::Base.pluralize_table_names + ActiveRecord::Base.pluralize_table_names = false + yield + ensure + ActiveRecord::Base.pluralize_table_names = old_state + end end diff --git a/railties/test/generators/model_generator_test.rb b/railties/test/generators/model_generator_test.rb index 01ab77ee20..b67cf02d7b 100644 --- a/railties/test/generators/model_generator_test.rb +++ b/railties/test/generators/model_generator_test.rb @@ -34,6 +34,13 @@ class ModelGeneratorTest < Rails::Generators::TestCase assert_no_migration "db/migrate/create_accounts.rb" end + def test_plural_names_are_singularized + content = run_generator ["accounts".freeze] + assert_file "app/models/account.rb", /class Account < ActiveRecord::Base/ + assert_file "test/models/account_test.rb", /class AccountTest/ + assert_match(/\[WARNING\] The model name 'accounts' was recognized as a plural, using the singular 'account' instead\. Override with --force-plural or setup custom inflection rules for this noun before running the generator\./, content) + end + def test_model_with_underscored_parent_option run_generator ["account", "--parent", "admin/account"] assert_file "app/models/account.rb", /class Account < Admin::Account/ diff --git a/railties/test/generators/namespaced_generators_test.rb b/railties/test/generators/namespaced_generators_test.rb index e17925ff65..d677c21f15 100644 --- a/railties/test/generators/namespaced_generators_test.rb +++ b/railties/test/generators/namespaced_generators_test.rb @@ -63,7 +63,7 @@ class NamespacedControllerGeneratorTest < NamespacedGeneratorTestCase def test_routes_should_not_be_namespaced run_generator - assert_file "config/routes.rb", /get "account\/foo"/, /get "account\/bar"/ + assert_file "config/routes.rb", /get 'account\/foo'/, /get 'account\/bar'/ end def test_invokes_default_template_engine_even_with_no_action diff --git a/railties/test/generators/plugin_generator_test.rb b/railties/test/generators/plugin_generator_test.rb index 068eb66bc6..7a2701f813 100644 --- a/railties/test/generators/plugin_generator_test.rb +++ b/railties/test/generators/plugin_generator_test.rb @@ -35,6 +35,12 @@ class PluginGeneratorTest < Rails::Generators::TestCase content = capture(:stderr){ run_generator [File.join(destination_root, "43things")] } assert_equal "Invalid plugin name 43things. Please give a name which does not start with numbers.\n", content + + content = capture(:stderr){ run_generator [File.join(destination_root, "plugin")] } + assert_equal "Invalid plugin name plugin. Please give a name which does not match one of the reserved rails words.\n", content + + content = capture(:stderr){ run_generator [File.join(destination_root, "Digest")] } + assert_equal "Invalid plugin name Digest, constant Digest is already in use. Please choose another plugin name.\n", content end def test_camelcase_plugin_name_underscores_filenames @@ -58,6 +64,17 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_file "test/integration/navigation_test.rb", /ActionDispatch::IntegrationTest/ end + def test_inclusion_of_debugger + run_generator [destination_root, '--full'] + if defined?(JRUBY_VERSION) + assert_file "Gemfile" do |content| + assert_no_match(/debugger/, content) + end + else + assert_file "Gemfile", /# gem 'debugger'/ + end + end + def test_generating_test_files_in_full_mode_without_unit_test_files run_generator [destination_root, "-T", "--full"] @@ -139,7 +156,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_match(/bukkits/, contents) end assert_match(/run bundle install/, result) - assert_match(/Using bukkits \(0\.0\.1\)/, result) + assert_match(/Using bukkits \(?0\.0\.1\)?/, result) assert_match(/Your bundle is complete/, result) assert_equal 1, result.scan("Your bundle is complete").size end @@ -168,22 +185,22 @@ class PluginGeneratorTest < Rails::Generators::TestCase run_generator FileUtils.cd destination_root quietly { system 'bundle install' } - assert_match(/1 runs, 1 assertions, 0 failures, 0 errors/, `bundle exec rake test`) + assert_match(/1 runs, 1 assertions, 0 failures, 0 errors/, `bundle exec rake test 2>&1`) end def test_ensure_that_tests_works_in_full_mode run_generator [destination_root, "--full", "--skip_active_record"] FileUtils.cd destination_root quietly { system 'bundle install' } - assert_match(/1 runs, 1 assertions, 0 failures, 0 errors/, `bundle exec rake test`) + assert_match(/1 runs, 1 assertions, 0 failures, 0 errors/, `bundle exec rake test 2>&1`) end def test_ensure_that_migration_tasks_work_with_mountable_option run_generator [destination_root, "--mountable"] FileUtils.cd destination_root quietly { system 'bundle install' } - `bundle exec rake db:migrate` - assert_equal 0, $?.exitstatus + output = `bundle exec rake db:migrate 2>&1` + assert $?.success?, "Command failed: #{output}" end def test_creating_engine_in_full_mode @@ -293,7 +310,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_file "Gemfile" do |contents| assert_no_match('gemspec', contents) assert_match(/gem "rails", "~> #{Rails.version}"/, contents) - assert_match(/group :development do\n gem "sqlite3"\nend/, contents) + assert_match_sqlite3(contents) assert_no_match(/# gem "jquery-rails"/, contents) end end @@ -304,12 +321,12 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_file "Gemfile" do |contents| assert_no_match('gemspec', contents) assert_match(/gem "rails", "~> #{Rails.version}"/, contents) - assert_match(/group :development do\n gem "sqlite3"\nend/, contents) + assert_match_sqlite3(contents) end end def test_creating_plugin_in_app_directory_adds_gemfile_entry - # simulate application existance + # simulate application existence gemfile_path = "#{Rails.root}/Gemfile" Object.const_set('APP_PATH', Rails.root) FileUtils.touch gemfile_path @@ -323,7 +340,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase end def test_skipping_gemfile_entry - # simulate application existance + # simulate application existence gemfile_path = "#{Rails.root}/Gemfile" Object.const_set('APP_PATH', Rails.root) FileUtils.touch gemfile_path @@ -338,6 +355,18 @@ class PluginGeneratorTest < Rails::Generators::TestCase FileUtils.rm gemfile_path end + def test_generating_controller_inside_mountable_engine + run_generator [destination_root, "--mountable"] + + capture(:stdout) do + `#{destination_root}/bin/rails g controller admin/dashboard foo` + end + + assert_file "config/routes.rb" do |contents| + assert_match(/namespace :admin/, contents) + assert_no_match(/namespace :bukkit/, contents) + end + end protected def action(*args, &block) @@ -347,4 +376,12 @@ protected def default_files ::DEFAULT_PLUGIN_FILES end + + def assert_match_sqlite3(contents) + unless defined?(JRUBY_VERSION) + assert_match(/group :development do\n gem "sqlite3"\nend/, contents) + else + assert_match(/group :development do\n gem "activerecord-jdbcsqlite3-adapter"\nend/, contents) + end + end end diff --git a/railties/test/generators/resource_generator_test.rb b/railties/test/generators/resource_generator_test.rb index 3d4e694361..dcdff22152 100644 --- a/railties/test/generators/resource_generator_test.rb +++ b/railties/test/generators/resource_generator_test.rb @@ -63,19 +63,19 @@ class ResourceGeneratorTest < Rails::Generators::TestCase content = run_generator ["accounts".freeze] assert_file "app/models/account.rb", /class Account < ActiveRecord::Base/ assert_file "test/models/account_test.rb", /class AccountTest/ - assert_match(/Plural version of the model detected, using singularized version. Override with --force-plural./, content) + assert_match(/\[WARNING\] The model name 'accounts' was recognized as a plural, using the singular 'account' instead\. Override with --force-plural or setup custom inflection rules for this noun before running the generator\./, content) end def test_plural_names_can_be_forced content = run_generator ["accounts", "--force-plural"] assert_file "app/models/accounts.rb", /class Accounts < ActiveRecord::Base/ assert_file "test/models/accounts_test.rb", /class AccountsTest/ - assert_no_match(/Plural version of the model detected/, content) + assert_no_match(/\[WARNING\]/, content) end def test_mass_nouns_do_not_throw_warnings content = run_generator ["sheep".freeze] - assert_no_match(/Plural version of the model detected/, content) + assert_no_match(/\[WARNING\]/, content) end def test_route_is_removed_on_revoke diff --git a/railties/test/generators/scaffold_controller_generator_test.rb b/railties/test/generators/scaffold_controller_generator_test.rb index 26e56a162c..3c1123b53d 100644 --- a/railties/test/generators/scaffold_controller_generator_test.rb +++ b/railties/test/generators/scaffold_controller_generator_test.rb @@ -160,13 +160,6 @@ class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase Unknown::Generators.send :remove_const, :ActiveModel end - def test_new_hash_style - run_generator - assert_file "app/controllers/users_controller.rb" do |content| - assert_match(/render action: 'new'/, content) - end - end - def test_model_name_option run_generator ["Admin::User", "--model-name=User"] assert_file "app/controllers/admin/users_controller.rb" do |content| diff --git a/railties/test/generators/shared_generator_tests.rb b/railties/test/generators/shared_generator_tests.rb index 7184639d23..8e198d5fe1 100644 --- a/railties/test/generators/shared_generator_tests.rb +++ b/railties/test/generators/shared_generator_tests.rb @@ -26,11 +26,17 @@ module SharedGeneratorTests default_files.each { |path| assert_file path } end - def test_generation_runs_bundle_install - generator([destination_root]).expects(:bundle_command).with('install').once + def assert_generates_with_bundler(options = {}) + generator([destination_root], options) + generator.expects(:bundle_command).with('install').once + generator.stubs(:bundle_command).with('exec spring binstub --all') quietly { generator.invoke_all } end + def test_generation_runs_bundle_install + assert_generates_with_bundler + end + def test_plugin_new_generate_pretend run_generator ["testapp", "--pretend"] default_files.each{ |path| assert_no_file File.join("testapp",path) } @@ -96,15 +102,13 @@ module SharedGeneratorTests end def test_dev_option - generator([destination_root], dev: true).expects(:bundle_command).with('install').once - quietly { generator.invoke_all } + assert_generates_with_bundler dev: true rails_path = File.expand_path('../../..', Rails.root) assert_file 'Gemfile', /^gem\s+["']rails["'],\s+path:\s+["']#{Regexp.escape(rails_path)}["']$/ end def test_edge_option - generator([destination_root], edge: true).expects(:bundle_command).with('install').once - quietly { generator.invoke_all } + assert_generates_with_bundler edge: true assert_file 'Gemfile', %r{^gem\s+["']rails["'],\s+github:\s+["']#{Regexp.escape("rails/rails")}["']$} end diff --git a/railties/test/generators/task_generator_test.rb b/railties/test/generators/task_generator_test.rb index 9399be9510..d5bd44b9db 100644 --- a/railties/test/generators/task_generator_test.rb +++ b/railties/test/generators/task_generator_test.rb @@ -7,6 +7,18 @@ class TaskGeneratorTest < Rails::Generators::TestCase def test_task_is_created run_generator - assert_file "lib/tasks/feeds.rake", /namespace :feeds/ + assert_file "lib/tasks/feeds.rake" do |content| + assert_match(/namespace :feeds/, content) + assert_match(/task foo:/, content) + assert_match(/task bar:/, content) + end + end + + def test_task_on_revoke + task_path = 'lib/tasks/feeds.rake' + run_generator + assert_file task_path + run_generator ['feeds'], behavior: :revoke + assert_no_file task_path end end diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb index 913e2b5e29..6c50911666 100644 --- a/railties/test/isolation/abstract_unit.rb +++ b/railties/test/isolation/abstract_unit.rb @@ -93,7 +93,8 @@ module TestHelpers # Build an application by invoking the generator and going through the whole stack. def build_app(options = {}) @prev_rails_env = ENV['RAILS_ENV'] - ENV['RAILS_ENV'] = 'development' + ENV['RAILS_ENV'] = "development" + ENV['SECRET_KEY_BASE'] ||= SecureRandom.hex(16) FileUtils.rm_rf(app_path) FileUtils.cp_r(app_template_path, app_path) @@ -117,9 +118,26 @@ module TestHelpers end end + File.open("#{app_path}/config/database.yml", "w") do |f| + f.puts <<-YAML + default: &default + adapter: sqlite3 + pool: 5 + timeout: 5000 + development: + <<: *default + database: db/development.sqlite3 + test: + <<: *default + database: db/test.sqlite3 + production: + <<: *default + database: db/production.sqlite3 + YAML + end + add_to_config <<-RUBY config.eager_load = false - config.secret_key_base = "3b7cd727ee24e8444053437c36cc66c4" config.session_store :cookie_store, key: "_myapp_session" config.active_support.deprecation = :log config.action_controller.allow_forgery_protection = false @@ -139,7 +157,7 @@ module TestHelpers app = Class.new(Rails::Application) app.config.eager_load = false - app.config.secret_key_base = "3b7cd727ee24e8444053437c36cc66c4" + app.secrets.secret_key_base = "3b7cd727ee24e8444053437c36cc66c4" app.config.session_store :cookie_store, key: "_myapp_session" app.config.active_support.deprecation = :log diff --git a/railties/test/rails_info_controller_test.rb b/railties/test/rails_info_controller_test.rb index e45a5228a1..a9b237d0a5 100644 --- a/railties/test/rails_info_controller_test.rb +++ b/railties/test/rails_info_controller_test.rb @@ -1,7 +1,5 @@ require 'abstract_unit' -ActionController::Base.superclass.send(:include, ActionView::Layouts) - module ActionController class Base include ActionController::Testing diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index 3075ffee0d..c4b18e9ea5 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -399,7 +399,7 @@ YAML assert $plugin_initializer end - test "midleware referenced in configuration" do + test "middleware referenced in configuration" do @plugin.write "lib/bukkits.rb", <<-RUBY class Bukkits def initialize(app) diff --git a/railties/test/railties/railtie_test.rb b/railties/test/railties/railtie_test.rb index 4cbd4822be..a458240d2f 100644 --- a/railties/test/railties/railtie_test.rb +++ b/railties/test/railties/railtie_test.rb @@ -72,6 +72,14 @@ module RailtiesTest assert $to_prepare end + test "railtie have access to application in before_configuration callbacks" do + $after_initialize = false + class Foo < Rails::Railtie ; config.before_configuration { $before_configuration = Rails.root.to_path } ; end + assert_not $before_configuration + require "#{app_path}/config/environment" + assert_equal app_path, $before_configuration + end + test "railtie can add after_initialize callbacks" do $after_initialize = false class Foo < Rails::Railtie ; config.after_initialize { $after_initialize = true } ; end diff --git a/railties/test/version_test.rb b/railties/test/version_test.rb new file mode 100644 index 0000000000..f270d8f0c9 --- /dev/null +++ b/railties/test/version_test.rb @@ -0,0 +1,12 @@ +require 'abstract_unit' + +class VersionTest < ActiveSupport::TestCase + def test_rails_version_returns_a_string + assert Rails.version.is_a? String + end + + def test_rails_gem_version_returns_a_correct_gem_version_object + assert Rails.gem_version.is_a? Gem::Version + assert_equal Rails.version, Rails.gem_version.to_s + end +end |