diff options
Diffstat (limited to 'railties')
162 files changed, 3158 insertions, 1262 deletions
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index 21887c32fe..2960eccb3f 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,281 +1,178 @@ -* `test_help.rb` now automatically checks/maintains your test datbase - schema. (Use `config.active_record.maintain_test_schema = false` to - disable.) +* Remove `--skip-action-view` option from `Rails::Generators::AppBase`. - *Jon Leighton* + Fixes #17023. -* Configure `secrets.yml` and `database.yml` to read configuration - from the system environment by default for production. + *Dan Olson* - *José Valim* +* Specify dummy app's db migrate path in plugin's test_helper.rb. -* `config.assets.raise_runtime_errors` is set to true by default + Fixes #16877. - This option has been introduced in - [sprockets-rails#100][https://github.com/rails/sprockets-rails/pull/100] - and defaults to true in new applications in development. + *Yukio Mizuta* - *Richard Schneeman* - -* Generates `html` and `text` templates for mailers by default. - - *Kassio Borges* - -* Move `secret_key_base` from `config/initializers/secret_token.rb` - to `config/secrets.yml`. - - `secret_key_base` is now saved in `Rails.application.secrets.secret_key_base` - and it fallbacks to the value of `config.secret_key_base` when it is not - present in `config/secrets.yml`. - - `config/initializers/secret_token.rb` is not generated by default - in new applications. - - *Guillermo Iguaran* - -* Generate a new `secrets.yml` file in the `config` folder for new - applications. By default, this file contains the application's `secret_key_base`, - but it could also be used to store other secrets such as access keys for external - APIs. +* Inject `Rack::Lock` if `config.eager_load` is false. - The secrets added to this file will be accessible via `Rails.application.secrets`. - For example, with the following `secrets.yml`: + Fixes #15089. - development: - secret_key_base: 3b7cd727ee24e8444053437c36cc66c3 - some_api_key: SOMEKEY - - `Rails.application.secrets.some_api_key` will return `SOMEKEY` in the development - environment. + *Xavier Noria* - *Guillermo Iguaran* +* Change the path of dummy app location in plugin's test_helper.rb for cases + you specify dummy_path option. -* Add `ENV['DATABASE_URL']` support in `rails dbconsole`. Fixes #13320. + *Yukio Mizuta* - *Huiming Teo* +* Fix a bug in the `gem` method for Rails templates when non-String options + are used. -* Add `Application#message_verifier` method to return a message verifier. + Fixes #16709. - This verifier can be used to generate and verify signed messages in the application. + *Yves Senn* - message = Rails.application.message_verifier(:sensitive_data).generate('my sensible data') - Rails.application.message_verifier(:sensitive_data).verify(message) - # => 'my sensible data' +* The [web-console](https://github.com/rails/web-console) gem is now + installed by default for new applications. It can help you debug + development exceptions by spawning an interactive console in its cause + binding. - It is recommended not to use the same verifier for different things, so you can get different - verifiers passing the name argument. + *Ryan Dao*, *Genadi Samokovarov*, *Guillermo Iguaran* - message = Rails.application.message_verifier(:cookies).generate('my sensible cookie data') +* Add a `required` option to the model generator for associations - See the `ActiveSupport::MessageVerifier` documentation for more information. + *Sean Griffin* - *Rafael Mendonça França* +* Add `after_bundle` callbacks in Rails templates. Useful for allowing the + generated binstubs to be added to version control. -* The [Spring application - preloader](https://github.com/jonleighton/spring) is now installed - by default for new applications. It uses the development group of - the Gemfile, so will not be installed in production. + Fixes #16292. - *Jon Leighton* + *Stefan Kanev* -* Uses .railsrc while creating new plugin if it is available. - Fixes #10700. +* Pull in the custom configuration concept from dhh/custom_configuration, which allows you to + configure your own code through the Rails configuration object with custom configuration: - *Prathamesh Sonpatki* + # config/environments/production.rb + config.x.payment_processing.schedule = :daily + config.x.payment_processing.retries = 3 + config.x.super_debugger = true -* Remove turbolinks when generating a new application based on a template that skips it. + These configuration points are then available through the configuration object: - Example: + Rails.configuration.x.payment_processing.schedule # => :daily + Rails.configuration.x.payment_processing.retries # => 3 + Rails.configuration.x.super_debugger # => true - Skips turbolinks adding `add_gem_entry_filter { |gem| gem.name != "turbolinks" }` - to the template. + *DHH* - *Lauro Caetano* +* Scaffold generator `_form` partial adds `class="field"` for password + confirmation fields. -* 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. + *noinkling* - Registering subscriber examples: +* Add `Rails::Application.config_for` to load a configuration for the current + environment. - # 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 + # config/exception_notification.yml: + production: + url: http://127.0.0.1:8080 + namespace: my_app_production + development: + url: http://localhost:3001 + namespace: my_app_development - # 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 + # config/production.rb + Rails.application.configure do + config.middleware.use ExceptionNotifier, config_for(:exception_notification) end - *Paul Nikitochkin* + *Rafael Mendonça França*, *DHH* -* Support for Pathnames in eager load paths. +* Deprecate `Rails::Rack::LogTailer` without replacement. - *Mike Pack* + *Rafael Mendonça França* -* Fixed missing line and shadow on service pages(404, 422, 500). +* Add a generic --skip-turbolinks options to generator. - *Dmitry Korotkov* + *Rafael Mendonça França* -* `BACKTRACE` environment variable to show unfiltered backtraces for - test failures. +* Invalid `bin/rails generate` commands will now show spelling suggestions. - Example: + *Richard Schneeman* - $ BACKTRACE=1 ruby -Itest ... - # or with rake - $ BACKTRACE=1 bin/rake +* Add `bin/setup` script to bootstrap an application. *Yves Senn* -* Removal of all javascript stuff (gems and files) when generating a new - application using the `--skip-javascript` option. +* Replace double quotes with single quotes while adding an entry into Gemfile. - *Robin Dupret* + *Alexander Belaev* -* Make the application name snake cased when it contains spaces +* Default `config.assets.digest` to `true` in development. - 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. + *Dan Kang* - *Robin Dupret* - -* Added `--model-name` option to `ScaffoldControllerGenerator`. - - *yalab* - -* Expose MiddlewareStack#unshift to environment configuration. +* Load database configuration from the first `database.yml` available in paths. - *Ben Pickles* - -* `rails server` will only extend the logger to output to STDOUT - in development environment. - - *Richard Schneeman* + *Pier-Olivier Thibault* -* Don't require passing path to app before options in `rails new` - and `rails plugin new` +* Reading name and email from git for plugin gemspec. - *Piotr Sarnacki* + Fixes #9589. -* rake notes now searches *.less files + *Arun Agrawal*, *Abd ar-Rahman Hamidi*, *Roman Shmatov* - *Josh Crowder* +* Fix `console` and `generators` blocks defined at different environments. -* Generate nested route for namespaced controller generated using - `rails g controller`. - Fixes #11532. - - 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. + Fixes #14748. *Rafael Mendonça França* -* Make `config.log_level` work with custom loggers. +* Move configuration of asset precompile list and version to an initializer. - *Max Shytikov* + *Matthew Draper* -* Changed stylesheet load order in the stylesheet manifest generator. - Fixes #11639. +* Remove sqlite3 lines from `.gitignore` if the application is not using sqlite3. - *Pawel Janiak* + *Dmitrii Golub* -* Added generated unit test for generator generator using new - `test:generators` rake task. +* Add public API to register new extensions for `rake notes`. - *Josef Šimánek* - -* Removed `update:application_controller` rake task. - - *Josef Šimánek* - -* Fix `rake environment` to do not eager load modules - - *Paul Nikitochkin* + Example: -* Fix `rake notes` to look into `*.sass` files + config.annotations.register_extensions("scss", "sass") { |tag| /\/\/\s*(#{tag}):?\s*(.*)$/ } - *Yuri Artemev* + *Roberto Miranda* -* Removed deprecated `Rails.application.railties.engines`. +* Removed unnecessary `rails application` command. *Arun Agrawal* -* Removed deprecated threadsafe! from Rails Config. - - *Paul Nikitochkin* - -* Remove deprecated `ActiveRecord::Generators::ActiveModel#update_attributes` in - favor of `ActiveRecord::Generators::ActiveModel#update`. +* Make the `rails:template` rake task load the application's initializers. - *Vipul A M* + Fixes #12133. -* 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`. + *Robin Dupret* - *John Wang* +* Introduce `Rails.gem_version` as a convenience method to return + `Gem::Version.new(Rails.version)`, suggesting a more reliable way to perform + version comparison. -* Clearing autoloaded constants triggers routes reloading. - Fixes #10685. + Example: - *Xavier Noria* + Rails.version #=> "4.1.2" + Rails.gem_version #=> #<Gem::Version "4.1.2"> -* Fixes bug with scaffold generator with `--assets=false --resource-route=false`. - Fixes #9525. + 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 - *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/RDOC_MAIN.rdoc b/railties/RDOC_MAIN.rdoc index eccdee7b07..8d847eaa1c 100644 --- a/railties/RDOC_MAIN.rdoc +++ b/railties/RDOC_MAIN.rdoc @@ -1,7 +1,7 @@ == Welcome to \Rails \Rails is a web-application framework that includes everything needed to create -database-backed web applications according to the {Model-View-Controller (MVC)}[http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller] pattern. +database-backed web applications according to the {Model-View-Controller (MVC)}[http://en.wikipedia.org/wiki/Model-view-controller] pattern. Understanding the MVC pattern is key to understanding \Rails. MVC divides your application into three layers, each with a specific responsibility. diff --git a/railties/README.rdoc b/railties/README.rdoc index 6248b5feed..a25658668c 100644 --- a/railties/README.rdoc +++ b/railties/README.rdoc @@ -31,7 +31,11 @@ API documentation is at * http://api.rubyonrails.org -Bug reports and feature requests can be filed with the rest for the Ruby on Rails project here: +Bug reports can be filed for the Ruby on Rails project here: * https://github.com/rails/rails/issues +Feature requests should be discussed on the rails-core mailing list here: + +* https://groups.google.com/forum/?fromgroups#!forum/rubyonrails-core + diff --git a/railties/Rakefile b/railties/Rakefile index a899d069b5..9a377ce4ee 100644 --- a/railties/Rakefile +++ b/railties/Rakefile @@ -29,6 +29,7 @@ Rake::TestTask.new('test:regular') do |t| t.pattern = 'test/**/*_test.rb' t.warning = true t.verbose = true + t.ruby_opts = ["--dev"] if defined?(JRUBY_VERSION) end # Generate GEM ---------------------------------------------------------------------------- diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb index be7570a5ba..e7172e491f 100644 --- a/railties/lib/rails.rb +++ b/railties/lib/rails.rb @@ -29,7 +29,13 @@ module Rails autoload :WelcomeController class << self - attr_accessor :application, :cache, :logger + @application = @app_class = nil + + attr_writer :application + attr_accessor :app_class, :cache, :logger + def application + @application ||= (app_class.instance if app_class) + end delegate :initialize!, :initialized?, to: :application @@ -80,10 +86,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/all.rb b/railties/lib/rails/all.rb index 2e83c0fe14..45361fca83 100644 --- a/railties/lib/rails/all.rb +++ b/railties/lib/rails/all.rb @@ -5,6 +5,7 @@ require "rails" action_controller action_view action_mailer + active_job rails/test_unit sprockets ).each do |framework| diff --git a/railties/lib/rails/api/task.rb b/railties/lib/rails/api/task.rb index 3e32576040..4d49244807 100644 --- a/railties/lib/rails/api/task.rb +++ b/railties/lib/rails/api/task.rb @@ -50,6 +50,13 @@ module Rails ) }, + 'activejob' => { + :include => %w( + README.md + lib/active_job/**/*.rb + ) + }, + 'railties' => { :include => %w( README.rdoc diff --git a/railties/lib/rails/app_rails_loader.rb b/railties/lib/rails/app_rails_loader.rb index 1610751844..39d8007333 100644 --- a/railties/lib/rails/app_rails_loader.rb +++ b/railties/lib/rails/app_rails_loader.rb @@ -2,6 +2,8 @@ require 'pathname' module Rails module AppRailsLoader + extend self + RUBY = Gem.ruby EXECUTABLES = ['bin/rails', 'script/rails'] BUNDLER_WARNING = <<EOS @@ -26,7 +28,7 @@ generate it and add it to source control: EOS - def self.exec_app_rails + def exec_app_rails original_cwd = Dir.pwd loop do @@ -54,8 +56,8 @@ EOS end end - def self.find_executable - EXECUTABLES.find { |exe| File.exist?(exe) } + def find_executable + EXECUTABLES.find { |exe| File.file?(exe) } end end end diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 05acd78d98..bc966e87c6 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -87,7 +87,15 @@ module Rails class << self def inherited(base) super - Rails.application ||= base.instance + Rails.app_class = base + end + + def instance + super.run_load_hooks! + end + + def create(initial_variable_values = {}, &block) + new(initial_variable_values, &block).run_load_hooks! end # Makes the +new+ method public. @@ -116,22 +124,33 @@ module Rails @ordered_railties = nil @railties = nil @message_verifiers = {} + @ran_load_hooks = false + + # are these actually used? + @initial_variable_values = initial_variable_values + @block = block add_lib_to_load_path! + end + + # Returns true if the application is initialized. + def initialized? + @initialized + end + + def run_load_hooks! # :nodoc: + return self if @ran_load_hooks + @ran_load_hooks = true ActiveSupport.run_load_hooks(:before_configuration, self) - initial_variable_values.each do |variable_name, value| + @initial_variable_values.each do |variable_name, value| if INITIAL_VARIABLES.include?(variable_name) instance_variable_set("@#{variable_name}", value) end end - instance_eval(&block) if block_given? - end - - # Returns true if the application is initialized. - def initialized? - @initialized + instance_eval(&@block) if @block + self end # Implements call according to the Rack API. It simply @@ -151,14 +170,13 @@ 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 + @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 end # Returns a message verifier object. @@ -186,6 +204,38 @@ module Rails end end + # Convenience for loading config/foo.yml for the current Rails env. + # + # Example: + # + # # config/exception_notification.yml: + # production: + # url: http://127.0.0.1:8080 + # namespace: my_app_production + # development: + # url: http://localhost:3001 + # namespace: my_app_development + # + # # config/production.rb + # Rails.application.configure do + # config.middleware.use ExceptionNotifier, config_for(:exception_notification) + # end + def config_for(name) + yaml = Pathname.new("#{paths["config"].existent.first}/#{name}.yml") + + if yaml.exist? + require "yaml" + require "erb" + (YAML.load(ERB.new(yaml.read).result) || {})[Rails.env] || {} + else + raise "Could not load configuration. No such file - #{yaml}" + end + rescue Psych::SyntaxError => e + raise "YAML syntax error occurred while parsing #{yaml}. " \ + "Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \ + "Error: #{e.message}" + end + # Stores some of the Rails initial environment parameters which # will be used by middlewares and engines to configure themselves. def env_config @@ -205,7 +255,9 @@ 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, + "action_dispatch.cookies_digest" => config.action_dispatch.cookies_digest }) end end @@ -229,6 +281,18 @@ module Rails self.class.runner(&blk) end + # Sends any console called in the instance of a new application up + # to the +console+ method defined in Rails::Railtie. + def console(&blk) + self.class.console(&blk) + end + + # Sends any generators called in the instance of a new application up + # to the +generators+ method defined in Rails::Railtie. + def generators(&blk) + self.class.generators(&blk) + end + # Sends the +isolate_namespace+ method up to the class method. def isolate_namespace(mod) self.class.isolate_namespace(mod) @@ -307,7 +371,8 @@ module Rails yaml = config.paths["config/secrets"].first if File.exist?(yaml) require "erb" - env_secrets = YAML.load(ERB.new(IO.read(yaml)).result)[Rails.env] + 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 @@ -330,6 +395,35 @@ 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 + + # Return an array of railties respecting the order they're loaded + # and the order specified by the +railties_order+ config. + # + # While when running initializers we need engines in reverse + # order here when copying migrations from railties we need then in the same + # order as given by +railties_order+ + def migration_railties # :nodoc: + ordered_railties.flatten - [self] + end + protected alias :build_middleware_stack :app @@ -379,13 +473,13 @@ module Rails index = order.index(:all) order[index] = all - order.reverse.flatten + order end end def railties_initializers(current) #:nodoc: initializers = [] - ordered_railties.each do |r| + ordered_railties.reverse.flatten.each do |r| if r == self initializers += current else diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb index a26d41c0cf..0f4d932749 100644 --- a/railties/lib/rails/application/bootstrap.rb +++ b/railties/lib/rails/application/bootstrap.rb @@ -47,7 +47,8 @@ INFO logger = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new(STDERR)) logger.level = ActiveSupport::Logger::WARN logger.warn( - "Rails Error: Unable to access log file. Please ensure that #{path} exists and is chmod 0666. " + + "Rails Error: Unable to access log file. Please ensure that #{path} exists and is writable " + + "(ie, make it writable for user and group: chmod 0664 #{path}). " + "The log level has been raised to WARN and the output directed to STDERR until the problem is fixed." ) logger diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index 9975bb8596..786dcee007 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 @@ -12,7 +13,7 @@ module Rails :railties_order, :relative_url_root, :secret_key_base, :secret_token, :serve_static_assets, :ssl_options, :static_cache_control, :session_options, :time_zone, :reload_classes_only_on_change, - :beginning_of_week, :filter_redirect + :beginning_of_week, :filter_redirect, :x attr_writer :log_level attr_reader :encoding @@ -47,6 +48,7 @@ module Rails @eager_load = nil @secret_token = nil @secret_key_base = nil + @x = Custom.new @assets = ActiveSupport::OrderedOptions.new @assets.enabled = true @@ -88,25 +90,35 @@ 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) + path = paths["config/database"].existent.first + yaml = Pathname.new(path) if path + + config = if yaml && 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}" + raise "Could not load database configuration. No such file - #{paths["config/database"].instance_variable_get(:@paths)}" 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 - @log_level ||= Rails.env.production? ? :info : :debug + @log_level ||= :debug end def colorize_logging @@ -141,6 +153,26 @@ module Rails end end + def annotations + SourceAnnotationExtractor::Annotation + end + + private + class Custom #:nodoc: + def initialize + @configurations = Hash.new + end + + def method_missing(method, *args) + if method =~ /=$/ + @configurations[$`.to_sym] = args.first + else + @configurations.fetch(method) { + @configurations[method] = ActiveSupport::OrderedOptions.new + } + end + end + 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 a00afe008c..d1789192ef 100644 --- a/railties/lib/rails/application/default_middleware_stack.rb +++ b/railties/lib/rails/application/default_middleware_stack.rb @@ -66,7 +66,11 @@ module Rails end def allow_concurrency? - config.allow_concurrency.nil? ? config.cache_classes : config.allow_concurrency + if config.allow_concurrency.nil? + config.cache_classes && config.eager_load + else + config.allow_concurrency + end end def load_rack_cache diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index 5b8509b2e9..7a1bb1e25c 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -22,8 +22,6 @@ 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/backtrace_cleaner.rb b/railties/lib/rails/backtrace_cleaner.rb index 8cc8eb1103..5276eb33c9 100644 --- a/railties/lib/rails/backtrace_cleaner.rb +++ b/railties/lib/rails/backtrace_cleaner.rb @@ -4,12 +4,16 @@ module Rails class BacktraceCleaner < ActiveSupport::BacktraceCleaner APP_DIRS_PATTERN = /^\/?(app|config|lib|test)/ RENDER_TEMPLATE_PATTERN = /:in `_render_template_\w*'/ + EMPTY_STRING = ''.freeze + SLASH = '/'.freeze + DOT_SLASH = './'.freeze def initialize super - add_filter { |line| line.sub("#{Rails.root}/", '') } - add_filter { |line| line.sub(RENDER_TEMPLATE_PATTERN, '') } - add_filter { |line| line.sub('./', '/') } # for tests + @root = "#{Rails.root}/".freeze + add_filter { |line| line.sub(@root, EMPTY_STRING) } + add_filter { |line| line.sub(RENDER_TEMPLATE_PATTERN, EMPTY_STRING) } + add_filter { |line| line.sub(DOT_SLASH, SLASH) } # for tests add_gem_filters add_silencer { |line| line !~ APP_DIRS_PATTERN } @@ -21,7 +25,8 @@ module Rails return if gems_paths.empty? gems_regexp = %r{(#{gems_paths.join('|')})/gems/([^/]+)-([\w.]+)/(.*)} - add_filter { |line| line.sub(gems_regexp, '\2 (\3) \4') } + gems_result = '\2 (\3) \4'.freeze + add_filter { |line| line.sub(gems_regexp, gems_result) } end end end diff --git a/railties/lib/rails/commands/commands_tasks.rb b/railties/lib/rails/commands/commands_tasks.rb index de60423784..8bae08e44e 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 @@ -132,7 +127,7 @@ EOT require 'rails/generators' require_application_and_environment! Rails.application.load_generators - require "rails/commands/#{command}" + require_command!(command) end # Change to the application's path if there is no config.ru file in current directory. diff --git a/railties/lib/rails/commands/console.rb b/railties/lib/rails/commands/console.rb index f6bdf129d6..96ced3c2f9 100644 --- a/railties/lib/rails/commands/console.rb +++ b/railties/lib/rails/commands/console.rb @@ -18,7 +18,14 @@ module Rails opt.on("-e", "--environment=name", String, "Specifies the environment to run this console under (test/development/production).", "Default: development") { |v| options[:environment] = v.strip } - opt.on("--debugger", 'Enable the debugger.') { |v| options[:debugger] = v } + opt.on("--debugger", 'Enables the debugger.') do |v| + if RUBY_VERSION < '2.0.0' + options[:debugger] = v + else + puts "=> Notice: debugger option is ignored since Ruby 2.0 and " \ + "it will be removed in future versions." + end + end opt.parse!(arguments) end @@ -69,12 +76,25 @@ module Rails Rails.env = environment end - def debugger? - options[:debugger] + if RUBY_VERSION < '2.0.0' + def debugger? + options[:debugger] + end + + def require_debugger + require 'debugger' + puts "=> Debugger enabled" + rescue LoadError + puts "You're missing the 'debugger' gem. Add it to your Gemfile, bundle it and try again." + exit(1) + end end def start - require_debugger if debugger? + if RUBY_VERSION < '2.0.0' + require_debugger if debugger? + end + set_environment! if environment? if sandbox? @@ -89,13 +109,5 @@ module Rails end console.start end - - def require_debugger - require 'debugger' - puts "=> Debugger enabled" - rescue LoadError - puts "You're missing the 'debugger' gem. Add it to your Gemfile, bundle it and try again." - exit(1) - end end end diff --git a/railties/lib/rails/commands/dbconsole.rb b/railties/lib/rails/commands/dbconsole.rb index c265ed8f36..1a2613a8d0 100644 --- a/railties/lib/rails/commands/dbconsole.rb +++ b/railties/lib/rails/commands/dbconsole.rb @@ -20,7 +20,7 @@ module Rails ENV['RAILS_ENV'] = options[:environment] || environment case config["adapter"] - when /^mysql/ + when /^(jdbc)?mysql/ args = { 'host' => '--host', 'port' => '--port', @@ -81,10 +81,11 @@ module Rails def config @config ||= begin - require APP_PATH - ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new( - Rails.application.config.database_configuration || {} - ).resolve(ENV["DATABASE_URL"]) + if configurations[environment].blank? + raise ActiveRecord::AdapterNotSpecified, "'#{environment}' database is not configured. Available configuration: #{configurations.inspect}" + else + configurations[environment] + end end end @@ -98,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 f7a0b99005..95bbdd4cdf 100644 --- a/railties/lib/rails/commands/plugin.rb +++ b/railties/lib/rails/commands/plugin.rb @@ -11,7 +11,7 @@ else end if File.exist?(railsrc) extra_args_string = File.read(railsrc) - extra_args = extra_args_string.split(/\n+/).map {|l| l.split}.flatten + 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 diff --git a/railties/lib/rails/commands/server.rb b/railties/lib/rails/commands/server.rb index fec4962fb5..e39f0920af 100644 --- a/railties/lib/rails/commands/server.rb +++ b/railties/lib/rails/commands/server.rb @@ -9,16 +9,33 @@ module Rails def parse!(args) args, options = args.dup, {} - opt_parser = OptionParser.new do |opts| - opts.banner = "Usage: rails server [mongrel, thin, etc] [options]" + option_parser(options).parse! args + + options[:log_stdout] = options[:daemonize].blank? && (options[:environment] || Rails.env) == "development" + options[:server] = args.shift + options + end + + private + + def option_parser(options) + OptionParser.new do |opts| + opts.banner = "Usage: rails server [mongrel, thin etc] [options]" opts.on("-p", "--port=port", Integer, "Runs Rails on the specified port.", "Default: 3000") { |v| options[:Port] = v } - opts.on("-b", "--binding=ip", String, - "Binds Rails to the specified ip.", "Default: 0.0.0.0") { |v| options[:Host] = v } + opts.on("-b", "--binding=IP", String, + "Binds Rails to the specified IP.", "Default: localhost") { |v| options[:Host] = v } opts.on("-c", "--config=file", String, - "Use custom rackup configuration file") { |v| options[:config] = v } - opts.on("-d", "--daemon", "Make server run as a Daemon.") { options[:daemonize] = true } - opts.on("-u", "--debugger", "Enable the debugger") { options[:debugger] = true } + "Uses a custom rackup configuration.") { |v| options[:config] = v } + opts.on("-d", "--daemon", "Runs server as a Daemon.") { options[:daemonize] = true } + opts.on("-u", "--debugger", "Enables the debugger.") do + if RUBY_VERSION < '2.0.0' + options[:debugger] = true + else + puts "=> Notice: debugger option is ignored since Ruby 2.0 and " \ + "it will be removed in future versions." + end + end opts.on("-e", "--environment=name", String, "Specifies the environment to run this server under (test/development/production).", "Default: development") { |v| options[:environment] = v } @@ -28,14 +45,8 @@ module Rails opts.separator "" - opts.on("-h", "--help", "Show this help message.") { puts opts; exit } + opts.on("-h", "--help", "Shows this help message.") { puts opts; exit } end - - opt_parser.parse! args - - options[:log_stdout] = options[:daemonize].blank? && (options[:environment] || Rails.env) == "development" - options[:server] = args.shift - options end end @@ -75,7 +86,9 @@ module Rails def middleware middlewares = [] - middlewares << [Rails::Rack::Debugger] if options[:debugger] + if RUBY_VERSION < '2.0.0' + middlewares << [Rails::Rack::Debugger] if options[:debugger] + end middlewares << [::Rack::ContentLength] # FIXME: add Rack::Lock in the case people are using webrick. @@ -113,10 +126,6 @@ module Rails puts "=> Rails #{Rails.version} application starting in #{Rails.env} on #{url}" puts "=> Run `rails server -h` for more startup options" - if options[:Host].to_s.match(/0\.0\.0\.0/) - puts "=> Notice: server is listening on all interfaces (#{options[:Host]}). Consider using 127.0.0.1 (--binding option)" - end - puts "=> Ctrl-C to shutdown server" unless options[:daemonize] end diff --git a/railties/lib/rails/commands/update.rb b/railties/lib/rails/commands/update.rb deleted file mode 100644 index 59fae5c337..0000000000 --- a/railties/lib/rails/commands/update.rb +++ /dev/null @@ -1,9 +0,0 @@ -require File.expand_path(File.join(File.dirname(__FILE__), '..', 'generators')) - -if ARGV.size == 0 - Rails::Generators.help - exit -end - -name = ARGV.shift -Rails::Generators.invoke name, ARGV, behavior: :skip diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 5c54cdaa70..dc3da1eb41 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -371,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 @@ -395,7 +395,7 @@ module Rails end unless mod.respond_to?(:railtie_routes_url_helpers) - define_method(:railtie_routes_url_helpers) { railtie.routes.url_helpers } + define_method(:railtie_routes_url_helpers) {|include_path_helpers = true| railtie.routes.url_helpers(include_path_helpers) } end end end @@ -429,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) @@ -510,7 +509,7 @@ module Rails def call(env) env.merge!(env_config) if env['SCRIPT_NAME'] - env.merge! "ROUTES_#{routes.object_id}_SCRIPT_NAME" => env['SCRIPT_NAME'].dup + env["ROUTES_#{routes.object_id}_SCRIPT_NAME"] = env['SCRIPT_NAME'].dup end app.call(env) end diff --git a/railties/lib/rails/gem_version.rb b/railties/lib/rails/gem_version.rb new file mode 100644 index 0000000000..8abed99f2c --- /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 = "beta4" + + STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") + end +end diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb index dce734b54e..bf2390cb7e 100644 --- a/railties/lib/rails/generators.rb +++ b/railties/lib/rails/generators.rb @@ -156,10 +156,20 @@ module Rails args << "--help" if args.empty? && klass.arguments.any? { |a| a.required? } klass.start(args, config) else - puts "Could not find generator #{namespace}." + options = sorted_groups.map(&:last).flatten + suggestions = options.sort_by {|suggested| levenshtein_distance(namespace.to_s, suggested) }.first(3) + msg = "Could not find generator '#{namespace}'. " + msg << "Maybe you meant #{ suggestions.map {|s| "'#{s}'"}.join(" or ") }\n" + msg << "Run `rails generate --help` for more options." + puts msg end end + # Returns an array of generator namespaces that are hidden. + # Generator namespaces may be hidden for a variety of reasons. + # Some are aliased such as "rails:migration" and can be + # invoked with the shorter "migration", others are private to other generators + # such as "css:scaffold". def self.hidden_namespaces @hidden_namespaces ||= begin orm = options[:rails][:orm] @@ -199,17 +209,6 @@ module Rails # Show help message with available generators. def self.help(command = 'generate') - lookup! - - namespaces = subclasses.map{ |k| k.namespace } - namespaces.sort! - - groups = Hash.new { |h,k| h[k] = [] } - namespaces.each do |namespace| - base = namespace.split(':').first - groups[base] << namespace - end - puts "Usage: rails #{command} GENERATOR [args] [options]" puts puts "General options:" @@ -222,20 +221,74 @@ module Rails puts "Please choose a generator below." puts - # Print Rails defaults first. + print_generators + end + + def self.public_namespaces + lookup! + subclasses.map { |k| k.namespace } + end + + def self.print_generators + sorted_groups.each { |b, n| print_list(b, n) } + end + + def self.sorted_groups + namespaces = public_namespaces + namespaces.sort! + groups = Hash.new { |h,k| h[k] = [] } + namespaces.each do |namespace| + base = namespace.split(':').first + groups[base] << namespace + end rails = groups.delete("rails") rails.map! { |n| n.sub(/^rails:/, '') } rails.delete("app") rails.delete("plugin") - print_list("rails", rails) hidden_namespaces.each { |n| groups.delete(n.to_s) } - groups.sort.each { |b, n| print_list(b, n) } + [["rails", rails]] + groups.sort.to_a end protected + # This code is based directly on the Text gem implementation + # Returns a value representing the "cost" of transforming str1 into str2 + def self.levenshtein_distance str1, str2 + s = str1 + t = str2 + n = s.length + m = t.length + max = n/2 + + return m if (0 == n) + return n if (0 == m) + return n if (n - m).abs > max + + d = (0..m).to_a + x = nil + + str1.each_char.each_with_index do |char1,i| + e = i+1 + + str2.each_char.each_with_index do |char2,j| + cost = (char1 == char2) ? 0 : 1 + x = [ + d[j+1] + 1, # insertion + e + 1, # deletion + d[j] + cost # substitution + ].min + d[j] = e + e = x + end + + d[m] = x + end + + return x + end + # Prints a list of generators. def self.print_list(base, namespaces) #:nodoc: namespaces = namespaces.reject do |n| diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb index afdbf5c241..ffdb314612 100644 --- a/railties/lib/rails/generators/actions.rb +++ b/railties/lib/rails/generators/actions.rb @@ -7,6 +7,7 @@ module Rails def initialize(*) # :nodoc: super @in_group = nil + @after_bundle_callbacks = [] end # Adds an entry into +Gemfile+ for the supplied gem. @@ -20,9 +21,9 @@ module Rails # Set the message to be shown in logs. Uses the git repo if one is given, # otherwise use name (version). - parts, message = [ name.inspect ], name + parts, message = [ quote(name) ], name if version ||= options.delete(:version) - parts << version.inspect + parts << quote(version) message << " (#{version})" end message = options[:git] if options[:git] @@ -30,7 +31,7 @@ module Rails log :gemfile, message options.each do |option, value| - parts << "#{option}: #{value.inspect}" + parts << "#{option}: #{quote(value)}" end in_root do @@ -68,7 +69,7 @@ module Rails log :source, source in_root do - prepend_file "Gemfile", "source #{source.inspect}\n", verbose: false + prepend_file "Gemfile", "source #{quote(source)}\n", verbose: false end end @@ -84,10 +85,10 @@ module Rails # environment(nil, env: "development") do # "config.autoload_paths += %W(#{config.root}/extras)" # end - def environment(data=nil, options={}, &block) + def environment(data=nil, options={}) sentinel = /class [a-z_:]+ < Rails::Application/i env_file_sentinel = /Rails\.application\.configure do/ - data = block.call if !data && block_given? + data = yield if !data && block_given? in_root do if options[:env].nil? @@ -188,7 +189,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 @@ -232,6 +233,16 @@ module Rails log File.read(find_in_source_paths(path)) end + # Registers a callback to be executed after bundle and spring binstubs + # have run. + # + # after_bundle do + # git add: '.' + # end + def after_bundle(&block) + @after_bundle_callbacks << block + end + protected # Define log for backwards compatibility. If just one argument is sent, @@ -255,6 +266,17 @@ module Rails end end + # Surround string with single quotes if there is no quotes. + # Otherwise fall back to double quotes + def quote(value) + return value.inspect unless value.is_a? String + + if value.include?("'") + value.inspect + else + "'#{value}'" + end + end end end end 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..cffdef6ec9 --- /dev/null +++ b/railties/lib/rails/generators/actions/create_migration.rb @@ -0,0 +1,69 @@ +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 + 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) + yield + 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 " + + "or --skip to ignore conflicted 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 3305a57b62..92ed9136a0 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -41,9 +41,6 @@ module Rails class_option :skip_active_record, type: :boolean, aliases: '-O', default: false, desc: 'Skip Active Record files' - class_option :skip_action_view, type: :boolean, aliases: '-V', default: false, - desc: 'Skip Action View files' - class_option :skip_sprockets, type: :boolean, aliases: '-S', default: false, desc: 'Skip Sprockets files' @@ -65,6 +62,9 @@ module Rails class_option :edge, type: :boolean, default: false, desc: "Setup the #{name} with Gemfile pointing to Rails repository" + class_option :skip_turbolinks, type: :boolean, default: false, + desc: 'Skip turbolinks gem' + class_option :skip_test_unit, type: :boolean, aliases: '-T', default: false, desc: 'Skip Test::Unit files' @@ -79,7 +79,6 @@ module Rails end def initialize(*args) - @original_wd = Dir.pwd @gem_filter = lambda { |gem| true } @extra_entries = [] super @@ -105,15 +104,14 @@ module Rails end def gemfile_entries - [ rails_gemfile_entry, - database_gemfile_entry, - assets_gemfile_entry, - javascript_gemfile_entry, - jbuilder_gemfile_entry, - sdoc_gemfile_entry, - platform_dependent_gemfile_entry, - spring_gemfile_entry, - @extra_entries].flatten.find_all(&@gem_filter) + [rails_gemfile_entry, + database_gemfile_entry, + assets_gemfile_entry, + javascript_gemfile_entry, + jbuilder_gemfile_entry, + sdoc_gemfile_entry, + psych_gemfile_entry, + @extra_entries].flatten.find_all(&@gem_filter) end def add_gem_entry_filter @@ -141,73 +139,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] @@ -227,13 +164,17 @@ module Rails end def include_all_railties? - !options[:skip_active_record] && !options[:skip_action_view] && !options[:skip_test_unit] && !options[:skip_sprockets] + !options[:skip_active_record] && !options[:skip_test_unit] && !options[:skip_sprockets] end def comment_if(value) 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 @@ -250,19 +191,13 @@ module Rails def self.path(name, path, comment = nil) new(name, nil, comment, path: path) end - - def padding(max_width) - ' ' * (max_width - name.length + 2) - end end def rails_gemfile_entry if options.dev? - [GemfileEntry.path('rails', Rails::Generators::RAILS_DEV_PATH), - GemfileEntry.github('arel', 'rails/arel')] + [GemfileEntry.path('rails', Rails::Generators::RAILS_DEV_PATH)] 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, @@ -308,7 +243,7 @@ module Rails 'Use SCSS for stylesheets') else gems << GemfileEntry.version('sass-rails', - '~> 4.0.1', + '~> 5.0.0.beta1', 'Use SCSS for stylesheets') end @@ -319,14 +254,6 @@ 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', '~> 2.0', comment) @@ -334,15 +261,15 @@ module Rails 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 - comment = 'Use CoffeeScript for .js.coffee assets and views' + comment = 'Use CoffeeScript for .coffee assets and views' if options.dev? || options.edge? GemfileEntry.github 'coffee-rails', 'rails/coffee-rails', comment else - GemfileEntry.version 'coffee-rails', '~> 4.0.0', comment + GemfileEntry.version 'coffee-rails', '~> 4.1.0', comment end end @@ -351,11 +278,20 @@ module Rails [] else gems = [coffee_gemfile_entry, javascript_runtime_gemfile_entry] - gems << GemfileEntry.version("#{options[:javascript]}-rails", nil, - "Use #{options[:javascript]} as the JavaScript library") - gems << GemfileEntry.version("turbolinks", nil, - "Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks") + if options[:javascript] == 'jquery' + gems << GemfileEntry.version('jquery-rails', '~> 4.0.0.beta2', + 'Use jQuery as the JavaScript library') + else + gems << GemfileEntry.version("#{options[:javascript]}-rails", nil, + "Use #{options[:javascript]} as the JavaScript library") + end + + unless options[:skip_turbolinks] + gems << GemfileEntry.version("turbolinks", nil, + "Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks") + end + gems end end @@ -369,10 +305,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/jonleighton/spring' - GemfileEntry.new('spring', nil, comment, group: :development) + def psych_gemfile_entry + return [] unless defined?(Rubinius) + + comment = 'Use Psych as the YAML engine, instead of Syck, so serialized ' \ + 'data can be read safely from different rubies (see http://git.io/uuLVag)' + GemfileEntry.new('psych', '~> 2.0', comment, platforms: :rbx) end def bundle_command(command) @@ -394,7 +332,8 @@ 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 diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb index 67bab96a22..9af6435f23 100644 --- a/railties/lib/rails/generators/base.rb +++ b/railties/lib/rails/generators/base.rb @@ -83,7 +83,7 @@ module Rails # # The first and last part used to find the generator to be invoked are # guessed based on class invokes hook_for, as noticed in the example above. - # This can be customized with two options: :base and :as. + # This can be customized with two options: :in and :as. # # Let's suppose you are creating a generator that needs to invoke the # controller generator from test unit. Your first attempt is: @@ -108,7 +108,7 @@ module Rails # "test_unit:controller", "test_unit" # # Similarly, if you want it to also lookup in the rails namespace, you just - # need to provide the :base value: + # need to provide the :in value: # # class AwesomeGenerator < Rails::Generators::Base # hook_for :test_framework, in: :rails, as: :controller diff --git a/railties/lib/rails/generators/erb.rb b/railties/lib/rails/generators/erb.rb index cfd77097d5..0755ac335c 100644 --- a/railties/lib/rails/generators/erb.rb +++ b/railties/lib/rails/generators/erb.rb @@ -6,7 +6,7 @@ module Erb # :nodoc: protected def formats - format + [format] end def format @@ -17,7 +17,7 @@ module Erb # :nodoc: :erb end - def filename_with_extensions(name, format) + 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 e62aece7c5..94c1b835d1 100644 --- a/railties/lib/rails/generators/erb/controller/controller_generator.rb +++ b/railties/lib/rails/generators/erb/controller/controller_generator.rb @@ -11,7 +11,7 @@ module Erb # :nodoc: actions.each do |action| @action = action - Array(formats).each do |format| + formats.each do |format| @path = File.join(base_path, filename_with_extensions(action, format)) template filename_with_extensions(:view, format), @path 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 index 8bb7c2b768..b5045671b3 100644 --- a/railties/lib/rails/generators/erb/mailer/templates/view.html.erb +++ b/railties/lib/rails/generators/erb/mailer/templates/view.html.erb @@ -1,5 +1,5 @@ <h1><%= class_name %>#<%= @action %></h1> <p> - <%%= @greeting %>, find me in app/views/<%= @path %> + <%%= @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 b219f459ac..c94829a0ae 100644 --- a/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb @@ -14,7 +14,7 @@ module Erb # :nodoc: def copy_view_files available_views.each do |view| - Array(formats).each do |format| + formats.each do |format| filename = filename_with_extensions(view, format) template filename, File.join("app/views", controller_file_path, filename) 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..bba9141fb8 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> @@ -17,17 +17,12 @@ <%%= f.label :password %><br> <%%= f.password_field :password %> </div> - <div> + <div class="field"> <%%= f.label :password_confirmation %><br> <%%= f.password_field :password_confirmation %> <% else -%> - <%- if attribute.reference? -%> <%%= f.label :<%= attribute.column_name %> %><br> <%%= f.<%= attribute.field_type %> :<%= attribute.column_name %> %> - <%- else -%> - <%%= f.label :<%= attribute.name %> %><br> - <%%= f.<%= attribute.field_type %> :<%= attribute.name %> %> - <%- end -%> <% end -%> </div> <% end -%> diff --git a/railties/lib/rails/generators/erb/scaffold/templates/edit.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/edit.html.erb index e58b9fbd08..5620fcc850 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/edit.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/edit.html.erb @@ -1,4 +1,4 @@ -<h1>Editing <%= singular_table_name %></h1> +<h1>Editing <%= singular_table_name.titleize %></h1> <%%= render 'form' %> diff --git a/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb index 814d6fdb0e..5e194783ff 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb @@ -1,4 +1,6 @@ -<h1>Listing <%= plural_table_name %></h1> +<p id="notice"><%%= notice %></p> + +<h1>Listing <%= plural_table_name.titleize %></h1> <table> <thead> diff --git a/railties/lib/rails/generators/erb/scaffold/templates/new.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/new.html.erb index 02ae4d015e..db13a5d870 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/new.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/new.html.erb @@ -1,4 +1,4 @@ -<h1>New <%= singular_table_name %></h1> +<h1>New <%= singular_table_name.titleize %></h1> <%%= render 'form' %> diff --git a/railties/lib/rails/generators/generated_attribute.rb b/railties/lib/rails/generators/generated_attribute.rb index 5e2784c4b0..f16bd8e082 100644 --- a/railties/lib/rails/generators/generated_attribute.rb +++ b/railties/lib/rails/generators/generated_attribute.rb @@ -44,8 +44,11 @@ module Rails return $1, limit: $2.to_i when /decimal\{(\d+)[,.-](\d+)\}/ return :decimal, precision: $1.to_i, scale: $2.to_i - when /(references|belongs_to)\{polymorphic\}/ - return $1, polymorphic: true + when /(references|belongs_to)\{(.+)\}/ + type = $1 + provided_options = $2.split(/[,.-]/) + options = Hash[provided_options.map { |opt| [opt.to_sym, true] }] + return type, options else return type, {} end @@ -94,6 +97,10 @@ module Rails name.sub(/_id$/, '').pluralize end + def singular_name + name.sub(/_id$/, '').singularize + end + def human_name name.humanize end @@ -119,7 +126,11 @@ module Rails end def polymorphic? - self.attr_options.has_key?(:polymorphic) + self.attr_options[:polymorphic] + end + + def required? + self.attr_options[:required] end def has_index? @@ -135,12 +146,21 @@ module Rails end def inject_options - "".tap { |s| @attr_options.each { |k,v| s << ", #{k}: #{v.inspect}" } } + "".tap { |s| options_for_migration.each { |k,v| s << ", #{k}: #{v.inspect}" } } end def inject_index_options has_uniq_index? ? ", unique: true" : "" end + + def options_for_migration + @attr_options.dup.tap do |options| + if required? + options.delete(:required) + options[:null] = false + end + end + end end end 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/named_base.rb b/railties/lib/rails/generators/named_base.rb index 5a92ab3e95..b7da44ca2d 100644 --- a/railties/lib/rails/generators/named_base.rb +++ b/railties/lib/rails/generators/named_base.rb @@ -30,7 +30,12 @@ module Rails protected attr_reader :file_name - alias :singular_name :file_name + + # FIXME: We are avoiding to use alias because a bug on thor that make + # this method public and add it to the task list. + def singular_name + file_name + end # Wrap block with namespace of current application # if namespace exists and is not skipped diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index d2eca5b2fb..9110c129d1 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 @@ -86,6 +86,16 @@ module Rails end end + def config_when_updating + cookie_serializer_config_exist = File.exist?('config/initializers/cookies_serializer.rb') + + config + + unless cookie_serializer_config_exist + gsub_file 'config/initializers/cookies_serializer.rb', /json/, 'marshal' + end + end + def database_yml template "config/databases/#{options[:database]}.yml", "config/database.yml" end @@ -166,7 +176,6 @@ module Rails end public_task :set_default_accessors! - public_task :apply_rails_template public_task :create_root def create_root_files @@ -189,6 +198,11 @@ module Rails build(:config) end + def update_config_files + build(:config_when_updating) + end + remove_task :update_config_files + def create_boot_file template "config/boot.rb" end @@ -232,14 +246,25 @@ module Rails end end + def delete_assets_initializer_skipping_sprockets + if options[:skip_sprockets] + remove_file 'config/initializers/assets.rb' + end + end + def finish_template build(:leftovers) end - public_task :run_bundle - public_task :replay_template + public_task :apply_rails_template, :run_bundle public_task :generate_spring_binstubs + def run_after_bundle_callbacks + @after_bundle_callbacks.each do |callback| + callback.call + end + end + protected def self.banner diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile index 68bd62d4b1..5961f7515c 100644 --- a/railties/lib/rails/generators/rails/app/templates/Gemfile +++ b/railties/lib/rails/generators/rails/app/templates/Gemfile @@ -1,35 +1,46 @@ source 'https://rubygems.org' -<% max_width = gemfile_entries.map { |g| g.name.length }.max -%> <% gemfile_entries.each do |gem| -%> <% if gem.comment -%> # <%= gem.comment %> <% end -%> -<%= gem.commented_out ? '# ' : '' %>gem '<%= gem.name %>'<% if gem.version -%> -, '<%= gem.version %>' -<% elsif gem.options.any? -%> -,<%= gem.padding(max_width) %><%= gem.options.map { |k,v| +<%= gem.commented_out ? '# ' : '' %>gem '<%= gem.name %>'<%= %(, '#{gem.version}') if gem.version -%> +<% if gem.options.any? -%> +, <%= 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 +# Use Unicorn as the app server # gem 'unicorn' # Use Capistrano for deployment # gem 'capistrano-rails', group: :development +group :development, :test do <% unless defined?(JRUBY_VERSION) -%> -# Use debugger -# gem 'debugger', group: [:development, :test] + <%- if RUBY_VERSION < '2.0.0' -%> + # Call 'debugger' anywhere in the code to stop execution and get a debugger console + gem 'debugger' + <%- else -%> + # Call 'byebug' anywhere in the code to stop execution and get a debugger console + gem 'byebug' + <%- end -%> + + # Access an IRB console on exception pages or by using <%%= console %> in views + gem 'web-console', '~> 2.0.0.beta4' +<%- if spring_install? %> + # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring + gem 'spring' +<% end -%> <% end -%> +end -<% if RUBY_PLATFORM.match(/bccwin|cygwin|emx|mingw|mswin|wince/) -%> +<% if RUBY_PLATFORM.match(/bccwin|cygwin|emx|mingw|mswin|wince|java/) -%> # Windows does not include zoneinfo files, so bundle the tzinfo-data gem -gem 'tzinfo-data', platforms: [:mingw, :mswin] +gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] <% end -%> 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/bin/setup b/railties/lib/rails/generators/rails/app/templates/bin/setup new file mode 100644 index 0000000000..0e22b3fa5c --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/bin/setup @@ -0,0 +1,28 @@ +require 'pathname' + +# path to your application root. +APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) + +Dir.chdir APP_ROOT do + # This script is a starting point to setup your application. + # Add necessary setup steps to this file: + + puts "== Installing dependencies ==" + system "gem install bundler --conservative" + system "bundle check || bundle install" + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # system "cp config/database.yml.sample config/database.yml" + # end + + puts "\n== Preparing database ==" + system "bin/rake db:setup" + + puts "\n== Removing old logs and tempfiles ==" + system "rm -f log/*" + system "rm -rf tmp/cache" + + puts "\n== Restarting application server ==" + system "touch tmp/restart.txt" +end diff --git a/railties/lib/rails/generators/rails/app/templates/config/application.rb b/railties/lib/rails/generators/rails/app/templates/config/application.rb index 16fe50bab8..111b680e4b 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/application.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb @@ -5,10 +5,11 @@ require 'rails/all' <% else -%> # Pick the frameworks you want: require "active_model/railtie" +require "active_job/railtie" <%= comment_if :skip_active_record %>require "active_record/railtie" require "action_controller/railtie" require "action_mailer/railtie" -<%= comment_if :skip_action_view %>require "action_view/railtie" +require "action_view/railtie" <%= comment_if :skip_sprockets %>require "sprockets/railtie" <%= comment_if :skip_test_unit %>require "rails/test_unit/railtie" <% end -%> @@ -30,5 +31,10 @@ 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 + <%- unless options.skip_active_record? -%> + + # Do not swallow errors in after_commit/after_rollback callbacks. + config.active_record.raise_in_transactional_callbacks = true + <%- end -%> end end diff --git a/railties/lib/rails/generators/rails/app/templates/config/boot.rb b/railties/lib/rails/generators/rails/app/templates/config/boot.rb index 5e5f0c1fac..6b750f00b1 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/boot.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/boot.rb @@ -1,4 +1,3 @@ -# 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 'bundler/setup' # Set up gems listed in the Gemfile. 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 138e3a8664..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,7 +23,27 @@ test: <<: *default database: <%= app_name %>_test -# Do not keep production credentials in the repository, -# instead read the configuration from the environment. +# 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: - url: <%%= ENV["DATABASE_URL"] %> + <<: *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 2cdb592eeb..187ff01bac 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 @@ -1,7 +1,7 @@ # IBM Dataservers # # Home Page -# http://rubyforge.org/projects/rubyibm/ +# https://github.com/dparnell/ibm_db # # To install the ibm_db gem: # @@ -31,8 +31,6 @@ # Configure Using Gemfile # gem 'ibm_db' # -# For more details on the installation and the connection parameters below, -# please refer to the latest documents at http://rubyforge.org/docman/?group_id=2361 # default: &default adapter: ibm_db @@ -61,7 +59,27 @@ test: <<: *default database: <%= app_name[0,4] %>_tst -# Do not keep production credentials in the repository, -# instead read the configuration from the environment. +# 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: - url: <%%= ENV["DATABASE_URL"] %> + <<: *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/jdbc.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbc.yml index cefd30d519..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 @@ -53,7 +53,16 @@ test: <<: *default url: jdbc:db://localhost/<%= app_name %>_test -# Do not keep production credentials in the repository, -# instead read the configuration from the environment. +# 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: - url: <%%= ENV["DATABASE_URL"] %> + 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 d31761349c..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 -# Do not keep production credentials in the repository, -# instead read the configuration from the environment. -production: <%%= ENV["DATABASE_URL"] %> +# 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 0d248dc197..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 @@ -42,7 +42,27 @@ test: <<: *default database: <%= app_name %>_test -# Do not keep production credentials in the repository, -# instead read the configuration from the environment. +# 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: - url: <%%= ENV["DATABASE_URL"] %> + <<: *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/jdbcsqlite3.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml index 66eba3bf0d..28c36eb82f 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml @@ -18,7 +18,6 @@ test: <<: *default database: db/test.sqlite3 -# Do not keep production credentials in the repository, -# instead read the configuration from the environment. production: - url: <%%= ENV["DATABASE_URL"] %> + <<: *default + database: db/production.sqlite3 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 95a8201437..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,11 +32,27 @@ test: <<: *default database: <%= app_name %>_test -# Avoid production credentials in the repository, -# instead read the configuration from the environment. +# 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. # -# Example: -# mysql2://myuser:mypass@localhost/somedatabase +# 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: - url: <%%= ENV["DATABASE_URL"] %> + <<: *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 d469ec0f99..9aedcc15cb 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 @@ -1,7 +1,7 @@ # Oracle/OCI 8i, 9, 10g # # Requires Ruby/OCI8: -# http://rubyforge.org/projects/ruby-oci8/ +# https://github.com/kubo/ruby-oci8 # # Specify your database using any valid connection syntax, such as a # tnsnames.ora service name, or an SQL connect string of the form: @@ -32,7 +32,27 @@ test: <<: *default database: <%= app_name %>_test -# Do not keep production credentials in the repository, -# instead read the configuration from the environment. +# 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: - url: <%%= ENV["DATABASE_URL"] %> + <<: *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 93f48656b2..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 @@ -59,11 +59,27 @@ test: <<: *default database: <%= app_name %>_test -# Do not keep production credentials in the repository, -# instead read the configuration from the environment. +# 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. # -# Example: -# postgres://myuser:mypass@localhost/somedatabase +# 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: - url: <%%= ENV["DATABASE_URL"] %> + <<: *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/sqlite3.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml index 7312ddb6cd..1c1a37ca8d 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml @@ -20,11 +20,6 @@ test: <<: *default database: db/test.sqlite3 -# Do not keep production credentials in the repository, -# instead read the configuration from the environment. -# -# Example: -# sqlite3://myuser:mypass@localhost/full/path/to/somedatabase -# production: - url: <%%= ENV["DATABASE_URL"] %> + <<: *default + database: db/production.sqlite3 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 aa960e493e..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,7 +42,27 @@ test: <<: *default database: <%= app_name %>_test -# Do not keep production credentials in the repository, -# instead read the configuration from the environment. +# 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: - url: <%%= ENV["DATABASE_URL"] %> + <<: *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 cce4743a33..d8326d1728 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 @@ -30,9 +30,16 @@ Rails.application.configure do # number of complex assets. config.assets.debug = true + # Asset digests allow you to set far-future HTTP expiration dates on all assets, + # yet still be able to expire them through the digest params. + config.assets.digest = true + # Adds additional error checking when serving assets at runtime. # Checks for improperly declared sprockets dependencies. # Raises helpful error messages. config.assets.raise_runtime_errors = true <%- end -%> + + # Raises error for missing translations + # 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 3baa382bd6..92ff0de030 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 @@ -16,10 +16,11 @@ Rails.application.configure do # Enable Rack::Cache to put a simple HTTP cache in front of your application # Add `rack-cache` to your Gemfile before enabling this. - # For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid. + # For large-scale production use, consider using a caching reverse proxy like + # NGINX, varnish or squid. # config.action_dispatch.rack_cache = true - # Disable Rails's static asset server (Apache or nginx will already do this). + # Disable Rails's static asset server (Apache or NGINX will already do this). config.serve_static_assets = false <%- unless options.skip_sprockets? -%> @@ -30,22 +31,22 @@ Rails.application.configure do # Do not fallback to assets pipeline if a precompiled asset is missed. config.assets.compile = false - # Generate digests for assets URLs. + # Asset digests allow you to set far-future HTTP expiration dates on all assets, + # yet still be able to expire them through the digest params. config.assets.digest = true - # Version of your assets, change this if you want to expire all your assets. - config.assets.version = '1.0' + # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb <%- end -%> # Specifies the header that your server uses for sending files. - # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache - # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx + # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache + # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # config.force_ssl = true - # Set to :debug to see everything in the log. - config.log_level = :info + # Decrease the log volume. + # config.log_level = :info # Prepend all log lines with the following tags. # config.log_tags = [ :subdomain, :uuid ] @@ -57,13 +58,7 @@ Rails.application.configure do # config.cache_store = :mem_cache_store # 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 -%> + # config.action_controller.asset_host = 'http://assets.example.com' # 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. @@ -76,9 +71,11 @@ Rails.application.configure do # Send deprecation notices to registered listeners. config.active_support.deprecation = :notify - # Disable automatic flushing of the log to improve performance. - # config.autoflush_log = false - # 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..32756eb88b 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 @@ -31,6 +31,12 @@ Rails.application.configure do # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test + # Randomize the order test cases are executed + config.active_support.test_order = :random + # 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/assets.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt new file mode 100644 index 0000000000..01ef3e6630 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt @@ -0,0 +1,11 @@ +# Be sure to restart your server when you modify this file. + +# Version of your assets, change this if you want to expire all your assets. +Rails.application.config.assets.version = '1.0' + +# Add additional assets to the asset load path +# Rails.application.config.assets.paths << Emoji.images_path + +# Precompile additional assets. +# application.js, application.css, and all non-JS/CSS in app/assets folder are already added. +# Rails.application.config.assets.precompile += %w( search.js ) 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/secrets.yml b/railties/lib/rails/generators/rails/app/templates/config/secrets.yml index 6e2c45e119..b2669a0f79 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/secrets.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/secrets.yml @@ -19,4 +19,4 @@ test: # Do not keep production secrets in the repository, # instead read values from the environment. production: - secret_key_base: <%%= ENV["RAILS_SECRET_KEY_BASE"] %> + 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/test/test_helper.rb b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb index 4ade1a0bdc..87b8fe3516 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,13 +1,10 @@ -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] -%> # 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 - # -- they do not yet inherit this setting fixtures :all <% end -%> diff --git a/railties/lib/rails/generators/rails/controller/USAGE b/railties/lib/rails/generators/rails/controller/USAGE index de33900e0a..64239ad599 100644 --- a/railties/lib/rails/generators/rails/controller/USAGE +++ b/railties/lib/rails/generators/rails/controller/USAGE @@ -16,4 +16,3 @@ Example: Test: test/controllers/credit_cards_controller_test.rb Views: app/views/credit_cards/debit.html.erb [...] Helper: app/helpers/credit_cards_helper.rb - Test: test/helpers/credit_cards_helper_test.rb diff --git a/railties/lib/rails/generators/rails/controller/controller_generator.rb b/railties/lib/rails/generators/rails/controller/controller_generator.rb index ef84447df9..df615c88b5 100644 --- a/railties/lib/rails/generators/rails/controller/controller_generator.rb +++ b/railties/lib/rails/generators/rails/controller/controller_generator.rb @@ -2,6 +2,8 @@ module Rails module Generators class ControllerGenerator < NamedBase # :nodoc: argument :actions, type: :array, default: [], banner: "action action" + class_option :skip_routes, type: :boolean, desc: "Don't add routes to config/routes.rb." + check_class_collision suffix: "Controller" def create_controller_files @@ -9,8 +11,10 @@ module Rails end def add_routes - actions.reverse.each do |action| - route generate_routing_code(action) + unless options[:skip_routes] + actions.reverse_each do |action| + route generate_routing_code(action) + end end end @@ -23,21 +27,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/helper/USAGE b/railties/lib/rails/generators/rails/helper/USAGE index 30e323a858..8855ef3b01 100644 --- a/railties/lib/rails/generators/rails/helper/USAGE +++ b/railties/lib/rails/generators/rails/helper/USAGE @@ -5,13 +5,9 @@ Description: To create a helper within a module, specify the helper name as a path like 'parent_module/helper_name'. - This generates a helper class in app/helpers and invokes the configured - test framework. - Example: `rails generate helper CreditCard` Credit card helper. Helper: app/helpers/credit_card_helper.rb - Test: test/helpers/credit_card_helper_test.rb diff --git a/railties/lib/rails/generators/rails/model/USAGE b/railties/lib/rails/generators/rails/model/USAGE index 833b7beb7f..8c3b63c3b4 100644 --- a/railties/lib/rails/generators/rails/model/USAGE +++ b/railties/lib/rails/generators/rails/model/USAGE @@ -6,6 +6,11 @@ Description: model's attributes. Timestamps are added by default, so you don't have to specify them by hand as 'created_at:datetime updated_at:datetime'. + As a special case, specifying 'password:digest' will generate a + password_digest field of string type, and configure your generated model and + tests for use with ActiveModel has_secure_password (assuming the default ORM + and test framework are being used). + You don't have to think up every attribute up front, but it helps to sketch out a few so you can start working with the model immediately. @@ -27,7 +32,8 @@ Available field types: `rails generate model post title:string body:text` will generate a title column with a varchar type and a body column with a text - type. You can use the following types: + type. If no type is specified the string type will be used by default. + You can use the following types: integer primary_key @@ -40,7 +46,6 @@ Available field types: date time datetime - timestamp You can also consider `references` as a kind of type. For instance, if you run: @@ -73,6 +78,10 @@ Available field types: `rails generate model user username:string{30}:uniq` `rails generate model product supplier:references{polymorphic}:index` + If you require a `password_digest` string column for use with + has_secure_password, you should specify `password:digest`: + + `rails generate model user password:digest` Examples: `rails generate model account` 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..584f776c01 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 @@ -291,6 +288,10 @@ task default: :test options[:mountable] end + def skip_git? + options[:skip_git] + end + def with_dummy_app? options[:skip_test_unit].blank? || options[:dummy_path] != 'test/dummy' end @@ -307,6 +308,24 @@ task default: :test @camelized ||= name.gsub(/\W/, '_').squeeze('_').camelize end + def author + default = "TODO: Write your name" + if skip_git? + @author = default + else + @author = `git config user.name`.chomp rescue default + end + end + + def email + default = "TODO: Write your email address" + if skip_git? + @email = default + else + @email = `git config user.email`.chomp rescue default + end + end + def valid_const? if original_name =~ /[^0-9a-zA-Z_]+/ raise Error, "Invalid plugin name #{original_name}. Please give a name which use only alphabetic or numeric or \"_\" characters." diff --git a/railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec b/railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec index 5fdf0e1554..919c349470 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec +++ b/railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec @@ -7,8 +7,8 @@ require "<%= name %>/version" Gem::Specification.new do |s| s.name = "<%= name %>" s.version = <%= camelized %>::VERSION - s.authors = ["TODO: Your name"] - s.email = ["TODO: Your email"] + s.authors = ["<%= author %>"] + s.email = ["<%= email %>"] s.homepage = "TODO" s.summary = "TODO: Summary of <%= camelized %>." s.description = "TODO: Description of <%= camelized %>." diff --git a/railties/lib/rails/generators/rails/plugin/templates/Gemfile b/railties/lib/rails/generators/rails/plugin/templates/Gemfile index 88ec4e6354..35ad9fbf9e 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/Gemfile +++ b/railties/lib/rails/generators/rails/plugin/templates/Gemfile @@ -1,7 +1,7 @@ -source "https://rubygems.org" +source 'https://rubygems.org' <% if options[:skip_gemspec] -%> -<%= '# ' if options.dev? || options.edge? -%>gem "rails", "~> <%= Rails::VERSION::STRING %>" +<%= '# ' if options.dev? || options.edge? -%>gem 'rails', '~> <%= Rails::VERSION::STRING %>' <% else -%> # Declare your gem's dependencies in <%= name %>.gemspec. # Bundler will treat runtime dependencies like base dependencies, and @@ -11,7 +11,7 @@ gemspec <% if options[:skip_gemspec] -%> group :development do - gem "<%= gem_for_database %>" + gem '<%= gem_for_database %>' end <% else -%> # Declare any dependencies that are still in development here instead of in @@ -29,17 +29,19 @@ end # <%= gem.comment %> <% end -%> -<%= gem.commented_out ? '# ' : '' %>gem '<%= gem.name %>'<% if gem.version -%> -, '<%= gem.version %>' -<% elsif gem.options.any? -%> -,<%= gem.padding(max_width) %><%= gem.options.map { |k,v| +<%= gem.commented_out ? '# ' : '' %>gem '<%= gem.name %>'<%= %(, '#{gem.version}') if gem.version -%> +<% if gem.options.any? -%> +, <%= gem.options.map { |k,v| "#{k}: #{v.inspect}" }.join(', ') %> -<% else %> <% end -%> <% end -%> <% end -%> <% unless defined?(JRUBY_VERSION) -%> -# To use debugger -# gem 'debugger' +# To use a debugger + <%- if RUBY_VERSION < '2.0.0' -%> +# gem 'debugger', group: [:development, :test] + <%- else -%> +# gem 'byebug', group: [:development, :test] + <%- end -%> <% end -%> diff --git a/railties/lib/rails/generators/rails/plugin/templates/MIT-LICENSE b/railties/lib/rails/generators/rails/plugin/templates/MIT-LICENSE index d7a9109894..ff2fb3ba4e 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/MIT-LICENSE +++ b/railties/lib/rails/generators/rails/plugin/templates/MIT-LICENSE @@ -1,4 +1,4 @@ -Copyright <%= Date.today.year %> YOURNAME +Copyright <%= Date.today.year %> <%= author %> 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/generators/rails/plugin/templates/Rakefile b/railties/lib/rails/generators/rails/plugin/templates/Rakefile index 0ba899176c..c338a0bdb1 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/Rakefile +++ b/railties/lib/rails/generators/rails/plugin/templates/Rakefile @@ -19,6 +19,10 @@ APP_RAKEFILE = File.expand_path("../<%= dummy_path -%>/Rakefile", __FILE__) load 'rails/tasks/engine.rake' <% end %> +<% if engine? -%> +load 'rails/tasks/statistics.rake' +<% end %> + <% unless options[:skip_gemspec] -%> Bundler::GemHelper.install_tasks 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/plugin/templates/rails/application.rb b/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb index 5508829f6b..b2aa82344a 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb @@ -7,7 +7,7 @@ require 'rails/all' <%= comment_if :skip_active_record %>require "active_record/railtie" require "action_controller/railtie" require "action_mailer/railtie" -<%= comment_if :skip_action_view %>require "action_view/railtie" +require "action_view/railtie" <%= comment_if :skip_sprockets %>require "sprockets/railtie" <%= comment_if :skip_test_unit %>require "rails/test_unit/railtie" <% end -%> diff --git a/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb index 1e26a313cd..d492e68357 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb @@ -1,7 +1,13 @@ # Configure Rails Environment ENV["RAILS_ENV"] = "test" -require File.expand_path("../dummy/config/environment.rb", __FILE__) +require File.expand_path("../../<%= options[:dummy_path] -%>/config/environment.rb", __FILE__) +<% unless options[:skip_active_record] -%> +ActiveRecord::Migrator.migrations_paths = [File.expand_path("../../<%= options[:dummy_path] -%>/db/migrate", __FILE__)] +<% if options[:mountable] -%> +ActiveRecord::Migrator.migrations_paths << File.expand_path('../../db/migrate', __FILE__) +<% end -%> +<% end -%> require "rails/test_help" Rails.backtrace_cleaner.remove_silencers! @@ -10,6 +16,6 @@ Rails.backtrace_cleaner.remove_silencers! Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f } # Load fixtures from the engine -if ActiveSupport::TestCase.method_defined?(:fixture_path=) +if ActiveSupport::TestCase.respond_to?(:fixture_path=) ActiveSupport::TestCase.fixture_path = File.expand_path("../fixtures", __FILE__) end diff --git a/railties/lib/rails/generators/rails/scaffold/USAGE b/railties/lib/rails/generators/rails/scaffold/USAGE index 4a3eb2c7c7..1b2a944103 100644 --- a/railties/lib/rails/generators/rails/scaffold/USAGE +++ b/railties/lib/rails/generators/rails/scaffold/USAGE @@ -9,11 +9,16 @@ Description: Attributes are field arguments specifying the model's attributes. You can optionally pass the type and an index to each field. For instance: - "title body:text tracking_id:integer:uniq" will generate a title field of + 'title body:text tracking_id:integer:uniq' will generate a title field of string type, a body with text type and a tracking_id as an integer with an unique index. "index" could also be given instead of "uniq" if one desires a non unique index. + As a special case, specifying 'password:digest' will generate a + password_digest field of string type, and configure your generated model, + controller, views, and test suite for use with ActiveModel + has_secure_password (assuming they are using Rails defaults). + Timestamps are added by default, so you don't have to specify them by hand as 'created_at:datetime updated_at:datetime'. @@ -33,3 +38,4 @@ Examples: `rails generate scaffold post` `rails generate scaffold post title body:text published:boolean` `rails generate scaffold purchase amount:decimal tracking_id:integer:uniq` + `rails generate scaffold user email:uniq password:digest` diff --git a/railties/lib/rails/generators/rails/scaffold_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/helper/helper_generator.rb b/railties/lib/rails/generators/test_unit/helper/helper_generator.rb index 0db76f9eaf..bde4e88915 100644 --- a/railties/lib/rails/generators/test_unit/helper/helper_generator.rb +++ b/railties/lib/rails/generators/test_unit/helper/helper_generator.rb @@ -3,11 +3,7 @@ require 'rails/generators/test_unit' module TestUnit # :nodoc: module Generators # :nodoc: class HelperGenerator < Base # :nodoc: - check_class_collision suffix: "HelperTest" - - def create_helper_files - template 'helper_test.rb', File.join('test/helpers', class_path, "#{file_name}_helper_test.rb") - end + # Rails does not generate anything here. end end end diff --git a/railties/lib/rails/generators/test_unit/helper/templates/helper_test.rb b/railties/lib/rails/generators/test_unit/helper/templates/helper_test.rb deleted file mode 100644 index 7d37bda0f9..0000000000 --- a/railties/lib/rails/generators/test_unit/helper/templates/helper_test.rb +++ /dev/null @@ -1,6 +0,0 @@ -require 'test_helper' - -<% module_namespacing do -%> -class <%= class_name %>HelperTest < ActionView::TestCase -end -<% end -%> diff --git a/railties/lib/rails/generators/test_unit/job/job_generator.rb b/railties/lib/rails/generators/test_unit/job/job_generator.rb new file mode 100644 index 0000000000..566b61ca66 --- /dev/null +++ b/railties/lib/rails/generators/test_unit/job/job_generator.rb @@ -0,0 +1,13 @@ +require 'rails/generators/test_unit' + +module TestUnit # :nodoc: + module Generators # :nodoc: + class JobGenerator < Base # :nodoc: + check_class_collision suffix: 'JobTest' + + def create_test_file + template 'unit_test.rb.erb', File.join('test/jobs', class_path, "#{file_name}_job_test.rb") + end + end + end +end diff --git a/railties/lib/rails/generators/test_unit/job/templates/unit_test.rb.erb b/railties/lib/rails/generators/test_unit/job/templates/unit_test.rb.erb new file mode 100644 index 0000000000..f5351d0ec6 --- /dev/null +++ b/railties/lib/rails/generators/test_unit/job/templates/unit_test.rb.erb @@ -0,0 +1,9 @@ +require 'test_helper' + +<% module_namespacing do -%> +class <%= class_name %>JobTest < ActiveJob::TestCase + # test "the truth" do + # assert true + # end +end +<% end -%> diff --git a/railties/lib/rails/generators/testing/assertions.rb b/railties/lib/rails/generators/testing/assertions.rb index 2e877f8762..bd069e4bd0 100644 --- a/railties/lib/rails/generators/testing/assertions.rb +++ b/railties/lib/rails/generators/testing/assertions.rb @@ -1,3 +1,5 @@ +require 'shellwords' + module Rails module Generators module Testing diff --git a/railties/lib/rails/generators/testing/behaviour.rb b/railties/lib/rails/generators/testing/behaviour.rb index 8e9028a3fb..fd2ea274e1 100644 --- a/railties/lib/rails/generators/testing/behaviour.rb +++ b/railties/lib/rails/generators/testing/behaviour.rb @@ -50,7 +50,7 @@ module Rails # class AppGeneratorTest < Rails::Generators::TestCase # tests AppGenerator # destination File.expand_path("../tmp", File.dirname(__FILE__)) - # teardown :cleanup_destination_root + # setup :prepare_destination # # test "database.yml is not created when skipping Active Record" do # run_generator %w(myapp --skip-active-record) @@ -61,11 +61,9 @@ module Rails # You can provide a configuration hash as second argument. This method returns the output # printed by the generator. def run_generator(args=self.default_arguments, config={}) - without_thor_debug do - capture(:stdout) do - args += ['--skip-bundle'] unless args.include? '--dev' - self.generator_class.start(args, config.reverse_merge(destination_root: destination_root)) - end + capture(:stdout) do + args += ['--skip-bundle'] unless args.include? '--dev' + self.generator_class.start(args, config.reverse_merge(destination_root: destination_root)) end end @@ -103,12 +101,21 @@ module Rails Dir.glob("#{dirname}/[0-9]*_*.rb").grep(/\d+_#{file_name}.rb$/).first end - # TODO: remove this once Bundler 1.5.2 is released - def without_thor_debug # :nodoc: - thor_debug, ENV['THOR_DEBUG'] = ENV['THOR_DEBUG'], nil + def capture(stream) + stream = stream.to_s + captured_stream = Tempfile.new(stream) + stream_io = eval("$#{stream}") + origin_stream = stream_io.dup + stream_io.reopen(captured_stream) + yield + + stream_io.rewind + return captured_stream.read ensure - ENV['THOR_DEBUG'] = thor_debug + captured_stream.close + captured_stream.unlink + stream_io.reopen(origin_stream) end end end diff --git a/railties/lib/rails/info.rb b/railties/lib/rails/info.rb index edadeaca0e..357aebf584 100644 --- a/railties/lib/rails/info.rb +++ b/railties/lib/rails/info.rb @@ -22,17 +22,6 @@ module Rails rescue Exception end - def frameworks - %w( active_record action_pack action_view action_mailer active_support ) - end - - def framework_version(framework) - if Object.const_defined?(framework.classify) - require "#{framework}/version" - framework.classify.constantize.version.to_s - end - end - def to_s column_width = properties.names.map {|name| name.length}.max info = properties.map do |name, value| @@ -61,6 +50,11 @@ module Rails end end + # The Rails version. + property 'Rails version' do + Rails.version.to_s + end + # The Ruby version and platform, e.g. "2.0.0-p247 (x86_64-darwin12.4.0)". property 'Ruby version' do "#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL} (#{RUBY_PLATFORM})" @@ -75,23 +69,10 @@ module Rails ::Rack.release end - # The Rails version. - property 'Rails version' do - Rails.version.to_s - end - property 'JavaScript Runtime' do ExecJS.runtime.name end - # Versions of each Rails framework (Active Record, Action Pack, - # Action Mailer, and Active Support). - frameworks.each do |framework| - property "#{framework.titlecase} version" do - framework_version(framework) - end - end - property 'Middleware' do Rails.configuration.middleware.map(&:inspect) end diff --git a/railties/lib/rails/info_controller.rb b/railties/lib/rails/info_controller.rb index 908c4ce65e..49e5431a16 100644 --- a/railties/lib/rails/info_controller.rb +++ b/railties/lib/rails/info_controller.rb @@ -5,7 +5,7 @@ class Rails::InfoController < Rails::ApplicationController # :nodoc: prepend_view_path ActionDispatch::DebugExceptions::RESCUES_TEMPLATE_PATH layout -> { request.xhr? ? false : 'application' } - before_filter :require_local! + before_action :require_local! def index redirect_to action: :routes diff --git a/railties/lib/rails/mailers_controller.rb b/railties/lib/rails/mailers_controller.rb index dd318f52e5..32740d66da 100644 --- a/railties/lib/rails/mailers_controller.rb +++ b/railties/lib/rails/mailers_controller.rb @@ -3,8 +3,8 @@ 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 + before_action :require_local! + before_action :find_preview, only: :preview def index @previews = ActionMailer::Preview.all @@ -70,4 +70,4 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc: @email end end -end
\ No newline at end of file +end diff --git a/railties/lib/rails/paths.rb b/railties/lib/rails/paths.rb index 117bb37487..3eb66c07af 100644 --- a/railties/lib/rails/paths.rb +++ b/railties/lib/rails/paths.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/rack.rb b/railties/lib/rails/rack.rb index d1ee96f7fd..886f0e52e1 100644 --- a/railties/lib/rails/rack.rb +++ b/railties/lib/rails/rack.rb @@ -1,6 +1,6 @@ module Rails module Rack - autoload :Debugger, "rails/rack/debugger" + autoload :Debugger, "rails/rack/debugger" if RUBY_VERSION < '2.0.0' autoload :Logger, "rails/rack/logger" autoload :LogTailer, "rails/rack/log_tailer" end diff --git a/railties/lib/rails/rack/log_tailer.rb b/railties/lib/rails/rack/log_tailer.rb index 50d0eb96fc..46517713c9 100644 --- a/railties/lib/rails/rack/log_tailer.rb +++ b/railties/lib/rails/rack/log_tailer.rb @@ -1,7 +1,11 @@ +require 'active_support/deprecation' + module Rails module Rack class LogTailer def initialize(app, log = nil) + ActiveSupport::Deprecation.warn('LogTailer is deprecated and will be removed on Rails 5.') + @app = app path = Pathname.new(log || "#{::File.expand_path(Rails.root)}/log/#{Rails.env}.log").cleanpath diff --git a/railties/lib/rails/rack/logger.rb b/railties/lib/rails/rack/logger.rb index 3b35798679..9962e6d943 100644 --- a/railties/lib/rails/rack/logger.rb +++ b/railties/lib/rails/rack/logger.rb @@ -34,7 +34,7 @@ module Rails instrumenter = ActiveSupport::Notifications.instrumenter instrumenter.start 'request.action_dispatch', request: request - logger.info started_request_message(request) + logger.info { started_request_message(request) } resp = @app.call(env) resp[2] = ::Rack::BodyProxy.new(resp[2]) { finish(request) } resp diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb index c63e0c0758..2b33beaa2b 100644 --- a/railties/lib/rails/railtie.rb +++ b/railties/lib/rails/railtie.rb @@ -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/ruby_version_check.rb b/railties/lib/rails/ruby_version_check.rb index 3b7f358a5b..df74643a59 100644 --- a/railties/lib/rails/ruby_version_check.rb +++ b/railties/lib/rails/ruby_version_check.rb @@ -2,7 +2,7 @@ if RUBY_VERSION < '1.9.3' desc = defined?(RUBY_DESCRIPTION) ? RUBY_DESCRIPTION : "ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE})" abort <<-end_message - Rails 4 prefers to run on Ruby 2.0. + Rails 4 prefers to run on Ruby 2.1 or newer. You're running #{desc} diff --git a/railties/lib/rails/rubyprof_ext.rb b/railties/lib/rails/rubyprof_ext.rb deleted file mode 100644 index 017eba3a76..0000000000 --- a/railties/lib/rails/rubyprof_ext.rb +++ /dev/null @@ -1,35 +0,0 @@ -require 'prof' - -module Prof #:nodoc: - # Adapted from Shugo Maeda's unprof.rb - def self.print_profile(results, io = $stderr) - total = results.detect { |i| - i.method_class.nil? && i.method_id == :"#toplevel" - }.total_time - total = 0.001 if total < 0.001 - - io.puts " %% cumulative self self total" - io.puts " time seconds seconds calls ms/call ms/call name" - - sum = 0.0 - results.each do |r| - sum += r.self_time - - name = if r.method_class.nil? - r.method_id.to_s - elsif r.method_class.is_a?(Class) - "#{r.method_class}##{r.method_id}" - else - "#{r.method_class}.#{r.method_id}" - end - io.printf "%6.2f %8.3f %8.3f %8d %8.2f %8.2f %s\n", - r.self_time / total * 100, - sum, - r.self_time, - r.count, - r.self_time * 1000 / r.count, - r.total_time * 1000 / r.count, - name - end - end -end diff --git a/railties/lib/rails/source_annotation_extractor.rb b/railties/lib/rails/source_annotation_extractor.rb index 3cf6a005ea..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. @@ -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..a1c805f8aa 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+\-\.]*://} @@ -55,7 +55,7 @@ namespace :rails do # desc "Update config/boot.rb from your current rails install" task :configs do invoke_from_app_generator :create_boot_file - invoke_from_app_generator :create_config_files + invoke_from_app_generator :update_config_files end # desc "Adds new executables to the application bin/ directory" diff --git a/railties/lib/rails/tasks/statistics.rake b/railties/lib/rails/tasks/statistics.rake index c1674c72ad..b94cd244be 100644 --- a/railties/lib/rails/tasks/statistics.rake +++ b/railties/lib/rails/tasks/statistics.rake @@ -1,6 +1,10 @@ +# while having global constant is not good, +# many 3rd party tools depend on it, like rspec-rails, cucumber-rails, etc +# so if will be removed - deprecation warning is needed STATS_DIRECTORIES = [ %w(Controllers app/controllers), %w(Helpers app/helpers), + %w(Jobs app/jobs), %w(Models app/models), %w(Mailers app/mailers), %w(Javascripts app/assets/javascripts), @@ -13,9 +17,11 @@ STATS_DIRECTORIES = [ %w(Integration\ tests test/integration), %w(Functional\ tests\ (old) test/functional), %w(Unit\ tests \ (old) test/unit) -].collect { |name, dir| [ name, "#{Rails.root}/#{dir}" ] }.select { |name, dir| File.directory?(dir) } +].collect do |name, dir| + [ name, "#{File.dirname(Rake.application.rakefile_location)}/#{dir}" ] +end.select { |name, dir| File.directory?(dir) } -desc "Report code statistics (KLOCs, etc) from the application" +desc "Report code statistics (KLOCs, etc) from the application or engine" task :stats do require 'rails/code_statistics' CodeStatistics.new(*STATS_DIRECTORIES).to_s diff --git a/railties/lib/rails/templates/rails/mailers/email.html.erb b/railties/lib/rails/templates/rails/mailers/email.html.erb index 977feb922b..0b08a01896 100644 --- a/railties/lib/rails/templates/rails/mailers/email.html.erb +++ b/railties/lib/rails/templates/rails/mailers/email.html.erb @@ -2,6 +2,14 @@ <html><head> <meta name="viewport" content="width=device-width" /> <style type="text/css"> + html, body, iframe { + height: 100%; + } + + body { + margin: 0; + } + header { width: 100%; padding: 10px 0 0 0; @@ -34,7 +42,6 @@ iframe { border: 0; width: 100%; - height: 800px; } </style> </head> @@ -95,4 +102,4 @@ <iframe seamless name="messageBody" src="?part=<%= Rack::Utils.escape(@part.mime_type) %>"></iframe> </body> -</html>
\ No newline at end of file +</html> diff --git a/railties/lib/rails/templates/rails/welcome/index.html.erb b/railties/lib/rails/templates/rails/welcome/index.html.erb index eb620caa00..89792066d5 100644 --- a/railties/lib/rails/templates/rails/welcome/index.html.erb +++ b/railties/lib/rails/templates/rails/welcome/index.html.erb @@ -19,13 +19,13 @@ } a {color: #03c} + a:hover { background-color: #03c; color: white; text-decoration: none; } - #page { background-color: #f0f0f0; width: 750px; @@ -57,21 +57,21 @@ padding-right: 30px; } - #header { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAABACAYAAABY1SR7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAGZhJREFUeNqsWwmUXGWV/t5Sr9aurl6qO0l3Z9/DEoJh18gZQGAUxPHIyQHH7eioZ8bjnAFHZ0RndNxxRBhGcUbxoKIHBkTEcUYREIHIGpKQjUDS6U660/tSVV3Lq/fefPf/Xy2dBFGYx3npqvde/e/e/97v3u/e/8e4Lt2L8DCCAFcGwF8ZBjYbgM1rAZoO+WLwZhDMu9y4+YcOozbAqzwXNA3GdzX/5hV+KnKO2+GXFj/AvzmW8e72iG202CYiphbY403f9/k3QHZtJ9oWtyCQe7wGX79TKVb7rP9pXJPDVxf0Rz+oyxm4HNWrahFNixdk3EAJbERMWOm4ulctVODNVeEVK0DeRVDgb1wfJgcqUo6duaKnFOH7bm6JmH+5LOEgZprwRIHAV3JYfLjKM55Noz3bBqdcgt0Wg52Kq/cHHkXns0qIukKBlltk9rU2QaiouiefPQ+RdBuseAJeqYTK1CTH8mE4NsyIpRWu8nssCs+xULWpjGVwTvieKl/sV6mIXzOib/OftzuG8d6l8SiVMODyRb46oazg8YPP2Wnvy9ISNqplzsxYAW6hjGhHEmYiBoPC+hRMfFMrESgrBC5n0KS+lq1nPahZh2OXymg9bSNWX/u3FKyKI//7Exx96B4Y8RiCEseq8t0VznyxjMDidFIJ8QSf3hJEOFbZEAHVhIkFTX54fxtnIW5pJUQIeZ8ooZShkInuDOLpFIX1ldtCBix7KI/k4E7OwbTjcNIdiCQzsONp2LEk7GgUnZsuQN9lW2En45xlukrUghWzeZq8FsXsi8+gND6MSCqD9k3nwulIUShKZxt0LYPWortRSY0NXreC8J6pZNDChEDh53PT1NIPLaEnLbQKNTETEaR7sycA0jD1INXZAnzObjTbiWh7Vr1A3Knn4nciu+lCvstUig09cp96cVCtcELoFpEIFUjjyIM/osWIg+IMXS3DcfNwZ3NQHmmKU9OqroX2jWdgatduuPkpmA4ViZrK9RqKABEBtg9tDeW+oUIyTIYuFaX7eCG4aqbU+hhKocD3UBoZISBLiC9cpAQKyq5SQo6OjVswtec5VHLTiHUuIN4WonXlqUj2riS0DIUXwZlERFHSK+SQGzqI3MHdmNm7CzMvvowF527B8qvejZ3/+iXk9vVTao5tiTKN0OUHISZEGS/8W6UbRdoTSHe3E1f+CRaR3xhBLVJSIQ7qleZQGBigZYoYdR+ElUjBaW3H6JMPIrV0Hdo2bEayZ7my0KsdLctPBS64EuWZMYw/9wTGnvod0mtzWH71Vuz66o10bVpK8FIx6orUMejpCKYBTvfM9HXBJtA8z3/1BKDivaksVJmaYsgsYPDnd6LzzAuw8I1XUIGleC1HtDWLnguv5BiX4+jDD2D4sQeV1bQvNXBi6vAb1MGtrEEHjRPgqfZ0qMRJElYYSudfq12nmzAvtJ2yib69iRadRGnySD0Uv5bDtCPou/gqnPY3N6DnLRczgtHxCf4aVnUeUdgw6i6FqM1w292Ujo/TJdB5wHcJ2iDCaBTRmVfw4rkw4yksuvQyJJf0YvrgNiayvBLESS9AYuFqJLLLCPb4SQWulosojhxmeCeoDeaQSoVuy8lPtSKxYKnC2Bmf+DwtvBgv3/qfTI6uEtGuJV7PCBTIq5zNtt5uxBgyvap30pf55TISfX1Y/PatGPrVvcgPvEyAJ1GenaPZLSy//G2IL+qki43CNCMwk620iovy9FGUJgYwm8gwpK/guRJOS5dyD688h+n9z2L28F4Ujx2ia04jEl8Ad3oGVTePaGcnQ3sKLb1rkD3nIqx594dRIh733n6PmmrrvGj671sjVlxczRWAkxZ0r+rTrhfMJ0uEM8xKUYXONR+5nr57BdpP24TCsX6M/f5F5AYLWPauK9F11htUwjOIL8GNZH1qpKwiyVGELk0OoDj2EtziFOaODSN3aC/v24xmZzAU51TgcJKd/DktHo9jyRXvg0Or7PvejTj22KPKiyafew6zg8MYypVLNsLkJ2bxaZXM4i5EmCBPsEaoWJUUpfeSK7DgvEtQmh4ihTDQdf5FOHDHr7HqPVeh99KL4OVzpE50N18CtqnCdBCY6rsEcTsqIGUGD6rY9e3bMPzIHmTWLsbqa7ai84wL6YrTqEyOqEmwonEExSoO//R7dLcJWiWCueF+7P7mjZAUY8YdJZqySMo24j5zQSybQdeyhdrX5imho4NhEEnkRbkDQyjSRVJLeziCgef/6avIrFuOtR95P2lJNSSshg4l6rdm+Ht9inWsqIOX7voN+u/eRoEM5PvHMbbjGcwcfg7jO3YxbCcRiaaYQOXnpEaFGeahGQaMCidJRidt8RghS6Q344XQIowmFq2QXdLNdwsx8zUFqCOQNIECVqdp8pESB53Fvhdux9T2FxBb1AWX4XbjDX/HFzjEmgedB4XYKT5D4T0VTLRCtIiTwOBvfovpvS8T+Bm4MyW6jw13tIIDt/9G/TTWk8HKvzgbmd4+YldYQIdixgHJYkC82Ul6UDnQSbEGdsFGZlEWyUyLyiEyYwajRVAoAXNlEjR+pjUCUmiDQcKOORwwgpFfP4cg5mPzTZ9FoqePdGVWuZRPYQNPcgrd0/dCpqpdy3DIsQ4fxtiTu7Hxkx8iRXkcB+94iM86/K0Jx4opi5aOzGJs14toWeLAdYXWxFQCtJlkA+LUq+bI7QR3mj3YoqVNgGcXd5NWUOiZAk9GH86S4jK25jWBLVREl1uK5Voywz6WXf1WLHjTm0lPigSyxoUpnEqU8c26Wyk/Y24RMjhw/yMoj+cQbWvH0isuwuijL6BwaJwcyq7XUTaBP7N3HOU3ke7HSONJb8RTBGoGKZPFyTE8saTZyCPtrC2coxOoTuY5+x4UTzHNsNjR6d6Qa8JJ5BIV8ksVtKzpwcr3v5dyOrzHKMWXizsZAnK6k1ImPDmAqjOmdr9AwXcodzr4kwfQfuY6VKbzyhpGU96S75WxIqb2DaPnvNWKklQD4WSuzB+sVILjOYjm/VARSWKTBQQzlZCFmErYeubzVJJR14SlQtVQMjO0xrXvoulXkq3OKnxAXqSsoSmNUbOM/BV35RjDDz9JrBXpnnEM3vsYjj38LLyZihI8QNAgQhITOCmTO46i+6w1MPm86RVIiC09/RJUGcECCe2UU0G6QIyUjEC5hGaCNd4RqHKU6VuDylQlI2N8hfXDWibEdyhCKXREuZUVUX8lyhh2+Jl5Q/6akSgT4izGn3wBFu+JwYOKj8qwtsbJaYmJuYEZ5AYmFOWXPCN1jTodzeuqM0WtSI1rzXrV0LSNKRFuZLYQ2EYVPjEQVuQUMsCya65GvL1HWUwJS+FNUcBsUiZUQv7aLGlndr+I8ug4XUMVAJw4U7FmI8SFETTmUaGK2gas1SeeP8znoizIEso9DaUIy2FWkNU5V0VYs/azWXKncuCHqgQq1CHiY831H8TGr34erRvXKdD6LD3b+HnRn12qGgdqlmxHZe2aRcy6NbQScl8y8dSOfWQE1yK9YYmqXYww3xhNObemUI2IWraF2d1HMTeeh83MbkUiylKiiMdy2wjzXBjxWYdRiSkhfDVVKGSstxM9l16JxZe/E2+848c49bPXK9D2vPUyEsBOVZMINmpCW6HgEOuIQjXF6FYuAV2aHsWyrVfj9C9er5SR5Kms0PTf8QoZtIo7WSJW+mmRJLGSpDK2ipzV2bK6X6fxtWOCicYVqyhGXkXn+WeTcfape5ZDsPGM91C5iy8LI0s445bd9FkrAFHICt1N8DE+gdyeQczs34+uzeei68LNLGfdea50st6VbiyYmHq+nxTFRSSRVsD3ii7xyeQbdt/M5h/MERMT4i6GjlAWeUxh6HCN8+LIz+5H5zlUbtHSOnVp4MCa51JaIQ16i0kwP9CP0uExPP+JL2DggfuYN8jTJClYxnH4aNimdpp0r7nDkyx9h5gE0+RqSVTyZXXTsMz5FaJyMJrrGLNopyWUIImj//1LjPzuUZLCC5gzVqMwPIglV7/rxCaihFaCPCDOxDUl1EoylFP4mUlFCgPDStLKWB47PnUjrSSsNqrJsa/zR02ZwGjYRoVkEZh0ZHzbfmTPXE85SWrnKip6GeFE2I1iKVBCzNK9pmiVhS1x+Axx7myRJesvgHvvR3rNKmQ3n/OKPVGND1MVXTqHiFK6qVFiwlXgTVDhkq+ChhnyJCW9GeaoIGQOdV0M9YhYZWbvUXrIJJ+rKL6lJ9CYj5Fai0iKqyPkx0HcUsJYrBbtREIJ2H72GxTI/2CL1zAbLkZ8WIxYgUvsKebq6Zl3rEZvymx6echo1N+au9XcS3oHsxWMPrGTFH+CLhsmbhMNRWrNB4SZVSwyJ5WDFRb3DAAmaXf2rPP+6BpbkmStkBLAWwkHmdNWKfYqFaZRp2GGdo+mhpv6bBkNhepRzERpdASeW1aKSZ5RidpoUsRAvQ+NJCnJHHl+bcZ80vjkij661vo/rWMQSitWskgnNv7LP+MNN38NadYuCPtYCItIFTjMRgfeqClkhkFZ+FXCQmpFuyKXii7xNI93LT9szdrUMsNZnJkuwZX6zlKdaqRXrESiq/e19kBC3NisLt+Gc/7jW0gtZ51Bl1MCmUaoM//aRv0aapnF0l362KIUnI6EyuhCUOuWrIVfAZcRAj5NJWJ0C5epP19y1awJLWhdt/a1t3KcGF8Yxb5bbsLItoeYmxZRkRWq46IrR9StX/tcw4oKsYH+nlrZpmbcZQ7R1tDPBvMbdIwofLpVKIfcJy5nCa5WRhnDFkVOx+s5kr29GPzpfUxsuxg0zlQUxSZudG/CqNOSIJxYCclGCA7fDRDpiCK6gIVfidVmWXrHRh0fmBd+eSYIIEcWdRhdJJsWp+aQT1vI9nYjnl3wuhSJLuhAJJ1WQWDisadUELCi0bD1WlscMpq6lrV1Ft0riC9tVcFD8odfDVS9bod5pNGgC3+XFnxsXA2rsw25/gHMTcwiRxdbvLgPsY7s61IktWSZinw6l8SbupNGvUlphB1yZY3aIhfZtRmz4XS3oMoA5JP6BywdvBIr24ytMdzsWjHaMcnI0nXRG5FkdCrnS6gy6QzccxeMZDsJW+r1KbJ4pbKAVy6huXoyauVUaAUjRK5WjN9cH05PCiZl84VfsXaSVTKf191C6F61qCXjtjAORtvTSPb0sgYoEi/UmEmnMj6JkpXA6z2cTAbxxV26GdEEZB12DVVV63BrIuwYaWpCGZyuJBWSFSxPLTB5PH1+rhDDKlQbuvajNUzE+UVyRTTdQt+zWIrGWIJOozo8hjmashq8PkXsZAoty1Yqi/gVnq6ru+p1pUKFTM3dENJzu421TiqKKq3hhUp45apSyM1VGMH0xOi+liz0yOxUyijs2w2DlRjI+8tHB3XUIP+fGBxA9+LFr1kRgwV769p1fPkEQ+9KRq+dKE9MsGKc1BmxltEC7W6CEdW0aUtocIvw0tcSt5JGu3R4OA+zIxW1uKoUOUZzFxmxRp/ai+iz+xi9CK5EVJGdqBNBlG4xdvBlRq9eTQteawhm0MgPLsSGj92gVqjKk8ew/TOfxPjjz8BKxhvLFGHjWUBuJh0Cu6pqD7WCTGz4BDqKpE30rIlj05rw6sKFxuCXPP9O8MEjxQqOTuQwNjJLa1mItaRRGB3GLHnO6znaNmxC/nA/cocPKNoS61iEZVdfEy5LBHVKUieCLY5eeKIiXp6RapJuNVJFMCamYGnOUFyslBo0Xronai0dIfXmnZIqtKhgNIaj/F3ULSLx4j60dnXXy8s/OZe0dyGW7cLOL34arevXI9rayWgYhZPtoJtNqsTbyPKUgwzamyCw867MtG5NBUF9bSBXLCkeKOzDroUutaZODax52yUk5sfgsyrL897+PXtQHTmK7vWnomPpCkSTf3pI7j7/Qmz/5HWY3r5LNziYeC3WPlYsovOJJ7VKVbuPENcgXEyvuV3IbKXpPlcqqh0acqGe2S1oq1jzqmZ+b0mGDJNaM2bnjrHuPnYUifZOtDMKda9ah1RnZ30F99WO9jM2MzouZw0vLdJIuCsiUInOz0vbiVNa9DSBtITyWo3VAV/XG/KmPEuBKrmard7rNxKiyCoN7EBnpXlLCiYTmfibuEHSSSkLV4uzGNr5NEYP7EZb31J0rd6AzMIevtf+g4oIg+7e8iYM3H03J5muw9n3ZquqfwU3aGDdMBqdztr+lXBbhyg+R2xYTb5jN7YG6SKnyh870r8Ki6Py0CiO3fcTNWaCBU3E8FVDr7ZPRjbcDLHO30N/TmazdLk+JFMxVoZh6errUrcmnDQp5o4MocrI4o3N6dmXhp1hoHkOFV2R5CXtVwm3Qc0aBip8Z6lY0HtRpJ8GYz5pVFgxgkaHiaCuDE1gfOAhFdNbJIKxplCKNJqqyoqi0CT9tp9/IyyPE2SryYyDKD9LVKxKUqXbuFOM+yVDN/Rq+0ia1mLmtYNqK8rhTiSpLLNbLkDLuZvQ0X8QBoG+//5fIMjP4AQ/kJkuM+vW+sS1wkgiVSTi0Fq2XqoLFfFYMMkyHSFL2mOpHQmy+aU4xXHoLk6rrIkYiE1JNpZOJjO1ivduOLSkZeuk6/YBwR54jaVv6chXpmZQmJnEssveQjwVcPCXv1IWt4//sUVB7K4WpGTREqhvJCrO5MhtGLMTKWU5pUSpDKs1glhbB4W3VCSpTM6gOl2GQzxJt+RQUMFcOoENrXG0FEhESSvMmIVIZ6uaHL9QZn6Y067VNJueV4bdmYDdktJ7pAJNKKfG+pG/cz8GH/gfGLIARF4o9fs8RWSrUmZxN7Z+9za0sooTPiRuI22bsUMHsevWW1B+iFnYdOgqFWTPPxWnXPdxtK5eV8fB9IH92Pn1m1hz7MQh00Xm/C34+K23MiOXsPvLX8bgbXej5bz1OPs7tzIhduHgnXfghX/8OplEsr6U4ZtV9G69HMvf8wEkKUfgaUeWbs4zX/8Sxm/+AbzxCRVF1VpFM9hrvS2ZmZbuRUh2LpxPw7t60EWK8vgHPoCZ5w4i1pvBps99Bu2nbJ73XLyzB4kvLcAPt27F2LFR9MTjSKbb1L1h4mIq4iNL14u2ZRFJysazZCNHqA0DZXRcuBGnf+bz6v4JLDqVgk3r247DnMdJDkOzffJtDfoY2b0dg08/gbZlq7BiyyWk+MuQ2bAGU9v2snTtQnxBj3pu9OnfYXr/Hiq1EZ0bz0ZsUS+sFUvgDB+DFfh1v3X9Kg4xknfLRNZ21h2/RYTX29avU0pUSwUcuP07KLw0oBZrA5bGozt2MlA5updgzGuJnYyp6rt7778HP37fX+OJW77ZaKzKoo5eOdfRhMehO3+EbXzu8H/dXW/SOTwj0gZqeoVck+h3xES9LDjpVp3QXeRdqSVLkDllrepy5oeHMPH0brq2qdteRmNJwj7pYKFVlr75YrztKw6ya9aFTzF8Tk+pBZrmXRGRdCsSLMiQbKlfE7PLrjarCcSSA0QZvQQevGKncnrfXpVwZTde3+XvqN9b8d4PYfuNn8O+b9zO56K6oGpOiMYreNfSc7eoE+FO00P334XJx3fQzM685zd8/Hqs/uCHGGEy9QEslaT0Cm9t7rVyYqnGWogEGIl+nqUTmyxwTj62HTs/91ks3XqN2u8VBLKZoVt14pe/42oc/O6dzB2+qnEMNGHEPHHbSfiSqloakGP7D7+Dpz79BfT6cRXu5rHatk51Nh9aEaOJu2mOZIf36uDu6EDi3PVoIQGV5efiwSG1Rjny8COY3P4sI1WM2HKx4bpPYdEFlzA9RMOlhCAsLJssYqGxRbcZI8//9MfIrliDvjPOwqqL/xwD996P6rY9zGHWPNMNPf8UJl9+Cdm169G9YWOdapjB8auShsJMc85YdekVWL7lQgroKHd68qMfRcAEu+lrX1GdSdmBKjQn0aOrU9lso5bK53uSLiyscNu10tAy66FganAQD9zwD6jM5ZBe2IeLbvoGWs5YofZQyfKXxbpejl133omfXfth7P/Fz8NRLbXgb0nGNe26GhGST5MzFmEYll2oCl+sd2IZCcWtTKxd6rokwdYVpyK9fB1z1KnIrD0NDt1WiNGB738X3kxJVapiWVmR5pCurc2iSaIkmNJ0Hr+9+WYkMu0YfHI7Dv9+J+766Eew8vSNiFP4WGsGBanhh6bw1K3fRjSdwfSel5FikTT67At4+t9vgVssojA0Rp6VwOyhfjx9262qABrfw1KaJW15YprXvsVcEG1sT5eCji40fXSURVyAvTd9TSmv6nTVifQx/uwzmHiU7kb3Clu+GC27MsY247p07+SihN0m/Kgc6EXRIjmMgDvCF9mcsXJxDgniZSnN3xFLIcc6Yormd1mhCX2QpWc7SteolNUpNUQkIUvJpDkUrsrfqy1L8ZjaFSTrJKLsCbvz6BqxaBwdBReWbJmF3kTa2NYRVYFGHEYKqqFKFXtzMg6uUhaJyzZyQ/d/FdUm8LwmAuYwO/vhQBU+m+ddmy+NpBKNWpIzF7EdRSxrOygMMl6LruUw2tQXOTy1akNFk/XtU/V70H3g6YyNNk5GtOIp/DYvlKp9LoJLWuIl2fADfJ/X71PQ8Jo2Vzbv620OAFI9jtIqCQ7tnfC/JxhNT4dShds4UKvB66s1ftPnRqOh/l13hDDqWGhxqUgTsIV1Fzg5Y7TEpKsK+B/w+sdqUWuqv1CxUN8K/MqHLMnhj/g/J/4/juDky9VSg0kh/zQj322897Pao/8nwAC+AZicLeuzngAAAABJRU5ErkJggg==); background-repeat: no-repeat; background-position: top left; height: 64px; } + #header h1, #header h2 {margin: 0} + #header h2 { color: #888; font-weight: normal; font-size: 16px; } - #about h3 { margin: 0; margin-bottom: 10px; @@ -84,18 +84,26 @@ margin-left: -55px; margin-right: -10px; } + #about-content table { margin-top: 10px; margin-bottom: 10px; font-size: 11px; border-collapse: collapse; } + #about-content td { padding: 10px; padding-top: 3px; padding-bottom: 3px; } - #about-content td.name {color: #555} + + #about-content td.name { + font-weight: bold; + vertical-align: top; + color: #555; + } + #about-content td.value {color: #000} #about-content ul { @@ -107,21 +115,23 @@ background-color: #fcc; border: 1px solid #f00; } + #about-content.failure p { margin: 0; padding: 10px; } - #getting-started { border-top: 1px solid #ccc; margin-top: 25px; padding-top: 15px; } + #getting-started h1 { margin: 0; font-size: 20px; } + #getting-started h2 { margin: 0; font-size: 14px; @@ -129,40 +139,46 @@ color: #333; margin-bottom: 25px; } + #getting-started ol { margin-left: 0; padding-left: 0; } + #getting-started li { font-size: 18px; color: #888; margin-bottom: 25px; } + #getting-started li h2 { margin: 0; font-weight: normal; font-size: 18px; color: #333; } + #getting-started li p { color: #555; font-size: 13px; } - #sidebar ul { margin-left: 0; padding-left: 0; } + #sidebar ul h3 { margin-top: 25px; font-size: 16px; padding-bottom: 10px; border-bottom: 1px solid #ccc; } + #sidebar li { list-style-type: none; } + #sidebar ul.links li { margin-bottom: 5px; } diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb index 2e6356343d..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' diff --git a/railties/lib/rails/test_unit/sub_test_task.rb b/railties/lib/rails/test_unit/sub_test_task.rb index d9bffba4d7..6fa96d2ced 100644 --- a/railties/lib/rails/test_unit/sub_test_task.rb +++ b/railties/lib/rails/test_unit/sub_test_task.rb @@ -7,7 +7,7 @@ module Rails # # This class takes a TestInfo class and defines the appropriate rake task # based on the information, then invokes it. - class TestCreator + class TestCreator # :nodoc: def initialize(info) @info = info end @@ -41,7 +41,7 @@ module Rails # to test files (or can be transformed into test files). Calling <tt>files</tt> # provides the set of test files and is used when initializing tests after # a call to <tt>rake test</tt>. - class TestInfo + class TestInfo # :nodoc: def initialize(tasks) @tasks = tasks @files = nil diff --git a/railties/lib/rails/test_unit/testing.rake b/railties/lib/rails/test_unit/testing.rake index 285e2ce846..957deb8a60 100644 --- a/railties/lib/rails/test_unit/testing.rake +++ b/railties/lib/rails/test_unit/testing.rake @@ -3,7 +3,7 @@ require 'rails/test_unit/sub_test_task' task default: :test -desc 'Runs test:units, test:functionals, test:generators, test:integration together' +desc 'Runs test:units, test:functionals, test:generators, test:integration, test:jobs together' task :test do Rails::TestTask.test_creator(Rake.application.top_level_tasks).invoke_rake_task end @@ -13,7 +13,7 @@ namespace :test do # Placeholder task for other Railtie and plugins to enhance. See Active Record for an example. end - task :run => ['test:units', 'test:functionals', 'test:generators', 'test:integration'] + task :run => ['test:units', 'test:functionals', 'test:generators', 'test:integration', 'test:jobs'] # Inspired by: http://ngauthier.com/2012/02/quick-tests-with-bash.html desc "Run tests quickly by merging all types and not resetting db" @@ -28,7 +28,7 @@ namespace :test do Rails::TestTask.new(single: "test:prepare") - ["models", "helpers", "controllers", "mailers", "integration"].each do |name| + ["models", "helpers", "controllers", "mailers", "integration", "jobs"].each do |name| Rails::TestTask.new(name => "test:prepare") do |t| t.pattern = "test/#{name}/**/*_test.rb" end diff --git a/railties/lib/rails/version.rb b/railties/lib/rails/version.rb index 923cab4e2a..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 = "beta1" +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/test/abstract_unit.rb b/railties/test/abstract_unit.rb index ade08d3f5a..0749615d03 100644 --- a/railties/test/abstract_unit.rb +++ b/railties/test/abstract_unit.rb @@ -17,3 +17,37 @@ module TestApp 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 + +class ActiveSupport::TestCase + # FIXME: we have tests that depend on run order, we should fix that and + # remove this method call. + self.test_order = :sorted + + private + + def capture(stream) + stream = stream.to_s + captured_stream = Tempfile.new(stream) + stream_io = eval("$#{stream}") + origin_stream = stream_io.dup + stream_io.reopen(captured_stream) + + yield + + stream_io.rewind + return captured_stream.read + ensure + captured_stream.close + captured_stream.unlink + stream_io.reopen(origin_stream) + end +end diff --git a/railties/test/app_rails_loader_test.rb b/railties/test/app_rails_loader_test.rb index 92cb3233d8..d4885447e6 100644 --- a/railties/test/app_rails_loader_test.rb +++ b/railties/test/app_rails_loader_test.rb @@ -3,13 +3,27 @@ require 'abstract_unit' require 'rails/app_rails_loader' class AppRailsLoaderTest < ActiveSupport::TestCase + def loader + @loader ||= Class.new do + extend Rails::AppRailsLoader + + def self.exec_arguments + @exec_arguments + end + + def self.exec(*args) + @exec_arguments = args + end + end + end + def write(filename, contents=nil) FileUtils.mkdir_p(File.dirname(filename)) File.write(filename, contents) end def expects_exec(exe) - Rails::AppRailsLoader.expects(:exec).with(Rails::AppRailsLoader::RUBY, exe) + assert_equal [Rails::AppRailsLoader::RUBY, exe], loader.exec_arguments end setup do @@ -22,24 +36,30 @@ 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) + def loader.find_executables; end + + assert !loader.exec_app_rails + end - assert !Rails::AppRailsLoader.exec_app_rails + test "is not in a Rails application if #{exe} exists but is a folder" do + FileUtils.mkdir_p(exe) + + assert !loader.exec_app_rails end ['APP_PATH', 'ENGINE_PATH'].each do |keyword| test "is in a Rails application if #{exe} exists and contains #{keyword}" do write exe, keyword + loader.exec_app_rails + expects_exec exe - Rails::AppRailsLoader.exec_app_rails end test "is not in a Rails application if #{exe} exists but doesn't contain #{keyword}" do write exe - assert !Rails::AppRailsLoader.exec_app_rails + assert !loader.exec_app_rails end test "is in a Rails application if parent directory has #{exe} containing #{keyword} and chdirs to the root directory" do @@ -48,8 +68,9 @@ class AppRailsLoaderTest < ActiveSupport::TestCase Dir.chdir('foo/bar') + loader.exec_app_rails + expects_exec exe - Rails::AppRailsLoader.exec_app_rails # Compare the realpath in case either of them has symlinks. # diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb index b235b51d90..8f091cfdbf 100644 --- a/railties/test/application/assets_test.rb +++ b/railties/test/application/assets_test.rb @@ -50,6 +50,8 @@ module ApplicationTests end RUBY + add_to_env_config "development", "config.assets.digest = false" + require "#{app_path}/config/environment" get "/assets/demo.js" @@ -189,7 +191,6 @@ module ApplicationTests end test "asset pipeline should use a Sprockets::Index when config.assets.digest is true" do - add_to_config "config.assets.digest = true" add_to_config "config.action_controller.perform_caching = false" ENV["RAILS_ENV"] = "production" @@ -199,10 +200,9 @@ 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 - add_to_config "config.assets.digest = true" precompile! manifest = Dir["#{app_path}/public/assets/manifest-*.json"].first @@ -214,8 +214,6 @@ module ApplicationTests test "the manifest file should be saved by default in the same assets folder" do app_file "app/assets/javascripts/application.js", "alert();" - # digest is default in false, we must enable it for test environment - add_to_config "config.assets.digest = true" add_to_config "config.assets.prefix = '/x'" precompile! @@ -248,7 +246,6 @@ module ApplicationTests test "precompile properly refers files referenced with asset_path and runs in the provided RAILS_ENV" do app_file "app/assets/images/rails.png", "notactuallyapng" app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>" - # digest is default in false, we must enable it for test environment add_to_env_config "test", "config.assets.digest = true" precompile!('RAILS_ENV=test') @@ -260,7 +257,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! @@ -280,12 +277,9 @@ module ApplicationTests test "precompile appends the md5 hash to files referenced with asset_path and run in production with digest true" do app_file "app/assets/images/rails.png", "notactuallyapng" app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>" - add_to_config "config.assets.compile = true" - add_to_config "config.assets.digest = true" - - ENV["RAILS_ENV"] = nil - precompile!('RAILS_GROUPS=assets') + ENV["RAILS_ENV"] = "production" + precompile! file = Dir["#{app_path}/public/assets/application-*.css"].first assert_match(/\/assets\/rails-([0-z]+)\.png/, File.read(file)) @@ -341,6 +335,8 @@ module ApplicationTests end RUBY + add_to_env_config "development", "config.assets.digest = false" + require "#{app_path}/config/environment" class ::OmgController < ActionController::Base @@ -365,6 +361,8 @@ module ApplicationTests app_file "app/assets/javascripts/demo.js", "alert();" + add_to_env_config "development", "config.assets.digest = false" + require "#{app_path}/config/environment" get "/assets/demo.js" @@ -394,7 +392,6 @@ module ApplicationTests app_file "app/assets/javascripts/application.js", "//= require_tree ." app_file "app/assets/javascripts/xmlhr.js.erb", "<%= Post.name %>" - add_to_config "config.assets.digest = false" precompile! assert_equal "Post;\n", File.read(Dir["#{app_path}/public/assets/application-*.js"].first) end @@ -414,7 +411,6 @@ module ApplicationTests test "digested assets are not mistakenly removed" do app_file "app/assets/application.js", "alert();" add_to_config "config.assets.compile = true" - add_to_config "config.assets.digest = true" precompile! @@ -437,6 +433,7 @@ module ApplicationTests test "asset urls should use the request's protocol by default" do app_with_assets_in_view add_to_config "config.asset_host = 'example.com'" + add_to_env_config "development", "config.assets.digest = false" require "#{app_path}/config/environment" class ::PostsController < ActionController::Base; end @@ -448,23 +445,24 @@ 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") %>";' - add_to_config "config.assets.precompile = %w{image_loader.js}" + app_file "app/assets/javascripts/image_loader.js.erb", "var src='<%= image_path('rails.png') %>';" + add_to_config "config.assets.precompile = %w{rails.png image_loader.js}" add_to_config "config.asset_host = 'example.com'" + add_to_env_config "development", "config.assets.digest = false" 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") %>";' - add_to_config "config.assets.precompile = %w{app.js}" + app_file "app/assets/javascripts/app.js.erb", "var src='<%= image_path('rails.png') %>';" + add_to_config "config.assets.precompile = %w{rails.png app.js}" + add_to_env_config "development", "config.assets.digest = false" 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/base_test.rb b/railties/test/application/configuration/base_test.rb new file mode 100644 index 0000000000..d6a82b139d --- /dev/null +++ b/railties/test/application/configuration/base_test.rb @@ -0,0 +1,37 @@ +require 'isolation/abstract_unit' +require 'rack/test' +require 'env_helpers' + +module ApplicationTests + module ConfigurationTests + class BaseTest < ActiveSupport::TestCase + def setup + build_app + boot_rails + FileUtils.rm_rf("#{app_path}/config/environments") + end + + def teardown + teardown_app + FileUtils.rm_rf(new_app) if File.directory?(new_app) + end + + private + def new_app + File.expand_path("#{app_path}/../new_app") + end + + def copy_app + FileUtils.cp_r(app_path, new_app) + end + + def app + @app ||= Rails.application + end + + def require_environment + require "#{app_path}/config/environment" + end + end + end +end
\ No newline at end of file diff --git a/railties/test/application/configuration/custom_test.rb b/railties/test/application/configuration/custom_test.rb new file mode 100644 index 0000000000..f8d22f6d97 --- /dev/null +++ b/railties/test/application/configuration/custom_test.rb @@ -0,0 +1,22 @@ +require 'application/configuration/base_test' + +class ApplicationTests::ConfigurationTests::CustomTest < ApplicationTests::ConfigurationTests::BaseTest + test 'access custom configuration point' do + add_to_config <<-RUBY + config.x.payment_processing.schedule = :daily + config.x.payment_processing.retries = 3 + config.x.super_debugger = true + config.x.hyper_debugger = false + config.x.nil_debugger = nil + RUBY + require_environment + + x = Rails.configuration.x + assert_equal :daily, x.payment_processing.schedule + assert_equal 3, x.payment_processing.retries + assert_equal true, x.super_debugger + assert_equal false, x.hyper_debugger + assert_equal nil, x.nil_debugger + assert_nil x.i_do_not_exist.zomg + end +end diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index 6158c416d7..0eddf644d9 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -8,6 +8,12 @@ end class ::MyOtherMailInterceptor < ::MyMailInterceptor; end +class ::MyPreviewMailInterceptor + def self.previewing_email(email); email; end +end + +class ::MyOtherPreviewMailInterceptor < ::MyPreviewMailInterceptor; end + class ::MyMailObserver def self.delivered_email(email); email; end end @@ -60,13 +66,25 @@ module ApplicationTests config.action_dispatch.show_exceptions = true RUBY + app_file 'db/migrate/20140708012246_create_user.rb', <<-RUBY + class CreateUser < ActiveRecord::Migration + def change + create_table :users + end + end + RUBY + require "#{app_path}/config/environment" - ActiveRecord::Migrator.stubs(:needs_migration?).returns(true) - ActiveRecord::NullMigration.any_instance.stubs(:mtime).returns(1) - get "/foo" - assert_equal 500, last_response.status - assert_match "ActiveRecord::PendingMigrationError", last_response.body + ActiveRecord::Migrator.migrations_paths = ["#{app_path}/db/migrate"] + + begin + get "/foo" + assert_equal 500, last_response.status + assert_match "ActiveRecord::PendingMigrationError", last_response.body + ensure + ActiveRecord::Migrator.migrations_paths = nil + end end test "Rails.groups returns available groups" do @@ -100,7 +118,7 @@ module ApplicationTests test "Rails::Application responds to paths" do require "#{app_path}/config/environment" assert_respond_to AppTemplate::Application, :paths - assert_equal AppTemplate::Application.paths["app/views"].expanded, ["#{app_path}/app/views"] + assert_equal ["#{app_path}/app/views"], AppTemplate::Application.paths["app/views"].expanded end test "the application root is set correctly" do @@ -164,7 +182,7 @@ module ApplicationTests test "application is always added to eager_load namespaces" do require "#{app_path}/config/application" - assert Rails.application, Rails.application.config.eager_load_namespaces + assert_includes Rails.application.config.eager_load_namespaces, AppTemplate::Application end test "the application can be eager loaded even when there are no frameworks" do @@ -336,6 +354,14 @@ module ApplicationTests 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 @@ -352,12 +378,14 @@ module ApplicationTests test "default method for update can be changed" do app_file 'app/models/post.rb', <<-RUBY class Post - extend ActiveModel::Naming + include ActiveModel::Model def to_key; [1]; end def persisted?; true; end end RUBY + token = "cf50faa3fe97702ca1ae" + app_file 'app/controllers/posts_controller.rb', <<-RUBY class PostsController < ApplicationController def show @@ -367,6 +395,10 @@ module ApplicationTests def update render text: "update" end + + private + + def form_authenticity_token; token; end # stub the authenticy token end RUBY @@ -378,8 +410,6 @@ module ApplicationTests require "#{app_path}/config/environment" - token = "cf50faa3fe97702ca1ae" - PostsController.any_instance.stubs(:form_authenticity_token).returns(token) params = {authenticity_token: token} get "/posts/1" @@ -410,7 +440,7 @@ module ApplicationTests end get "/" - assert last_response.body =~ /_xsrf_token_here/ + assert_match "_xsrf_token_here", last_response.body end test "sets ActionDispatch.test_app" do @@ -452,6 +482,32 @@ module ApplicationTests assert_equal [::MyMailInterceptor, ::MyOtherMailInterceptor], ::Mail.send(:class_variable_get, "@@delivery_interceptors") end + test "registers preview interceptors with ActionMailer" do + add_to_config <<-RUBY + config.action_mailer.preview_interceptors = MyPreviewMailInterceptor + RUBY + + require "#{app_path}/config/environment" + require "mail" + + _ = ActionMailer::Base + + assert_equal [::MyPreviewMailInterceptor], ActionMailer::Base.preview_interceptors + end + + test "registers multiple preview interceptors with ActionMailer" do + add_to_config <<-RUBY + config.action_mailer.preview_interceptors = [MyPreviewMailInterceptor, "MyOtherPreviewMailInterceptor"] + RUBY + + require "#{app_path}/config/environment" + require "mail" + + _ = ActionMailer::Base + + assert_equal [MyPreviewMailInterceptor, MyOtherPreviewMailInterceptor], ActionMailer::Base.preview_interceptors + end + test "registers observers with ActionMailer" do add_to_config <<-RUBY config.action_mailer.observers = MyMailObserver @@ -481,7 +537,7 @@ module ApplicationTests test "valid timezone is setup correctly" do add_to_config <<-RUBY config.root = "#{app_path}" - config.time_zone = "Wellington" + config.time_zone = "Wellington" RUBY require "#{app_path}/config/environment" @@ -492,7 +548,7 @@ module ApplicationTests test "raises when an invalid timezone is defined in the config" do add_to_config <<-RUBY config.root = "#{app_path}" - config.time_zone = "That big hill over yonder hill" + config.time_zone = "That big hill over yonder hill" RUBY assert_raise(ArgumentError) do @@ -503,7 +559,7 @@ module ApplicationTests test "valid beginning of week is setup correctly" do add_to_config <<-RUBY config.root = "#{app_path}" - config.beginning_of_week = :wednesday + config.beginning_of_week = :wednesday RUBY require "#{app_path}/config/environment" @@ -514,7 +570,7 @@ module ApplicationTests test "raises when an invalid beginning of week is defined in the config" do add_to_config <<-RUBY config.root = "#{app_path}" - config.beginning_of_week = :invalid + config.beginning_of_week = :invalid RUBY assert_raise(ArgumentError) do @@ -674,6 +730,44 @@ module ApplicationTests assert_match "We're sorry, but something went wrong", last_response.body end + test "config.action_controller.always_permitted_parameters are: controller, action by default" do + require "#{app_path}/config/environment" + assert_equal %w(controller action), ActionController::Parameters.always_permitted_parameters + end + + test "config.action_controller.always_permitted_parameters = ['controller', 'action', 'format']" do + add_to_config <<-RUBY + config.action_controller.always_permitted_parameters = %w( controller action format ) + RUBY + require "#{app_path}/config/environment" + assert_equal %w( controller action format ), ActionController::Parameters.always_permitted_parameters + end + + test "config.action_controller.always_permitted_parameters = ['controller','action','format'] does not raise exeception" do + app_file 'app/controllers/posts_controller.rb', <<-RUBY + class PostsController < ActionController::Base + def create + render text: params.permit(post: [:title]) + end + end + RUBY + + add_to_config <<-RUBY + routes.prepend do + resources :posts + end + config.action_controller.always_permitted_parameters = %w( controller action format ) + config.action_controller.action_on_unpermitted_parameters = :raise + RUBY + + require "#{app_path}/config/environment" + + assert_equal :raise, ActionController::Parameters.action_on_unpermitted_parameters + + post "/posts", {post: {"title" =>"zomg"}, format: "json"} + assert_equal 200, last_response.status + end + test "config.action_controller.action_on_unpermitted_parameters is :log by default on development" do ENV["RAILS_ENV"] = "development" @@ -768,5 +862,239 @@ 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 + + test "rake_tasks block works at instance level" do + app_file "config/environments/development.rb", <<-RUBY + Rails.application.configure do + config.ran_block = false + + rake_tasks do + config.ran_block = true + end + end + RUBY + + require "#{app_path}/config/environment" + assert_not Rails.configuration.ran_block + + require 'rake' + require 'rake/testtask' + require 'rdoc/task' + + Rails.application.load_tasks + assert Rails.configuration.ran_block + end + + test "generators block works at instance level" do + app_file "config/environments/development.rb", <<-RUBY + Rails.application.configure do + config.ran_block = false + + generators do + config.ran_block = true + end + end + RUBY + + require "#{app_path}/config/environment" + assert_not Rails.configuration.ran_block + + Rails.application.load_generators + assert Rails.configuration.ran_block + end + + test "console block works at instance level" do + app_file "config/environments/development.rb", <<-RUBY + Rails.application.configure do + config.ran_block = false + + console do + config.ran_block = true + end + end + RUBY + + require "#{app_path}/config/environment" + assert_not Rails.configuration.ran_block + + Rails.application.load_console + assert Rails.configuration.ran_block + end + + test "runner block works at instance level" do + app_file "config/environments/development.rb", <<-RUBY + Rails.application.configure do + config.ran_block = false + + runner do + config.ran_block = true + end + end + RUBY + + require "#{app_path}/config/environment" + assert_not Rails.configuration.ran_block + + Rails.application.load_runner + assert Rails.configuration.ran_block + end + + test "loading the first existing database configuration available" do + app_file 'config/environments/development.rb', <<-RUBY + + Rails.application.configure do + config.paths.add 'config/database', with: 'config/nonexistant.yml' + config.paths['config/database'] << 'config/database.yml' + end + RUBY + + require "#{app_path}/config/environment" + + assert_kind_of Hash, Rails.application.config.database_configuration + end + + test 'raises with proper error message if no database configuration found' do + FileUtils.rm("#{app_path}/config/database.yml") + require "#{app_path}/config/environment" + err = assert_raises RuntimeError do + Rails.application.config.database_configuration + end + assert_match 'config/database', err.message + end + + test 'config.action_mailer.show_previews defaults to true in development' do + Rails.env = "development" + require "#{app_path}/config/environment" + + assert Rails.application.config.action_mailer.show_previews + end + + test 'config.action_mailer.show_previews defaults to false in production' do + Rails.env = "production" + require "#{app_path}/config/environment" + + assert_equal false, Rails.application.config.action_mailer.show_previews + end + + test 'config.action_mailer.show_previews can be set in the configuration file' do + Rails.env = "production" + add_to_config <<-RUBY + config.action_mailer.show_previews = true + RUBY + require "#{app_path}/config/environment" + + assert_equal true, Rails.application.config.action_mailer.show_previews + end + + test "config_for loads custom configuration from yaml files" do + app_file 'config/custom.yml', <<-RUBY + development: + key: 'custom key' + RUBY + + add_to_config <<-RUBY + config.my_custom_config = config_for('custom') + RUBY + + require "#{app_path}/config/environment" + + assert_equal 'custom key', Rails.application.config.my_custom_config['key'] + end + + test "config_for raises an exception if the file does not exist" do + add_to_config <<-RUBY + config.my_custom_config = config_for('custom') + RUBY + + exception = assert_raises(RuntimeError) do + require "#{app_path}/config/environment" + end + + assert_equal "Could not load configuration. No such file - #{app_path}/config/custom.yml", exception.message + end + + test "config_for without the environment configured returns an empty hash" do + app_file 'config/custom.yml', <<-RUBY + test: + key: 'custom key' + RUBY + + add_to_config <<-RUBY + config.my_custom_config = config_for('custom') + RUBY + require "#{app_path}/config/environment" + + assert_equal({}, Rails.application.config.my_custom_config) + end + + test "config_for with empty file returns an empty hash" do + app_file 'config/custom.yml', <<-RUBY + RUBY + + add_to_config <<-RUBY + config.my_custom_config = config_for('custom') + RUBY + require "#{app_path}/config/environment" + + assert_equal({}, Rails.application.config.my_custom_config) + end + + test "config_for containing ERB tags should evaluate" do + app_file 'config/custom.yml', <<-RUBY + development: + key: <%= 'custom key' %> + RUBY + + add_to_config <<-RUBY + config.my_custom_config = config_for('custom') + RUBY + require "#{app_path}/config/environment" + + assert_equal 'custom key', Rails.application.config.my_custom_config['key'] + end + + test "config_for with syntax error show a more descritive exception" do + app_file 'config/custom.yml', <<-RUBY + development: + key: foo: + RUBY + + add_to_config <<-RUBY + config.my_custom_config = config_for('custom') + RUBY + + exception = assert_raises(RuntimeError) do + require "#{app_path}/config/environment" + end + + assert_match 'YAML syntax error occurred while parsing', exception.message + end end end diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb index 3601a58f67..2d45c9b53f 100644 --- a/railties/test/application/initializers/frameworks_test.rb +++ b/railties/test/application/initializers/frameworks_test.rb @@ -35,8 +35,8 @@ module ApplicationTests require "#{app_path}/config/environment" expanded_path = File.expand_path("app/views", app_path) - assert_equal ActionController::Base.view_paths[0].to_s, expanded_path - assert_equal ActionMailer::Base.view_paths[0].to_s, expanded_path + assert_equal expanded_path, ActionController::Base.view_paths[0].to_s + assert_equal expanded_path, ActionMailer::Base.view_paths[0].to_s end test "allows me to configure default url options for ActionMailer" do @@ -50,7 +50,7 @@ module ApplicationTests assert_equal "test.rails", ActionMailer::Base.default_url_options[:host] end - test "does not include url helpers as action methods" do + test "includes url helpers as action methods" do app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get "/foo", :to => lambda { |env| [200, {}, []] }, :as => :foo @@ -66,8 +66,8 @@ module ApplicationTests require "#{app_path}/config/environment" assert Foo.method_defined?(:foo_path) + assert Foo.method_defined?(:foo_url) assert Foo.method_defined?(:main_app) - assert_equal Set.new(["notify"]), Foo.action_methods end test "allows to not load all helpers for controllers" do @@ -216,8 +216,8 @@ module ApplicationTests require "#{app_path}/config/environment" orig_database_url = ENV.delete("DATABASE_URL") orig_rails_env, Rails.env = Rails.env, 'development' - database_url_db_name = File.join(app_path, "db/database_url_db.sqlite3") - ENV["DATABASE_URL"] = "sqlite3://:@localhost/#{database_url_db_name}" + database_url_db_name = "db/database_url_db.sqlite3" + 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 bc34897cdf..9ee54796a4 100644 --- a/railties/test/application/initializers/i18n_test.rb +++ b/railties/test/application/initializers/i18n_test.rb @@ -184,28 +184,13 @@ en: 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 + load_app assert_equal false, I18n.enforce_available_locales assert_nothing_raised do @@ -220,8 +205,7 @@ en: config.i18n.default_locale = :fr RUBY - output = capture(:stderr) { load_app } - assert_no_match %r{deprecated.*enforce_available_locales}, output + load_app assert_equal false, I18n.enforce_available_locales assert_nothing_raised do diff --git a/railties/test/application/mailer_previews_test.rb b/railties/test/application/mailer_previews_test.rb index c588fd7012..55e917c3ec 100644 --- a/railties/test/application/mailer_previews_test.rb +++ b/railties/test/application/mailer_previews_test.rb @@ -26,6 +26,20 @@ module ApplicationTests assert_equal 404, last_response.status end + test "/rails/mailers is accessible with correct configuraiton" do + add_to_config "config.action_mailer.show_previews = true" + app("production") + get "/rails/mailers" + assert_equal 200, last_response.status + end + + test "/rails/mailers is not accessible with show_previews = false" do + add_to_config "config.action_mailer.show_previews = false" + app("development") + 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 @@ -403,6 +417,58 @@ module ApplicationTests assert_match '<option selected value="?part=text%2Fplain">View as plain-text email</option>', last_response.body end + test "*_path helpers emit a deprecation" do + + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + get 'foo', to: 'foo#index' + end + RUBY + + mailer 'notifier', <<-RUBY + class Notifier < ActionMailer::Base + default from: "from@example.com" + + def path_in_view + mail to: "to@example.org" + end + + def path_in_mailer + @url = foo_path + mail to: "to@example.org" + end + end + RUBY + + html_template 'notifier/path_in_view', "<%= link_to 'foo', foo_path %>" + + mailer_preview 'notifier', <<-RUBY + class NotifierPreview < ActionMailer::Preview + def path_in_view + Notifier.path_in_view + end + + def path_in_mailer + Notifier.path_in_mailer + end + end + RUBY + + app('development') + + assert_deprecated do + get "/rails/mailers/notifier/path_in_view.html" + assert_equal 200, last_response.status + end + + html_template 'notifier/path_in_mailer', "No ERB in here" + + assert_deprecated do + get "/rails/mailers/notifier/path_in_mailer.html" + assert_equal 200, last_response.status + end + end + private def build_app super diff --git a/railties/test/application/middleware/cache_test.rb b/railties/test/application/middleware/cache_test.rb index b4db840e68..c951dabd6c 100644 --- a/railties/test/application/middleware/cache_test.rb +++ b/railties/test/application/middleware/cache_test.rb @@ -81,8 +81,8 @@ module ApplicationTests add_to_config "config.action_dispatch.rack_cache = true" get "/expires/expires_header" - assert_equal "miss, ignore, store", last_response.headers["X-Rack-Cache"] - assert_equal "max-age=10, public", last_response.headers["Cache-Control"] + assert_equal "miss, store", last_response.headers["X-Rack-Cache"] + assert_equal "max-age=10, public", last_response.headers["Cache-Control"] body = last_response.body @@ -115,8 +115,8 @@ module ApplicationTests add_to_config "config.action_dispatch.rack_cache = true" get "/expires/expires_etag" - assert_equal "miss, ignore, store", last_response.headers["X-Rack-Cache"] - assert_equal "public", last_response.headers["Cache-Control"] + assert_equal "miss, store", last_response.headers["X-Rack-Cache"] + assert_equal "public", last_response.headers["Cache-Control"] body = last_response.body etag = last_response.headers["ETag"] @@ -149,8 +149,8 @@ module ApplicationTests add_to_config "config.action_dispatch.rack_cache = true" get "/expires/expires_last_modified" - assert_equal "miss, ignore, store", last_response.headers["X-Rack-Cache"] - assert_equal "public", last_response.headers["Cache-Control"] + assert_equal "miss, store", last_response.headers["X-Rack-Cache"] + assert_equal "public", last_response.headers["Cache-Control"] body = last_response.body last = last_response.headers["Last-Modified"] diff --git a/railties/test/application/middleware/exceptions_test.rb b/railties/test/application/middleware/exceptions_test.rb index 42096cfec4..a7472b37f1 100644 --- a/railties/test/application/middleware/exceptions_test.rb +++ b/railties/test/application/middleware/exceptions_test.rb @@ -60,6 +60,21 @@ module ApplicationTests assert_equal "YOU FAILED BRO", last_response.body end + test "url generation error when action_dispatch.show_exceptions is set raises an exception" do + controller :foo, <<-RUBY + class FooController < ActionController::Base + def index + raise ActionController::UrlGenerationError + end + end + RUBY + + app.config.action_dispatch.show_exceptions = true + + get '/foo' + assert_equal 500, last_response.status + end + test "unspecified route when action_dispatch.show_exceptions is not set raises an exception" do app.config.action_dispatch.show_exceptions = false diff --git a/railties/test/application/middleware/remote_ip_test.rb b/railties/test/application/middleware/remote_ip_test.rb index 946b82eeb3..97d5b5c698 100644 --- a/railties/test/application/middleware/remote_ip_test.rb +++ b/railties/test/application/middleware/remote_ip_test.rb @@ -1,3 +1,4 @@ +require 'ipaddr' require 'isolation/abstract_unit' require 'active_support/key_generator' @@ -53,12 +54,25 @@ module ApplicationTests end end + test "remote_ip works with HTTP_X_FORWARDED_FOR" do + make_basic_app + assert_equal "4.2.42.42", remote_ip("REMOTE_ADDR" => "1.1.1.1", "HTTP_X_FORWARDED_FOR" => "4.2.42.42") + end + test "the user can set trusted proxies" do make_basic_app do |app| app.config.action_dispatch.trusted_proxies = /^4\.2\.42\.42$/ end - assert_equal "1.1.1.1", remote_ip("REMOTE_ADDR" => "4.2.42.42,1.1.1.1") + assert_equal "1.1.1.1", remote_ip("REMOTE_ADDR" => "1.1.1.1", "HTTP_X_FORWARDED_FOR" => "4.2.42.42") + end + + test "the user can set trusted proxies with an IPAddr argument" do + make_basic_app do |app| + app.config.action_dispatch.trusted_proxies = IPAddr.new('4.2.42.0/24') + end + + assert_equal "1.1.1.1", remote_ip("REMOTE_ADDR" => "1.1.1.1", "HTTP_X_FORWARDED_FOR" => "10.0.0.0,4.2.42.42") end end end diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb index 1557b90d27..caef39d16f 100644 --- a/railties/test/application/middleware_test.rb +++ b/railties/test/application/middleware_test.rb @@ -83,7 +83,7 @@ module ApplicationTests add_to_config "config.ssl_options = { host: 'example.com' }" boot! - assert_equal Rails.application.middleware.first.args, [{host: 'example.com'}] + assert_equal [{host: 'example.com'}], Rails.application.middleware.first.args end test "removing Active Record omits its middleware" do @@ -94,13 +94,20 @@ module ApplicationTests assert !middleware.include?("ActiveRecord::Migration::CheckPending") end - test "removes lock if cache classes is set" do + test "includes lock if cache_classes is set but eager_load is not" do add_to_config "config.cache_classes = true" boot! + assert middleware.include?("Rack::Lock") + end + + test "does not include lock if cache_classes is set and so is eager_load" do + add_to_config "config.cache_classes = true" + add_to_config "config.eager_load = true" + boot! assert !middleware.include?("Rack::Lock") end - test "removes lock if allow concurrency is set" do + test "does not include lock if allow_concurrency is set" do add_to_config "config.allow_concurrency = true" boot! assert !middleware.include?("Rack::Lock") @@ -188,7 +195,7 @@ module ApplicationTests end end - etag = "5af83e3196bf99f440f31f2e1a6c9afe".inspect + etag = "W/" + "5af83e3196bf99f440f31f2e1a6c9afe".inspect get "/" assert_equal 200, last_response.status diff --git a/railties/test/application/multiple_applications_test.rb b/railties/test/application/multiple_applications_test.rb index 5bfea599e0..9ebf163671 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 @@ -30,23 +36,23 @@ module ApplicationTests end def test_initialization_of_application_with_previous_config - application1 = AppTemplate::Application.new(config: Rails.application.config) - application2 = AppTemplate::Application.new + application1 = AppTemplate::Application.create(config: Rails.application.config) + application2 = AppTemplate::Application.create assert_equal Rails.application.config, application1.config, "Creating a new application while setting an initial config should result in the same config" assert_not_equal Rails.application.config, application2.config, "New applications without setting an initial config should not have the same config" end def test_initialization_of_application_with_previous_railties - application1 = AppTemplate::Application.new(railties: Rails.application.railties) - application2 = AppTemplate::Application.new + application1 = AppTemplate::Application.create(railties: Rails.application.railties) + application2 = AppTemplate::Application.create assert_equal Rails.application.railties, application1.railties assert_not_equal Rails.application.railties, application2.railties end def test_initialize_new_application_with_all_previous_initialization_variables - application1 = AppTemplate::Application.new( + application1 = AppTemplate::Application.create( config: Rails.application.config, railties: Rails.application.railties, routes_reloader: Rails.application.routes_reloader, @@ -66,26 +72,26 @@ module ApplicationTests end def test_rake_tasks_defined_on_different_applications_go_to_the_same_class - $run_count = 0 + run_count = 0 application1 = AppTemplate::Application.new application1.rake_tasks do - $run_count += 1 + run_count += 1 end application2 = AppTemplate::Application.new application2.rake_tasks do - $run_count += 1 + run_count += 1 end require "#{app_path}/config/environment" - assert_equal 0, $run_count, "The count should stay at zero without any calls to the rake tasks" + assert_equal 0, run_count, "The count should stay at zero without any calls to the rake tasks" require 'rake' require 'rake/testtask' require 'rdoc/task' Rails.application.load_tasks - assert_equal 2, $run_count, "Calling a rake task should result in two increments to the count" + assert_equal 2, run_count, "Calling a rake task should result in two increments to the count" end def test_multiple_applications_can_be_initialized @@ -94,36 +100,56 @@ module ApplicationTests def test_initializers_run_on_different_applications_go_to_the_same_class application1 = AppTemplate::Application.new - $run_count = 0 + run_count = 0 AppTemplate::Application.initializer :init0 do - $run_count += 1 + run_count += 1 end application1.initializer :init1 do - $run_count += 1 + run_count += 1 end AppTemplate::Application.new.initializer :init2 do - $run_count += 1 + run_count += 1 end - assert_equal 0, $run_count, "Without loading the initializers, the count should be 0" + assert_equal 0, run_count, "Without loading the initializers, the count should be 0" # Set config.eager_load to false so that an eager_load warning doesn't pop up AppTemplate::Application.new { config.eager_load = false }.initialize! - assert_equal 3, $run_count, "There should have been three initializers that incremented the count" + assert_equal 3, run_count, "There should have been three initializers that incremented the count" + end + + def test_consoles_run_on_different_applications_go_to_the_same_class + run_count = 0 + AppTemplate::Application.console { run_count += 1 } + AppTemplate::Application.new.console { run_count += 1 } + + assert_equal 0, run_count, "Without loading the consoles, the count should be 0" + Rails.application.load_console + assert_equal 2, run_count, "There should have been two consoles that increment the count" + end + + def test_generators_run_on_different_applications_go_to_the_same_class + run_count = 0 + AppTemplate::Application.generators { run_count += 1 } + AppTemplate::Application.new.generators { run_count += 1 } + + assert_equal 0, run_count, "Without loading the generators, the count should be 0" + Rails.application.load_generators + assert_equal 2, run_count, "There should have been two generators that increment the count" end def test_runners_run_on_different_applications_go_to_the_same_class - $run_count = 0 - AppTemplate::Application.runner { $run_count += 1 } - AppTemplate::Application.new.runner { $run_count += 1 } + run_count = 0 + AppTemplate::Application.runner { run_count += 1 } + AppTemplate::Application.new.runner { run_count += 1 } - assert_equal 0, $run_count, "Without loading the runners, the count should be 0" + assert_equal 0, run_count, "Without loading the runners, the count should be 0" Rails.application.load_runner - assert_equal 2, $run_count, "There should have been two runners that increment the count" + assert_equal 2, run_count, "There should have been two runners that increment the count" end def test_isolate_namespace_on_an_application diff --git a/railties/test/application/rack/logger_test.rb b/railties/test/application/rack/logger_test.rb index 701843a6fd..0082ec9cd2 100644 --- a/railties/test/application/rack/logger_test.rb +++ b/railties/test/application/rack/logger_test.rb @@ -11,10 +11,12 @@ module ApplicationTests def setup build_app + add_to_config <<-RUBY + config.logger = ActiveSupport::LogSubscriber::TestHelper::MockLogger.new + RUBY + require "#{app_path}/config/environment" super - @logger = MockLogger.new - Rails.stubs(:logger).returns(@logger) end def teardown @@ -23,7 +25,7 @@ module ApplicationTests end def logs - @logs ||= @logger.logged(:info).join("\n") + @logs ||= Rails.logger.logged(:info).join("\n") end test "logger logs proper HTTP GET verb and path" do diff --git a/railties/test/application/rake/dbs_test.rb b/railties/test/application/rake/dbs_test.rb index 35d9c31c1e..524c70aad2 100644 --- a/railties/test/application/rake/dbs_test.rb +++ b/railties/test/application/rake/dbs_test.rb @@ -17,66 +17,57 @@ module ApplicationTests end def database_url_db_name - File.join(app_path, "db/database_url_db.sqlite3") + "db/database_url_db.sqlite3" end def set_database_url - ENV['DATABASE_URL'] = File.join("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(%r{database:\s+\S*#{Regexp.escape(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 @@ -97,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 @@ -110,43 +100,60 @@ 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 + + test 'db:fixtures:load with namespaced fixture' do + require "#{app_path}/config/environment" + Dir.chdir(app_path) do + `rails generate model admin::book title:string; + bundle exec rake db:migrate db:fixtures:load` + require "#{app_path}/app/models/admin/book" + assert_equal 2, Admin::Book.count + end 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 environment db:drop db:structure: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" #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 @@ -157,9 +164,9 @@ module ApplicationTests 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 @@ -176,6 +183,35 @@ module ApplicationTests "your test schema automatically, see the release notes for details.\n", output end end + + test 'db:setup loads schema and seeds database' do + begin + @old_rails_env = ENV["RAILS_ENV"] + @old_rack_env = ENV["RACK_ENV"] + ENV.delete "RAILS_ENV" + ENV.delete "RACK_ENV" + + app_file 'db/schema.rb', <<-RUBY + ActiveRecord::Schema.define(version: "1") do + create_table :users do |t| + t.string :name + end + end + RUBY + + app_file 'db/seeds.rb', <<-RUBY + puts ActiveRecord::Base.connection_config[:database] + RUBY + + Dir.chdir(app_path) do + database_path = `bundle exec rake db:setup` + assert_equal "development.sqlite3", File.basename(database_path.strip) + end + ensure + ENV["RAILS_ENV"] = @old_rails_env + ENV["RACK_ENV"] = @old_rack_env + 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..a3819b93b2 100644 --- a/railties/test/application/rake/migrations_test.rb +++ b/railties/test/application/rake/migrations_test.rb @@ -58,7 +58,7 @@ module ApplicationTests end test 'migration status when schema migrations table is not present' do - output = Dir.chdir(app_path){ `rake db:migrate:status` } + output = Dir.chdir(app_path){ `rake db:migrate:status 2>&1` } assert_equal "Schema migrations table does not exist yet.\n", output end @@ -153,6 +153,52 @@ 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 + + test 'test migration status migrated file is deleted' do + Dir.chdir(app_path) do + `rails generate model user username:string password:string; + rails generate migration add_email_to_users email:string; + rake db:migrate + rm db/migrate/*email*.rb` + + output = `rake db:migrate:status` + File.write('test.txt', output) + + assert_match(/up\s+\d{14}\s+Create users/, output) + assert_match(/up\s+\d{14}\s+\** NO FILE \**/, output) + end + end end end end diff --git a/railties/test/application/rake/notes_test.rb b/railties/test/application/rake/notes_test.rb index 05f6338b68..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,48 +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 12, 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 @@ -72,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) @@ -92,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 @@ -108,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) @@ -129,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 @@ -150,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 317e73245c..e8c8de9f73 100644 --- a/railties/test/application/rake_test.rb +++ b/railties/test/application/rake_test.rb @@ -271,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_runner_test.rb b/railties/test/application/test_runner_test.rb index 118f22995e..032b11a95f 100644 --- a/railties/test/application/test_runner_test.rb +++ b/railties/test/application/test_runner_test.rb @@ -109,6 +109,17 @@ module ApplicationTests end end + def test_run_jobs + create_test_file :jobs, 'foo_job' + create_test_file :jobs, 'bar_job' + create_test_file :models, 'foo' + run_test_jobs_command.tap do |output| + assert_match "FooJobTest", output + assert_match "BarJobTest", output + assert_match "2 runs, 2 assertions, 0 failures", output + end + end + def test_run_functionals create_test_file :mailers, 'foo_mailer' create_test_file :controllers, 'bar_controller' @@ -132,11 +143,11 @@ module ApplicationTests end def test_run_all_suites - suites = [:models, :helpers, :unit, :controllers, :mailers, :functional, :integration] + suites = [:models, :helpers, :unit, :controllers, :mailers, :functional, :integration, :jobs] suites.each { |suite| create_test_file suite, "foo_#{suite}" } run_test_command('') .tap do |output| suites.each { |suite| assert_match "Foo#{suite.to_s.camelize}Test", output } - assert_match "7 runs, 7 assertions, 0 failures", output + assert_match "8 runs, 8 assertions, 0 failures", output end end @@ -245,7 +256,7 @@ module ApplicationTests def run_test_command(arguments = 'test/unit/test_test.rb') run_task ['test', arguments] end - %w{ mailers models helpers units controllers functionals integration }.each do |type| + %w{ mailers models helpers units controllers functionals integration jobs }.each do |type| define_method("run_test_#{type}_command") do run_task ["test:#{type}"] end diff --git a/railties/test/application/test_test.rb b/railties/test/application/test_test.rb index a223180169..c724c867ec 100644 --- a/railties/test/application/test_test.rb +++ b/railties/test/application/test_test.rb @@ -67,7 +67,7 @@ module ApplicationTests assert_match %r{/app/test/unit/failing_test\.rb}, output end - test "migrations" do + test "ruby schema migrations" do output = script('generate model user name:string') version = output.match(/(\d+)_create_users\.rb/)[1] @@ -104,6 +104,95 @@ module ApplicationTests assert !result.include?("create_table(:users)") end + test "sql structure 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/structure.sql', '' + app_file 'config/initializers/enable_sql_schema_format.rb', <<-RUBY + Rails.application.config.active_record.schema_format = :sql + RUBY + + assert_unsuccessful_run "models/user_test.rb", "Migrations are pending" + + app_file 'db/structure.sql', <<-SQL + CREATE TABLE "schema_migrations" ("version" varchar(255) NOT NULL); + CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version"); + CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255)); + INSERT INTO schema_migrations (version) VALUES ('#{version}'); + SQL + + 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" + + assert_successful_test_run('models/user_test.rb') + end + + test "sql structure migrations when adding column to existing table" do + output_1 = script('generate model user name:string') + version_1 = output_1.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 'config/initializers/enable_sql_schema_format.rb', <<-RUBY + Rails.application.config.active_record.schema_format = :sql + RUBY + + app_file 'db/structure.sql', <<-SQL + CREATE TABLE "schema_migrations" ("version" varchar(255) NOT NULL); + CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version"); + CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255)); + INSERT INTO schema_migrations (version) VALUES ('#{version_1}'); + SQL + + assert_successful_test_run('models/user_test.rb') + + output_2 = script('generate migration add_email_to_users') + version_2 = output_2.match(/(\d+)_add_email_to_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", email: "jon@doe.com" + end + end + RUBY + + app_file 'db/structure.sql', <<-SQL + CREATE TABLE "schema_migrations" ("version" varchar(255) NOT NULL); + CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version"); + CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255), "email" varchar(255)); + INSERT INTO schema_migrations (version) VALUES ('#{version_1}'); + INSERT INTO schema_migrations (version) VALUES ('#{version_2}'); + SQL + + assert_successful_test_run('models/user_test.rb') + end + private def assert_unsuccessful_run(name, message) result = run_test_file(name) diff --git a/railties/test/commands/console_test.rb b/railties/test/commands/console_test.rb index a34beaedb3..4aea3e980f 100644 --- a/railties/test/commands/console_test.rb +++ b/railties/test/commands/console_test.rb @@ -6,7 +6,13 @@ class Rails::ConsoleTest < ActiveSupport::TestCase include EnvHelpers class FakeConsole - def self.start; end + def self.started? + @started + end + + def self.start + @started = true + end end def test_sandbox_option @@ -19,37 +25,47 @@ class Rails::ConsoleTest < ActiveSupport::TestCase assert console.sandbox? end - def test_debugger_option - console = Rails::Console.new(app, parse_arguments(["--debugger"])) - assert console.debugger? - end - def test_no_options console = Rails::Console.new(app, parse_arguments([])) - assert !console.debugger? assert !console.sandbox? end def test_start - FakeConsole.expects(:start) start + + assert app.console.started? assert_match(/Loading \w+ environment \(Rails/, output) end - def test_start_with_debugger - rails_console = Rails::Console.new(app, parse_arguments(["--debugger"])) - rails_console.expects(:require_debugger).returns(nil) + def test_start_with_sandbox + start ["--sandbox"] + - silence_stream(STDOUT) { rails_console.start } + assert app.console.started? + assert app.sandbox + assert_match(/Loading \w+ environment in sandbox \(Rails/, output) end - def test_start_with_sandbox - app.expects(:sandbox=).with(true) - FakeConsole.expects(:start) + if RUBY_VERSION < '2.0.0' + def test_debugger_option + console = Rails::Console.new(app, parse_arguments(["--debugger"])) + assert console.debugger? + end - start ["--sandbox"] + def test_no_options_does_not_set_debugger_flag + console = Rails::Console.new(app, parse_arguments([])) + assert !console.debugger? + end - assert_match(/Loading \w+ environment in sandbox \(Rails/, output) + def test_start_with_debugger + stubbed_console = Class.new(Rails::Console) do + def require_debugger + end + end + + rails_console = stubbed_console.new(app, parse_arguments(["--debugger"])) + silence_stream(STDOUT) { rails_console.start } + end end def test_console_with_environment @@ -58,7 +74,7 @@ class Rails::ConsoleTest < ActiveSupport::TestCase end def test_console_defaults_to_IRB - app = build_app(console: nil) + app = build_app(nil) assert_equal IRB, Rails::Console.new(app).console end @@ -109,8 +125,12 @@ class Rails::ConsoleTest < ActiveSupport::TestCase end def test_rails_env_is_dev_when_argument_is_dev_and_dev_env_is_present - Rails::Console.stubs(:available_environments).returns(['dev']) - options = Rails::Console.parse_arguments(['dev']) + stubbed_console = Class.new(Rails::Console) do + def available_environments + ['dev'] + end + end + options = stubbed_console.parse_arguments(['dev']) assert_match('dev', options[:environment]) end @@ -125,15 +145,29 @@ class Rails::ConsoleTest < ActiveSupport::TestCase end def app - @app ||= build_app(console: FakeConsole) + @app ||= build_app(FakeConsole) end - def build_app(config) - config = mock("config", config) - app = mock("app", config: config) - app.stubs(:sandbox=).returns(nil) - app.expects(:load_console) - app + def build_app(console) + mocked_console = Class.new do + attr_reader :sandbox, :console + + def initialize(console) + @console = console + end + + def config + self + end + + def sandbox=(arg) + @sandbox = arg + end + + def load_console + end + end + mocked_console.new(console) end def parse_arguments(args) diff --git a/railties/test/commands/dbconsole_test.rb b/railties/test/commands/dbconsole_test.rb index 7ad83a8b5d..a3cd1eb0ed 100644 --- a/railties/test/commands/dbconsole_test.rb +++ b/railties/test/commands/dbconsole_test.rb @@ -1,4 +1,5 @@ require 'abstract_unit' +require 'minitest/mock' require 'rails/commands/dbconsole' class Rails::DBConsoleTest < ActiveSupport::TestCase @@ -26,20 +27,21 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase "timeout"=> "3000" } } - app_db_config(config_sample) - assert_equal Rails::DBConsole.new.config, config_sample["test"] + app_db_config(config_sample) do + assert_equal config_sample["test"], Rails::DBConsole.new.config + end end def test_config_with_no_db_config - app_db_config(nil) - assert_raise(ActiveRecord::AdapterNotSpecified) { - Rails::DBConsole.new.config - } + app_db_config(nil) do + assert_raise(ActiveRecord::AdapterNotSpecified) { + Rails::DBConsole.new.config + } + end 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", @@ -50,7 +52,10 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase "pool" => "5", "timeout" => "3000" }.sort - assert_equal expected, Rails::DBConsole.new.config.sort + + app_db_config(nil) do + assert_equal expected, Rails::DBConsole.new.config.sort + end end def test_config_choose_database_url_if_exists @@ -68,68 +73,77 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase "timeout" => "3000" } } - app_db_config(sample_config) - assert_equal host, Rails::DBConsole.new.config["host"] + app_db_config(sample_config) do + assert_equal host, Rails::DBConsole.new.config["host"] + end end def test_env - assert_equal Rails::DBConsole.new.environment, "test" + assert_equal "test", Rails::DBConsole.new.environment ENV['RAILS_ENV'] = nil ENV['RACK_ENV'] = nil - Rails.stubs(:respond_to?).with(:env).returns(false) - assert_equal Rails::DBConsole.new.environment, "development" + Rails.stub(:respond_to?, false) do + assert_equal "development", Rails::DBConsole.new.environment - ENV['RACK_ENV'] = "rack_env" - assert_equal Rails::DBConsole.new.environment, "rack_env" + ENV['RACK_ENV'] = "rack_env" + assert_equal "rack_env", Rails::DBConsole.new.environment - ENV['RAILS_ENV'] = "rails_env" - assert_equal Rails::DBConsole.new.environment, "rails_env" + ENV['RAILS_ENV'] = "rails_env" + assert_equal "rails_env", Rails::DBConsole.new.environment + end ensure ENV['RAILS_ENV'] = "test" + ENV['RACK_ENV'] = nil end def test_rails_env_is_development_when_argument_is_dev - Rails::DBConsole.stubs(:available_environments).returns(['development', 'test']) - options = Rails::DBConsole.new.send(:parse_arguments, ['dev']) - assert_match('development', options[:environment]) + dbconsole = Rails::DBConsole.new + + dbconsole.stub(:available_environments, ['development', 'test']) do + options = dbconsole.send(:parse_arguments, ['dev']) + assert_match('development', options[:environment]) + end end def test_rails_env_is_dev_when_argument_is_dev_and_dev_env_is_present - Rails::DBConsole.stubs(:available_environments).returns(['dev']) - options = Rails::DBConsole.new.send(:parse_arguments, ['dev']) - assert_match('dev', options[:environment]) + dbconsole = Rails::DBConsole.new + + dbconsole.stub(:available_environments, ['dev']) do + options = dbconsole.send(:parse_arguments, ['dev']) + assert_match('dev', options[:environment]) + end end def test_mysql - dbconsole.expects(:find_cmd_and_exec).with(%w[mysql mysql5], 'db') start(adapter: 'mysql', database: 'db') assert !aborted + assert_equal [%w[mysql mysql5], 'db'], dbconsole.find_cmd_and_exec_args end def test_mysql_full - dbconsole.expects(:find_cmd_and_exec).with(%w[mysql mysql5], '--host=locahost', '--port=1234', '--socket=socket', '--user=user', '--default-character-set=UTF-8', '-p', 'db') start(adapter: 'mysql', database: 'db', host: 'locahost', port: 1234, socket: 'socket', username: 'user', password: 'qwerty', encoding: 'UTF-8') assert !aborted + assert_equal [%w[mysql mysql5], '--host=locahost', '--port=1234', '--socket=socket', '--user=user', '--default-character-set=UTF-8', '-p', 'db'], dbconsole.find_cmd_and_exec_args end def test_mysql_include_password - dbconsole.expects(:find_cmd_and_exec).with(%w[mysql mysql5], '--user=user', '--password=qwerty', 'db') start({adapter: 'mysql', database: 'db', username: 'user', password: 'qwerty'}, ['-p']) assert !aborted + assert_equal [%w[mysql mysql5], '--user=user', '--password=qwerty', 'db'], dbconsole.find_cmd_and_exec_args end def test_postgresql - dbconsole.expects(:find_cmd_and_exec).with('psql', 'db') start(adapter: 'postgresql', database: 'db') assert !aborted + assert_equal ['psql', 'db'], dbconsole.find_cmd_and_exec_args end def test_postgresql_full - dbconsole.expects(:find_cmd_and_exec).with('psql', 'db') start(adapter: 'postgresql', database: 'db', username: 'user', password: 'q1w2e3', host: 'host', port: 5432) assert !aborted + assert_equal ['psql', 'db'], dbconsole.find_cmd_and_exec_args assert_equal 'user', ENV['PGUSER'] assert_equal 'host', ENV['PGHOST'] assert_equal '5432', ENV['PGPORT'] @@ -137,60 +151,60 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase end def test_postgresql_include_password - dbconsole.expects(:find_cmd_and_exec).with('psql', 'db') start({adapter: 'postgresql', database: 'db', username: 'user', password: 'q1w2e3'}, ['-p']) assert !aborted + assert_equal ['psql', 'db'], dbconsole.find_cmd_and_exec_args assert_equal 'user', ENV['PGUSER'] assert_equal 'q1w2e3', ENV['PGPASSWORD'] end def test_sqlite - dbconsole.expects(:find_cmd_and_exec).with('sqlite', 'db') start(adapter: 'sqlite', database: 'db') assert !aborted + assert_equal ['sqlite', 'db'], dbconsole.find_cmd_and_exec_args end def test_sqlite3 - dbconsole.expects(:find_cmd_and_exec).with('sqlite3', Rails.root.join('db.sqlite3').to_s) start(adapter: 'sqlite3', database: 'db.sqlite3') assert !aborted + assert_equal ['sqlite3', Rails.root.join('db.sqlite3').to_s], dbconsole.find_cmd_and_exec_args end def test_sqlite3_mode - dbconsole.expects(:find_cmd_and_exec).with('sqlite3', '-html', Rails.root.join('db.sqlite3').to_s) start({adapter: 'sqlite3', database: 'db.sqlite3'}, ['--mode', 'html']) assert !aborted + assert_equal ['sqlite3', '-html', Rails.root.join('db.sqlite3').to_s], dbconsole.find_cmd_and_exec_args end def test_sqlite3_header - dbconsole.expects(:find_cmd_and_exec).with('sqlite3', '-header', Rails.root.join('db.sqlite3').to_s) start({adapter: 'sqlite3', database: 'db.sqlite3'}, ['--header']) + assert_equal ['sqlite3', '-header', Rails.root.join('db.sqlite3').to_s], dbconsole.find_cmd_and_exec_args end def test_sqlite3_db_absolute_path - dbconsole.expects(:find_cmd_and_exec).with('sqlite3', '/tmp/db.sqlite3') start(adapter: 'sqlite3', database: '/tmp/db.sqlite3') assert !aborted + assert_equal ['sqlite3', '/tmp/db.sqlite3'], dbconsole.find_cmd_and_exec_args end def test_sqlite3_db_without_defined_rails_root - Rails.stubs(:respond_to?) - Rails.expects(:respond_to?).with(:root).once.returns(false) - dbconsole.expects(:find_cmd_and_exec).with('sqlite3', Rails.root.join('../config/db.sqlite3').to_s) - start(adapter: 'sqlite3', database: 'config/db.sqlite3') - assert !aborted + Rails.stub(:respond_to?, false) do + start(adapter: 'sqlite3', database: 'config/db.sqlite3') + assert !aborted + assert_equal ['sqlite3', Rails.root.join('../config/db.sqlite3').to_s], dbconsole.find_cmd_and_exec_args + end end def test_oracle - dbconsole.expects(:find_cmd_and_exec).with('sqlplus', 'user@db') start(adapter: 'oracle', database: 'db', username: 'user', password: 'secret') assert !aborted + assert_equal ['sqlplus', 'user@db'], dbconsole.find_cmd_and_exec_args end def test_oracle_include_password - dbconsole.expects(:find_cmd_and_exec).with('sqlplus', 'user/secret@db') start({adapter: 'oracle', database: 'db', username: 'user', password: 'secret'}, ['-p']) assert !aborted + assert_equal ['sqlplus', 'user/secret@db'], dbconsole.find_cmd_and_exec_args end def test_unknown_command_line_client @@ -223,16 +237,27 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase private def app_db_config(results) - Rails.application.config.stubs(:database_configuration).returns(results) + Rails.application.config.stub(:database_configuration, results || {}) do + yield + end end def dbconsole - @dbconsole ||= Rails::DBConsole.new(nil) + @dbconsole ||= Class.new(Rails::DBConsole) do + attr_reader :find_cmd_and_exec_args + + def find_cmd_and_exec(*args) + @find_cmd_and_exec_args = args + end + end.new(nil) end def start(config = {}, argv = []) - dbconsole.stubs(config: config.stringify_keys, arguments: argv) - capture_abort { dbconsole.start } + dbconsole.stub(:config, config.stringify_keys) do + dbconsole.stub(:arguments, argv) do + capture_abort { dbconsole.start } + end + end end def capture_abort diff --git a/railties/test/configuration/middleware_stack_proxy_test.rb b/railties/test/configuration/middleware_stack_proxy_test.rb index 6f3e45f320..d5072614cf 100644 --- a/railties/test/configuration/middleware_stack_proxy_test.rb +++ b/railties/test/configuration/middleware_stack_proxy_test.rb @@ -1,3 +1,4 @@ +require 'active_support' require 'active_support/testing/autorun' require 'rails/configuration' require 'active_support/test_case' diff --git a/railties/test/engine_test.rb b/railties/test/engine_test.rb index 7970913d21..f46fb748f5 100644 --- a/railties/test/engine_test.rb +++ b/railties/test/engine_test.rb @@ -11,4 +11,15 @@ class EngineTest < ActiveSupport::TestCase assert !engine.routes? end + + def test_application_can_be_subclassed + klass = Class.new(Rails::Application) do + attr_reader :hello + def initialize + @hello = "world" + super + end + end + assert_equal "world", klass.instance.hello + end end diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb index 0db40c1d32..2206e389b5 100644 --- a/railties/test/generators/actions_test.rb +++ b/railties/test/generators/actions_test.rb @@ -1,6 +1,7 @@ require 'generators/generators_test_helper' require 'rails/generators/rails/app/app_generator' require 'env_helpers' +require 'mocha/setup' # FIXME: stop using mocha class ActionsTest < Rails::Generators::TestCase include GeneratorsTestHelper @@ -41,13 +42,13 @@ class ActionsTest < Rails::Generators::TestCase def test_add_source_adds_source_to_gemfile run_generator action :add_source, 'http://gems.github.com' - assert_file 'Gemfile', /source "http:\/\/gems\.github\.com"/ + assert_file 'Gemfile', /source 'http:\/\/gems\.github\.com'/ end def test_gem_should_put_gem_dependency_in_gemfile run_generator action :gem, 'will-paginate' - assert_file 'Gemfile', /gem "will\-paginate"/ + assert_file 'Gemfile', /gem 'will\-paginate'/ end def test_gem_with_version_should_include_version_in_gemfile @@ -55,7 +56,7 @@ class ActionsTest < Rails::Generators::TestCase action :gem, 'rspec', '>=2.0.0.a5' - assert_file 'Gemfile', /gem "rspec", ">=2.0.0.a5"/ + assert_file 'Gemfile', /gem 'rspec', '>=2.0.0.a5'/ end def test_gem_should_insert_on_separate_lines @@ -66,8 +67,8 @@ class ActionsTest < Rails::Generators::TestCase action :gem, 'rspec' action :gem, 'rspec-rails' - assert_file 'Gemfile', /^gem "rspec"$/ - assert_file 'Gemfile', /^gem "rspec-rails"$/ + assert_file 'Gemfile', /^gem 'rspec'$/ + assert_file 'Gemfile', /^gem 'rspec-rails'$/ end def test_gem_should_include_options @@ -75,7 +76,25 @@ class ActionsTest < Rails::Generators::TestCase action :gem, 'rspec', github: 'dchelimsky/rspec', tag: '1.2.9.rc1' - assert_file 'Gemfile', /gem "rspec", github: "dchelimsky\/rspec", tag: "1\.2\.9\.rc1"/ + assert_file 'Gemfile', /gem 'rspec', github: 'dchelimsky\/rspec', tag: '1\.2\.9\.rc1'/ + end + + def test_gem_with_non_string_options + run_generator + + action :gem, 'rspec', require: false + action :gem, 'rspec-rails', group: [:development, :test] + + assert_file 'Gemfile', /^gem 'rspec', require: false$/ + assert_file 'Gemfile', /^gem 'rspec-rails', group: \[:development, :test\]$/ + end + + def test_gem_falls_back_to_inspect_if_string_contains_single_quote + run_generator + + action :gem, 'rspec', ">=2.0'0" + + assert_file 'Gemfile', /^gem 'rspec', ">=2\.0'0"$/ end def test_gem_group_should_wrap_gems_in_a_group @@ -89,7 +108,7 @@ class ActionsTest < Rails::Generators::TestCase gem 'fakeweb' end - assert_file 'Gemfile', /\ngroup :development, :test do\n gem "rspec-rails"\nend\n\ngroup :test do\n gem "fakeweb"\nend/ + assert_file 'Gemfile', /\ngroup :development, :test do\n gem 'rspec-rails'\nend\n\ngroup :test do\n gem 'fakeweb'\nend/ end def test_environment_should_include_data_in_environment_initializer_block @@ -234,7 +253,7 @@ class ActionsTest < Rails::Generators::TestCase protected def action(*args, &block) - silence(:stdout){ generator.send(*args, &block) } + capture(:stdout){ generator.send(*args, &block) } end end diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index 195f13bdc3..b7cbe04003 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -1,6 +1,7 @@ require 'generators/generators_test_helper' require 'rails/generators/rails/app/app_generator' require 'generators/shared_generator_tests' +require 'mocha/setup' # FIXME: stop using mocha DEFAULT_APP_FILES = %w( .gitignore @@ -21,6 +22,7 @@ DEFAULT_APP_FILES = %w( bin/bundle bin/rails bin/rake + bin/setup config/environments config/initializers config/locales @@ -58,8 +60,8 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_assets run_generator - assert_file("app/views/layouts/application.html.erb", /stylesheet_link_tag\s+"application", media: "all", "data-turbolinks-track" => true/) - assert_file("app/views/layouts/application.html.erb", /javascript_include_tag\s+"application", "data-turbolinks-track" => true/) + assert_file("app/views/layouts/application.html.erb", /stylesheet_link_tag\s+'application', media: 'all', 'data-turbolinks-track' => 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 @@ -119,7 +121,7 @@ class AppGeneratorTest < Rails::Generators::TestCase generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: app_moved_root, shell: @shell generator.send(:app_const) - quietly { generator.send(:create_config_files) } + quietly { generator.send(:update_config_files) } assert_file "myapp_moved/config/environment.rb", /Rails\.application\.initialize!/ assert_file "myapp_moved/config/initializers/session_store.rb", /_myapp_session/ end @@ -134,10 +136,46 @@ class AppGeneratorTest < Rails::Generators::TestCase generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: app_root, shell: @shell generator.send(:app_const) - quietly { generator.send(:create_config_files) } + quietly { generator.send(:update_config_files) } assert_file "myapp/config/initializers/session_store.rb", /_myapp_session/ end + def test_new_application_use_json_serialzier + run_generator + + assert_file("config/initializers/cookies_serializer.rb", /Rails\.application\.config\.action_dispatch\.cookies_serializer = :json/) + end + + def test_rails_update_keep_the_cookie_serializer_if_it_is_already_configured + app_root = File.join(destination_root, 'myapp') + run_generator [app_root] + + Rails.application.config.root = app_root + Rails.application.class.stubs(:name).returns("Myapp") + Rails.application.stubs(:is_a?).returns(Rails::Application) + + generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: app_root, shell: @shell + generator.send(:app_const) + quietly { generator.send(:update_config_files) } + assert_file("#{app_root}/config/initializers/cookies_serializer.rb", /Rails\.application\.config\.action_dispatch\.cookies_serializer = :json/) + end + + def test_rails_update_set_the_cookie_serializer_to_marchal_if_it_is_not_already_configured + app_root = File.join(destination_root, 'myapp') + run_generator [app_root] + + FileUtils.rm("#{app_root}/config/initializers/cookies_serializer.rb") + + Rails.application.config.root = app_root + Rails.application.class.stubs(:name).returns("Myapp") + Rails.application.stubs(:is_a?).returns(Rails::Application) + + generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: app_root, shell: @shell + generator.send(:app_const) + quietly { generator.send(:update_config_files) } + assert_file("#{app_root}/config/initializers/cookies_serializer.rb", /Rails\.application\.config\.action_dispatch\.cookies_serializer = :marshal/) + end + def test_application_names_are_not_singularized run_generator [File.join(destination_root, "hats")] assert_file "hats/config/environment.rb", /Rails\.application\.initialize!/ @@ -156,66 +194,20 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_config_database_is_added_by_default run_generator assert_file "config/database.yml", /sqlite3/ - unless defined?(JRUBY_VERSION) - assert_gem "sqlite3" - else + if defined?(JRUBY_VERSION) assert_gem "activerecord-jdbcsqlite3-adapter" - end - end - - def test_add_gemfile_entry - Tempfile.open('my_template') do |template| - template.puts 'gemfile_entry "tenderlove"' - template.flush - template.close - run_generator([destination_root, "-m", template.path]) - assert_file "Gemfile", /tenderlove/ - end - end - - def test_add_skip_entry - Tempfile.open 'my_template' do |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 - end - end - - def test_skip_turbolinks_when_it_is_not_on_gemfile - Tempfile.open 'my_template' do |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 "app/views/layouts/application.html.erb" do |contents| - assert_no_match 'turbolinks', contents - end - - assert_file "app/views/layouts/application.html.erb" do |contents| - assert_no_match('data-turbolinks-track', contents) - end - - assert_file "app/assets/javascripts/application.js" do |contents| - assert_no_match 'turbolinks', contents - end + else + assert_gem "sqlite3" end end def test_config_another_database run_generator([destination_root, "-d", "mysql"]) assert_file "config/database.yml", /mysql/ - unless defined?(JRUBY_VERSION) - assert_gem "mysql2" - else + if defined?(JRUBY_VERSION) assert_gem "activerecord-jdbcmysql-adapter" + else + assert_gem "mysql2" end end @@ -227,10 +219,10 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_config_postgresql_database run_generator([destination_root, "-d", "postgresql"]) assert_file "config/database.yml", /postgresql/ - unless defined?(JRUBY_VERSION) - assert_gem "pg" - else + if defined?(JRUBY_VERSION) assert_gem "activerecord-jdbcpostgresql-adapter" + else + assert_gem "pg" end end @@ -259,9 +251,9 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_gem "activerecord-jdbc-adapter" end - def test_config_jdbc_database_when_no_option_given - if defined?(JRUBY_VERSION) - run_generator([destination_root]) + if defined?(JRUBY_VERSION) + def test_config_jdbc_database_when_no_option_given + run_generator assert_file "config/database.yml", /sqlite3/ assert_gem "activerecord-jdbcsqlite3-adapter" end @@ -276,13 +268,9 @@ class AppGeneratorTest < Rails::Generators::TestCase end end - def test_generator_if_skip_action_view_is_given - run_generator [destination_root, "--skip-action-view"] - assert_file "config/application.rb", /#\s+require\s+["']action_view\/railtie["']/ - end - def test_generator_if_skip_sprockets_is_given run_generator [destination_root, "--skip-sprockets"] + assert_no_file "config/initializers/assets.rb" assert_file "config/application.rb" do |content| assert_match(/#\s+require\s+["']sprockets\/railtie["']/, content) end @@ -298,23 +286,15 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_no_match(/config\.assets\.digest = true/, content) assert_no_match(/config\.assets\.js_compressor = :uglifier/, content) assert_no_match(/config\.assets\.css_compressor = :sass/, content) - assert_no_match(/config\.assets\.version = '1\.0'/, content) end end def test_inclusion_of_javascript_runtime - run_generator([destination_root]) + run_generator if defined?(JRUBY_VERSION) assert_gem "therubyrhino" else - assert_file "Gemfile", /# gem\s+["']therubyracer["']+, \s+platforms: :ruby$/ - end - end - - def test_inclusion_of_plateform_dependent_gems - run_generator([destination_root]) - if RUBY_ENGINE == 'rbx' - assert_gem 'rubysl' + assert_file "Gemfile", /# gem 'therubyracer', platforms: :ruby/ end end @@ -343,8 +323,8 @@ 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| @@ -355,23 +335,26 @@ class AppGeneratorTest < Rails::Generators::TestCase def test_inclusion_of_jbuilder run_generator - assert_file "Gemfile", /gem 'jbuilder'/ + assert_gem 'jbuilder' end - def test_inclusion_of_debugger + def test_inclusion_of_a_debugger run_generator if defined?(JRUBY_VERSION) assert_file "Gemfile" do |content| + assert_no_match(/byebug/, content) assert_no_match(/debugger/, content) end + elsif RUBY_VERSION < '2.0.0' + assert_gem 'debugger' else - assert_file "Gemfile", /# gem 'debugger'/ + assert_gem 'byebug' 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 @@ -407,10 +390,11 @@ class AppGeneratorTest < Rails::Generators::TestCase run_generator [destination_root, "--skip-test-unit", "--skip-active-record"] assert_file "config/application.rb", /#\s+require\s+["']rails\/test_unit\/railtie["']/ assert_file "config/application.rb", /#\s+require\s+["']active_record\/railtie["']/ + assert_file "config/application.rb", /\s+require\s+["']active_job\/railtie["']/ end def test_new_hash_style - run_generator [destination_root] + run_generator assert_file "config/initializers/session_store.rb" do |file| assert_match(/config.session_store :cookie_store, key: '_.+_session'/, file) end @@ -431,18 +415,25 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_file "foo bar/config/initializers/session_store.rb", /key: '_foo_bar/ end + def test_web_console + run_generator + assert_gem 'web-console' + end + def test_spring run_generator - assert_file "Gemfile", /gem 'spring', \s+group: :development/ + assert_gem 'spring' 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 @@ -459,13 +450,79 @@ class AppGeneratorTest < Rails::Generators::TestCase end end -protected + def test_generator_if_skip_turbolinks_is_given + run_generator [destination_root, "--skip-turbolinks"] + + assert_file "Gemfile" do |content| + assert_no_match(/turbolinks/, content) + end + assert_file "app/views/layouts/application.html.erb" do |content| + assert_no_match(/data-turbolinks-track/, content) + end + assert_file "app/assets/javascripts/application.js" do |content| + assert_no_match(/turbolinks/, 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 + + def test_psych_gem + run_generator + gem_regex = /gem 'psych',\s+'~> 2.0',\s+platforms: :rbx/ + + assert_file "Gemfile" do |content| + if defined?(Rubinius) + assert_match(gem_regex, content) + else + assert_no_match(gem_regex, content) + end + end + end + + def test_after_bundle_callback + path = 'http://example.org/rails_template' + template = %{ after_bundle { run 'echo ran after_bundle' } } + template.instance_eval "def read; self; end" # Make the string respond to read + + generator([destination_root], template: path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template) + + bundler_first = sequence('bundle, binstubs, after_bundle') + generator.expects(:bundle_command).with('install').once.in_sequence(bundler_first) + generator.expects(:bundle_command).with('exec spring binstub --all').in_sequence(bundler_first) + generator.expects(:run).with('echo ran after_bundle').in_sequence(bundler_first) + + quietly { generator.invoke_all } + end + + protected def action(*args, &block) - silence(:stdout) { generator.send(*args, &block) } + capture(:stdout) { generator.send(*args, &block) } end def assert_gem(gem) - assert_file "Gemfile", /^gem\s+["']#{gem}["']$/ + assert_file "Gemfile", /^\s*gem\s+["']#{gem}["']$*/ end end diff --git a/railties/test/generators/argv_scrubber_test.rb b/railties/test/generators/argv_scrubber_test.rb index a94350cbd7..31e07bc8da 100644 --- a/railties/test/generators/argv_scrubber_test.rb +++ b/railties/test/generators/argv_scrubber_test.rb @@ -16,7 +16,7 @@ module Rails output = nil exit_code = nil scrubber.extend(Module.new { - define_method(:puts) { |str| output = str } + define_method(:puts) { |string| output = string } define_method(:exit) { |code| exit_code = code } }) scrubber.prepare! diff --git a/railties/test/generators/controller_generator_test.rb b/railties/test/generators/controller_generator_test.rb index 2268f04839..a7d56dd352 100644 --- a/railties/test/generators/controller_generator_test.rb +++ b/railties/test/generators/controller_generator_test.rb @@ -28,13 +28,11 @@ class ControllerGeneratorTest < Rails::Generators::TestCase def test_invokes_helper run_generator assert_file "app/helpers/account_helper.rb" - assert_file "test/helpers/account_helper_test.rb" end def test_does_not_invoke_helper_if_required run_generator ["account", "--skip-helper"] assert_no_file "app/helpers/account_helper.rb" - assert_no_file "test/helpers/account_helper_test.rb" end def test_invokes_assets @@ -67,7 +65,14 @@ 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_skip_routes + run_generator ["account", "foo", "--skip-routes"] + assert_file "config/routes.rb" do |routes| + assert_no_match(/get 'account\/foo'/, routes) + end end def test_invokes_default_template_engine_even_with_no_action @@ -91,6 +96,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/generated_attribute_test.rb b/railties/test/generators/generated_attribute_test.rb index c48bc20899..ee7c009305 100644 --- a/railties/test/generators/generated_attribute_test.rb +++ b/railties/test/generators/generated_attribute_test.rb @@ -141,4 +141,12 @@ class GeneratedAttributeTest < Rails::Generators::TestCase assert_equal "post_id", create_generated_attribute('references', 'post').column_name assert_equal "post_id", create_generated_attribute('belongs_to', 'post').column_name end + + def test_parse_required_attribute_with_index + att = Rails::Generators::GeneratedAttribute.parse("supplier:references{required}:index") + assert_equal "supplier", att.name + assert_equal :references, att.type + assert att.has_index? + assert att.required? + 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 77ec2f1c0c..6cc91f166b 100644 --- a/railties/test/generators/generators_test_helper.rb +++ b/railties/test/generators/generators_test_helper.rb @@ -7,7 +7,7 @@ module Rails class << self remove_possible_method :root def root - @root ||= File.expand_path(File.join(File.dirname(__FILE__), '..', 'fixtures')) + @root ||= Pathname.new(File.expand_path('../../fixtures', __FILE__)) end end end @@ -41,4 +41,12 @@ module GeneratorsTestHelper FileUtils.mkdir_p(destination) FileUtils.cp routes, destination end + + def quietly + silence_stream(STDOUT) do + silence_stream(STDERR) do + yield + end + end + end end diff --git a/railties/test/generators/helper_generator_test.rb b/railties/test/generators/helper_generator_test.rb index 81d4fcb129..add04f21a4 100644 --- a/railties/test/generators/helper_generator_test.rb +++ b/railties/test/generators/helper_generator_test.rb @@ -13,26 +13,11 @@ class HelperGeneratorTest < Rails::Generators::TestCase assert_file "app/helpers/admin_helper.rb", /module AdminHelper/ end - def test_invokes_default_test_framework - run_generator - assert_file "test/helpers/admin_helper_test.rb", /class AdminHelperTest < ActionView::TestCase/ - end - - def test_logs_if_the_test_framework_cannot_be_found - content = run_generator ["admin", "--test-framework=rspec"] - assert_match(/rspec \[not found\]/, content) - end - def test_check_class_collision content = capture(:stderr){ run_generator ["object"] } assert_match(/The name 'ObjectHelper' is either already used in your application or reserved/, content) end - def test_check_class_collision_on_tests - content = capture(:stderr){ run_generator ["another_object"] } - assert_match(/The name 'AnotherObjectHelperTest' is either already used in your application or reserved/, content) - end - def test_namespaced_and_not_namespaced_helpers run_generator ["products"] diff --git a/railties/test/generators/mailer_generator_test.rb b/railties/test/generators/mailer_generator_test.rb index d209801f60..25649881eb 100644 --- a/railties/test/generators/mailer_generator_test.rb +++ b/railties/test/generators/mailer_generator_test.rb @@ -69,12 +69,12 @@ class MailerGeneratorTest < Rails::Generators::TestCase 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 @@ -82,12 +82,12 @@ class MailerGeneratorTest < Rails::Generators::TestCase def test_invokes_default_html_template_engine run_generator assert_file "app/views/notifier/foo.html.erb" do |view| - assert_match(%r(app/views/notifier/foo\.html\.erb), 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(app/views/notifier/bar\.html\.erb), view) + assert_match(%r(\sapp/views/notifier/bar\.html\.erb), view) assert_match(/<%= @greeting %>/, view) end end diff --git a/railties/test/generators/migration_generator_test.rb b/railties/test/generators/migration_generator_test.rb index d876597944..72f5fe29ca 100644 --- a/railties/test/generators/migration_generator_test.rb +++ b/railties/test/generators/migration_generator_test.rb @@ -159,6 +159,18 @@ class MigrationGeneratorTest < Rails::Generators::TestCase end end + def test_add_migration_with_required_references + migration = "add_references_to_books" + run_generator [migration, "author:belongs_to{required}", "distributor:references{polymorphic,required}"] + + assert_migration "db/migrate/#{migration}.rb" do |content| + assert_method :change, content do |change| + assert_match(/add_reference :books, :author, index: true, null: false/, change) + assert_match(/add_reference :books, :distributor, polymorphic: true, index: true, null: false/, change) + end + end + end + def test_create_join_table_migration migration = "add_media_join_table" run_generator [migration, "artist_id", "musics:uniq"] @@ -197,4 +209,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..c78597c81b 100644 --- a/railties/test/generators/model_generator_test.rb +++ b/railties/test/generators/model_generator_test.rb @@ -1,5 +1,6 @@ require 'generators/generators_test_helper' require 'rails/generators/rails/model/model_generator' +require 'active_support/core_ext/string/strip' class ModelGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper @@ -34,6 +35,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/ @@ -215,7 +223,7 @@ class ModelGeneratorTest < Rails::Generators::TestCase def test_migration_with_timestamps run_generator - assert_migration "db/migrate/create_accounts.rb", /t.timestamps/ + assert_migration "db/migrate/create_accounts.rb", /t.timestamps null: false/ end def test_migration_timestamps_are_skipped @@ -356,6 +364,49 @@ class ModelGeneratorTest < Rails::Generators::TestCase end end + def test_required_belongs_to_adds_required_association + run_generator ["account", "supplier:references{required}"] + + expected_file = <<-FILE.strip_heredoc + class Account < ActiveRecord::Base + belongs_to :supplier, required: true + end + FILE + assert_file "app/models/account.rb", expected_file + end + + def test_required_polymorphic_belongs_to_generages_correct_model + run_generator ["account", "supplier:references{required,polymorphic}"] + + expected_file = <<-FILE.strip_heredoc + class Account < ActiveRecord::Base + belongs_to :supplier, polymorphic: true, required: true + end + FILE + assert_file "app/models/account.rb", expected_file + end + + def test_required_and_polymorphic_are_order_independent + run_generator ["account", "supplier:references{polymorphic.required}"] + + expected_file = <<-FILE.strip_heredoc + class Account < ActiveRecord::Base + belongs_to :supplier, polymorphic: true, required: true + end + FILE + assert_file "app/models/account.rb", expected_file + end + + def test_required_adds_null_false_to_column + run_generator ["account", "supplier:references{required}"] + + assert_migration "db/migrate/create_accounts.rb" do |m| + assert_method :change, m do |up| + assert_match(/t\.references :supplier,.*\snull: false/, up) + end + end + end + private def assert_generated_fixture(path, parsed_contents) fixture_file = File.new File.expand_path(path, destination_root) diff --git a/railties/test/generators/named_base_test.rb b/railties/test/generators/named_base_test.rb index ac5cfff229..4199e00b0d 100644 --- a/railties/test/generators/named_base_test.rb +++ b/railties/test/generators/named_base_test.rb @@ -1,5 +1,6 @@ require 'generators/generators_test_helper' require 'rails/generators/rails/scaffold_controller/scaffold_controller_generator' +require 'mocha/setup' # FIXME: stop using mocha # Mock out what we need from AR::Base. module ActiveRecord diff --git a/railties/test/generators/namespaced_generators_test.rb b/railties/test/generators/namespaced_generators_test.rb index e17925ff65..7eeb084eab 100644 --- a/railties/test/generators/namespaced_generators_test.rb +++ b/railties/test/generators/namespaced_generators_test.rb @@ -47,7 +47,6 @@ class NamespacedControllerGeneratorTest < NamespacedGeneratorTestCase def test_helper_is_also_namespaced run_generator assert_file "app/helpers/test_app/account_helper.rb", /module TestApp/, / module AccountHelper/ - assert_file "test/helpers/test_app/account_helper_test.rb", /module TestApp/, / class AccountHelperTest/ end def test_invokes_default_test_framework @@ -63,7 +62,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 @@ -229,7 +228,6 @@ class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase # Helpers assert_file "app/helpers/test_app/product_lines_helper.rb" - assert_file "test/helpers/test_app/product_lines_helper_test.rb" # Stylesheets assert_file "app/assets/stylesheets/scaffold.css" @@ -260,7 +258,6 @@ class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase # Helpers assert_no_file "app/helpers/test_app/product_lines_helper.rb" - assert_no_file "test/helpers/test_app/product_lines_helper_test.rb" # Stylesheets (should not be removed) assert_file "app/assets/stylesheets/scaffold.css" @@ -297,7 +294,6 @@ class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase # Helpers assert_file "app/helpers/test_app/admin/roles_helper.rb" - assert_file "test/helpers/test_app/admin/roles_helper_test.rb" # Stylesheets assert_file "app/assets/stylesheets/scaffold.css" @@ -329,7 +325,6 @@ class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase # Helpers assert_no_file "app/helpers/test_app/admin/roles_helper.rb" - assert_no_file "test/helpers/test_app/admin/roles_helper_test.rb" # Stylesheets (should not be removed) assert_file "app/assets/stylesheets/scaffold.css" @@ -366,7 +361,6 @@ class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase # Helpers assert_file "app/helpers/test_app/admin/user/special/roles_helper.rb" - assert_file "test/helpers/test_app/admin/user/special/roles_helper_test.rb" # Stylesheets assert_file "app/assets/stylesheets/scaffold.css" @@ -397,7 +391,6 @@ class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase # Helpers assert_no_file "app/helpers/test_app/admin/user/special/roles_helper.rb" - assert_no_file "test/helpers/test_app/admin/user/special/roles_helper_test.rb" # Stylesheets (should not be removed) assert_file "app/assets/stylesheets/scaffold.css" diff --git a/railties/test/generators/plugin_generator_test.rb b/railties/test/generators/plugin_generator_test.rb index 932cd75bcb..4329c6e1a4 100644 --- a/railties/test/generators/plugin_generator_test.rb +++ b/railties/test/generators/plugin_generator_test.rb @@ -1,6 +1,7 @@ require 'generators/generators_test_helper' require 'rails/generators/rails/plugin/plugin_generator' require 'generators/shared_generator_tests' +require 'mocha/setup' # FIXME: stop using mocha DEFAULT_PLUGIN_FILES = %w( .gitignore @@ -53,7 +54,10 @@ class PluginGeneratorTest < Rails::Generators::TestCase run_generator assert_file "README.rdoc", /Bukkits/ assert_no_file "config/routes.rb" - assert_file "test/test_helper.rb" + assert_file "test/test_helper.rb" do |content| + assert_match(/require.+test\/dummy\/config\/environment/, content) + assert_match(/ActiveRecord::Migrator\.migrations_paths.+test\/dummy\/db\/migrate/, content) + end assert_file "test/bukkits_test.rb", /assert_kind_of Module, Bukkits/ end @@ -64,14 +68,17 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_file "test/integration/navigation_test.rb", /ActionDispatch::IntegrationTest/ end - def test_inclusion_of_debugger + def test_inclusion_of_a_debugger run_generator [destination_root, '--full'] if defined?(JRUBY_VERSION) assert_file "Gemfile" do |content| + assert_no_match(/byebug/, content) assert_no_match(/debugger/, content) end - else + elsif RUBY_VERSION < '2.0.0' assert_file "Gemfile", /# gem 'debugger'/ + else + assert_file "Gemfile", /# gem 'byebug'/ end end @@ -91,7 +98,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase end def test_generating_adds_dummy_app_without_javascript_and_assets_deps - run_generator [destination_root] + run_generator assert_file "test/dummy/app/assets/stylesheets/application.css" @@ -156,7 +163,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 @@ -185,22 +192,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 @@ -238,6 +245,10 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_match(/stylesheet_link_tag\s+['"]bukkits\/application['"]/, contents) assert_match(/javascript_include_tag\s+['"]bukkits\/application['"]/, contents) end + assert_file "test/test_helper.rb" do |content| + assert_match(/ActiveRecord::Migrator\.migrations_paths.+\.\.\/test\/dummy\/db\/migrate/, content) + assert_match(/ActiveRecord::Migrator\.migrations_paths.+<<.+\.\.\/db\/migrate/, content) + end end def test_creating_gemspec @@ -266,6 +277,10 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_file "spec/dummy" assert_file "spec/dummy/config/application.rb" assert_no_file "test/dummy" + assert_file "test/test_helper.rb" do |content| + assert_match(/require.+spec\/dummy\/config\/environment/, content) + assert_match(/ActiveRecord::Migrator\.migrations_paths.+spec\/dummy\/db\/migrate/, content) + end end def test_creating_dummy_application_with_different_name @@ -273,6 +288,10 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_file "spec/fake" assert_file "spec/fake/config/application.rb" assert_no_file "test/dummy" + assert_file "test/test_helper.rb" do |content| + assert_match(/require.+spec\/fake\/config\/environment/, content) + assert_match(/ActiveRecord::Migrator\.migrations_paths.+spec\/fake\/db\/migrate/, content) + end end def test_creating_dummy_without_tests_but_with_dummy_path @@ -280,6 +299,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_file "spec/dummy" assert_file "spec/dummy/config/application.rb" assert_no_file "test" + assert_no_file "test/test_helper.rb" assert_file '.gitignore' do |contents| assert_match(/spec\/dummy/, contents) end @@ -309,7 +329,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_no_file "bukkits.gemspec" assert_file "Gemfile" do |contents| assert_no_match('gemspec', contents) - assert_match(/gem "rails", "~> #{Rails.version}"/, contents) + assert_match(/gem 'rails', '~> #{Rails.version}'/, contents) assert_match_sqlite3(contents) assert_no_match(/# gem "jquery-rails"/, contents) end @@ -320,7 +340,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase assert_no_file "bukkits.gemspec" assert_file "Gemfile" do |contents| assert_no_match('gemspec', contents) - assert_match(/gem "rails", "~> #{Rails.version}"/, contents) + assert_match(/gem 'rails', '~> #{Rails.version}'/, contents) assert_match_sqlite3(contents) end end @@ -331,7 +351,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase Object.const_set('APP_PATH', Rails.root) FileUtils.touch gemfile_path - run_generator [destination_root] + run_generator assert_file gemfile_path, /gem 'bukkits', path: 'tmp\/bukkits'/ ensure @@ -355,6 +375,52 @@ 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 + + def test_git_name_and_email_in_gemspec_file + name = `git config user.name`.chomp rescue "TODO: Write your name" + email = `git config user.email`.chomp rescue "TODO: Write your email address" + + run_generator + assert_file "bukkits.gemspec" do |contents| + assert_match name, contents + assert_match email, contents + end + end + + def test_git_name_in_license_file + name = `git config user.name`.chomp rescue "TODO: Write your name" + + run_generator + assert_file "MIT-LICENSE" do |contents| + assert_match name, contents + end + end + + def test_no_details_from_git_when_skip_git + name = "TODO: Write your name" + email = "TODO: Write your email address" + + run_generator [destination_root, '--skip-git'] + assert_file "MIT-LICENSE" do |contents| + assert_match name, contents + end + assert_file "bukkits.gemspec" do |contents| + assert_match name, contents + assert_match email, contents + end + end protected def action(*args, &block) @@ -366,10 +432,10 @@ protected end def assert_match_sqlite3(contents) - unless defined?(JRUBY_VERSION) - assert_match(/group :development do\n gem "sqlite3"\nend/, contents) + if defined?(JRUBY_VERSION) + assert_match(/group :development do\n gem 'activerecord-jdbcsqlite3-adapter'\nend/, contents) else - assert_match(/group :development do\n gem "activerecord-jdbcsqlite3-adapter"\nend/, contents) + assert_match(/group :development do\n gem 'sqlite3'\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..581d80d60e 100644 --- a/railties/test/generators/resource_generator_test.rb +++ b/railties/test/generators/resource_generator_test.rb @@ -36,7 +36,6 @@ class ResourceGeneratorTest < Rails::Generators::TestCase assert_file "test/controllers/accounts_controller_test.rb", /class AccountsControllerTest < ActionController::TestCase/ assert_file "app/helpers/accounts_helper.rb", /module AccountsHelper/ - assert_file "test/helpers/accounts_helper_test.rb", /class AccountsHelperTest < ActionView::TestCase/ end def test_resource_controller_with_actions @@ -63,19 +62,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..ca972a3bdd 100644 --- a/railties/test/generators/scaffold_controller_generator_test.rb +++ b/railties/test/generators/scaffold_controller_generator_test.rb @@ -81,7 +81,6 @@ class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase def test_helper_are_invoked_with_a_pluralized_name run_generator assert_file "app/helpers/users_helper.rb", /module UsersHelper/ - assert_file "test/helpers/users_helper_test.rb", /class UsersHelperTest < ActionView::TestCase/ end def test_views_are_generated @@ -93,6 +92,14 @@ class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase assert_no_file "app/views/layouts/users.html.erb" end + def test_index_page_have_notice + run_generator + + %w(index show).each do |view| + assert_file "app/views/users/#{view}.html.erb", /notice/ + end + end + def test_functional_tests run_generator ["User", "name:string", "age:integer", "organization:references{polymorphic}"] @@ -118,7 +125,6 @@ class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase def test_skip_helper_if_required run_generator ["User", "name:string", "age:integer", "--no-helper"] assert_no_file "app/helpers/users_helper.rb" - assert_no_file "test/helpers/users_helper_test.rb" end def test_skip_layout_if_required @@ -160,13 +166,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/scaffold_generator_test.rb b/railties/test/generators/scaffold_generator_test.rb index 524bbde2b7..637bde2a44 100644 --- a/railties/test/generators/scaffold_generator_test.rb +++ b/railties/test/generators/scaffold_generator_test.rb @@ -70,7 +70,6 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase # Helpers assert_file "app/helpers/product_lines_helper.rb" - assert_file "test/helpers/product_lines_helper_test.rb" # Assets assert_file "app/assets/stylesheets/scaffold.css" @@ -114,7 +113,6 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase # Helpers assert_no_file "app/helpers/product_lines_helper.rb" - assert_no_file "test/helpers/product_lines_helper_test.rb" # Assets assert_file "app/assets/stylesheets/scaffold.css", /:visited/ @@ -182,7 +180,6 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase # Helpers assert_file "app/helpers/admin/roles_helper.rb" - assert_file "test/helpers/admin/roles_helper_test.rb" # Assets assert_file "app/assets/stylesheets/scaffold.css", /:visited/ @@ -216,7 +213,6 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase # Helpers assert_no_file "app/helpers/admin/roles_helper.rb" - assert_no_file "test/helpers/admin/roles_helper_test.rb" # Assets assert_file "app/assets/stylesheets/scaffold.css" diff --git a/railties/test/generators/shared_generator_tests.rb b/railties/test/generators/shared_generator_tests.rb index 8e198d5fe1..b998fef42e 100644 --- a/railties/test/generators/shared_generator_tests.rb +++ b/railties/test/generators/shared_generator_tests.rb @@ -78,9 +78,12 @@ module SharedGeneratorTests end def test_template_raises_an_error_with_invalid_path - content = capture(:stderr){ run_generator([destination_root, "-m", "non/existent/path"]) } - assert_match(/The template \[.*\] could not be loaded/, content) - assert_match(/non\/existent\/path/, content) + quietly do + content = capture(:stderr){ run_generator([destination_root, "-m", "non/existent/path"]) } + + assert_match(/The template \[.*\] could not be loaded/, content) + assert_match(/non\/existent\/path/, content) + end end def test_template_is_executed_when_supplied @@ -89,7 +92,7 @@ module SharedGeneratorTests template.instance_eval "def read; self; end" # Make the string respond to read generator([destination_root], template: path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template) - assert_match(/It works!/, capture(:stdout) { generator.invoke_all }) + quietly { assert_match(/It works!/, capture(:stdout) { generator.invoke_all }) } end def test_template_is_executed_when_supplied_an_https_path @@ -98,7 +101,7 @@ module SharedGeneratorTests template.instance_eval "def read; self; end" # Make the string respond to read generator([destination_root], template: path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template) - assert_match(/It works!/, capture(:stdout) { generator.invoke_all }) + quietly { assert_match(/It works!/, capture(:stdout) { generator.invoke_all }) } end def test_dev_option diff --git a/railties/test/generators_test.rb b/railties/test/generators_test.rb index eac28badfe..127e059bf1 100644 --- a/railties/test/generators_test.rb +++ b/railties/test/generators_test.rb @@ -1,6 +1,7 @@ require 'generators/generators_test_helper' require 'rails/generators/rails/model/model_generator' require 'rails/generators/test_unit/model/model_generator' +require 'mocha/setup' # FIXME: stop using mocha class GeneratorsTest < Rails::Generators::TestCase include GeneratorsTestHelper @@ -21,8 +22,16 @@ class GeneratorsTest < Rails::Generators::TestCase end def test_invoke_when_generator_is_not_found - output = capture(:stdout){ Rails::Generators.invoke :unknown } - assert_equal "Could not find generator unknown.\n", output + name = :unknown + output = capture(:stdout){ Rails::Generators.invoke name } + assert_match "Could not find generator '#{name}'", output + assert_match "`rails generate --help`", output + end + + def test_generator_suggestions + name = :migrationz + output = capture(:stdout){ Rails::Generators.invoke name } + assert_match "Maybe you meant 'migration'", output end def test_help_when_a_generator_with_required_arguments_is_invoked_without_arguments @@ -143,6 +152,8 @@ class GeneratorsTest < Rails::Generators::TestCase klass = Rails::Generators.find_by_namespace(:plugin, :remarkable) assert klass assert_equal "test_unit:plugin", klass.namespace + ensure + Rails::Generators.fallbacks.delete(:remarkable) end def test_fallbacks_for_generators_on_find_by_namespace_with_context @@ -150,18 +161,26 @@ class GeneratorsTest < Rails::Generators::TestCase klass = Rails::Generators.find_by_namespace(:remarkable, :rails, :plugin) assert klass assert_equal "test_unit:plugin", klass.namespace + ensure + Rails::Generators.fallbacks.delete(:remarkable) end def test_fallbacks_for_generators_on_invoke Rails::Generators.fallbacks[:shoulda] = :test_unit TestUnit::Generators::ModelGenerator.expects(:start).with(["Account"], {}) Rails::Generators.invoke "shoulda:model", ["Account"] + ensure + Rails::Generators.fallbacks.delete(:shoulda) end def test_nested_fallbacks_for_generators + Rails::Generators.fallbacks[:shoulda] = :test_unit Rails::Generators.fallbacks[:super_shoulda] = :shoulda TestUnit::Generators::ModelGenerator.expects(:start).with(["Account"], {}) Rails::Generators.invoke "super_shoulda:model", ["Account"] + ensure + Rails::Generators.fallbacks.delete(:shoulda) + Rails::Generators.fallbacks.delete(:super_shoulda) end def test_developer_options_are_overwritten_by_user_options diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb index a1f1973563..40469e31d7 100644 --- a/railties/test/isolation/abstract_unit.rb +++ b/railties/test/isolation/abstract_unit.rb @@ -9,6 +9,7 @@ require 'fileutils' require 'bundler/setup' unless defined?(Bundler) +require 'active_support' require 'active_support/testing/autorun' require 'active_support/test_case' @@ -93,8 +94,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_SECRET_KEY_BASE'] ||= SecureRandom.hex(16) + ENV['RAILS_ENV'] = "development" + ENV['SECRET_KEY_BASE'] ||= SecureRandom.hex(16) FileUtils.rm_rf(app_path) FileUtils.cp_r(app_template_path, app_path) @@ -140,6 +141,7 @@ module TestHelpers config.eager_load = false config.session_store :cookie_store, key: "_myapp_session" config.active_support.deprecation = :log + config.active_support.test_order = :random config.action_controller.allow_forgery_protection = false RUBY end @@ -276,8 +278,12 @@ module TestHelpers end def use_frameworks(arr) - to_remove = [:actionmailer, - :activerecord] - arr + to_remove = [:actionmailer, :activerecord] - arr + + if to_remove.include?(:activerecord) + remove_from_config 'config.active_record.*' + end + $:.reject! {|path| path =~ %r'/(#{to_remove.join('|')})/' } end @@ -291,6 +297,35 @@ class ActiveSupport::TestCase include TestHelpers::Paths include TestHelpers::Rack include TestHelpers::Generation + + self.test_order = :sorted + + private + + def capture(stream) + stream = stream.to_s + captured_stream = Tempfile.new(stream) + stream_io = eval("$#{stream}") + origin_stream = stream_io.dup + stream_io.reopen(captured_stream) + + yield + + stream_io.rewind + return captured_stream.read + ensure + captured_stream.close + captured_stream.unlink + stream_io.reopen(origin_stream) + end + + def quietly + silence_stream(STDOUT) do + silence_stream(STDERR) do + yield + end + end + end end # Create a scope and build a fixture rails app diff --git a/railties/test/path_generation_test.rb b/railties/test/path_generation_test.rb new file mode 100644 index 0000000000..13bf29d3c3 --- /dev/null +++ b/railties/test/path_generation_test.rb @@ -0,0 +1,88 @@ +# encoding: utf-8 +require 'abstract_unit' +require 'active_support/core_ext/object/with_options' +require 'active_support/core_ext/object/json' +require 'rails' +require 'rails/application' + +ROUTING = ActionDispatch::Routing + +class PathGenerationTest < ActiveSupport::TestCase + attr_reader :app + + class TestSet < ROUTING::RouteSet + def initialize(block) + @block = block + super() + end + + class Dispatcher < ROUTING::RouteSet::Dispatcher + def initialize(defaults, set, block) + super(defaults) + @block = block + @set = set + end + + def controller_reference(controller_param) + block = @block + set = @set + Class.new(ActionController::Base) { + include set.url_helpers + define_method(:process) { |name| block.call(self) } + def to_a; [200, {}, []]; end + } + end + end + + def dispatcher defaults + TestSet::Dispatcher.new defaults, self, @block + end + end + + def send_request(uri_or_host, method, path, script_name = nil) + host = uri_or_host.host unless path + path ||= uri_or_host.path + + params = {'PATH_INFO' => path, + 'REQUEST_METHOD' => method, + 'HTTP_HOST' => host } + + params['SCRIPT_NAME'] = script_name if script_name + + status, headers, body = app.call(params) + new_body = [] + body.each { |part| new_body << part } + body.close if body.respond_to? :close + [status, headers, new_body] + end + + def test_original_script_name + original_logger = Rails.logger + Rails.logger = Logger.new nil + + app = Class.new(Rails::Application) { + attr_accessor :controller + def initialize + super + app = self + @routes = TestSet.new ->(c) { app.controller = c } + secrets.secret_key_base = "foo" + secrets.secret_token = "foo" + end + def app; routes; end + } + + @app = app + app.routes.draw { resource :blogs } + + url = URI("http://example.org/blogs") + + send_request(url, 'GET', nil, '/FOO') + assert_equal '/FOO/blogs', app.instance.controller.blogs_path + + send_request(url, 'GET', nil) + assert_equal '/blogs', app.instance.controller.blogs_path + ensure + Rails.logger = original_logger + end +end diff --git a/railties/test/paths_test.rb b/railties/test/paths_test.rb index ed4559ec6f..1aeb9ec339 100644 --- a/railties/test/paths_test.rb +++ b/railties/test/paths_test.rb @@ -1,5 +1,6 @@ require 'abstract_unit' require 'rails/paths' +require 'mocha/setup' # FIXME: stop using mocha class PathsTest < ActiveSupport::TestCase def setup diff --git a/railties/test/rack_logger_test.rb b/railties/test/rack_logger_test.rb index 6ebd47fff9..fcc79b57fb 100644 --- a/railties/test/rack_logger_test.rb +++ b/railties/test/rack_logger_test.rb @@ -39,11 +39,11 @@ module Rails def setup @subscriber = Subscriber.new @notifier = ActiveSupport::Notifications.notifier - notifier.subscribe 'request.action_dispatch', subscriber + @subscription = notifier.subscribe 'request.action_dispatch', subscriber end def teardown - notifier.unsubscribe subscriber + notifier.unsubscribe @subscription end def test_notification diff --git a/railties/test/rails_info_controller_test.rb b/railties/test/rails_info_controller_test.rb index a9b237d0a5..8d61af4972 100644 --- a/railties/test/rails_info_controller_test.rb +++ b/railties/test/rails_info_controller_test.rb @@ -1,4 +1,5 @@ require 'abstract_unit' +require 'mocha/setup' # FIXME: stop using mocha module ActionController class Base diff --git a/railties/test/rails_info_test.rb b/railties/test/rails_info_test.rb index 44a5fd1904..92e4af25b5 100644 --- a/railties/test/rails_info_test.rb +++ b/railties/test/rails_info_test.rb @@ -38,21 +38,10 @@ class InfoTest < ActiveSupport::TestCase end def test_rails_version - assert_property 'Rails version', + assert_property 'Rails version', File.read(File.realpath('../../../RAILS_VERSION', __FILE__)).chomp end - def test_framework_version - assert_property 'Active Support version', ActiveSupport.version.to_s - end - - def test_frameworks_exist - Rails::Info.frameworks.each do |framework| - dir = File.dirname(__FILE__) + "/../../" + framework.delete('_') - assert File.directory?(dir), "#{framework.classify} does not exist" - end - end - def test_html_includes_middleware Rails::Info.module_eval do property 'Middleware', ['Rack::Lock', 'Rack::Static'] @@ -66,16 +55,6 @@ class InfoTest < ActiveSupport::TestCase end protected - def svn_info=(info) - Rails::Info.module_eval do - class << self - def svn_info - info - end - end - end - end - def properties Rails::Info.properties end diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index c4b18e9ea5..6239af2066 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -34,6 +34,7 @@ module RailtiesTest test "serving sprocket's assets" do @plugin.write "app/assets/javascripts/engine.js.erb", "<%= :alert %>();" + add_to_env_config "development", "config.assets.digest = false" boot_rails require 'rack/test' @@ -111,6 +112,74 @@ module RailtiesTest end end + test 'respects the order of railties when installing migrations' do + @blog = engine "blog" do |plugin| + plugin.write "lib/blog.rb", <<-RUBY + module Blog + class Engine < ::Rails::Engine + end + end + RUBY + end + + @plugin.write "db/migrate/1_create_users.rb", <<-RUBY + class CreateUsers < ActiveRecord::Migration + end + RUBY + + @blog.write "db/migrate/2_create_blogs.rb", <<-RUBY + class CreateBlogs < ActiveRecord::Migration + end + RUBY + + add_to_config("config.railties_order = [Bukkits::Engine, Blog::Engine, :all, :main_app]") + + boot_rails + + Dir.chdir(app_path) do + output = `bundle exec rake railties:install:migrations`.split("\n") + + assert_match(/Copied migration \d+_create_users.bukkits.rb from bukkits/, output.first) + assert_match(/Copied migration \d+_create_blogs.blog_engine.rb from blog_engine/, output.last) + end + end + + test "dont reverse default railties order" do + @api = engine "api" do |plugin| + plugin.write "lib/api.rb", <<-RUBY + module Api + class Engine < ::Rails::Engine; end + end + RUBY + end + + # added last but here is loaded before api engine + @core = engine "core" do |plugin| + plugin.write "lib/core.rb", <<-RUBY + module Core + class Engine < ::Rails::Engine; end + end + RUBY + end + + @core.write "db/migrate/1_create_users.rb", <<-RUBY + class CreateUsers < ActiveRecord::Migration; end + RUBY + + @api.write "db/migrate/2_create_keys.rb", <<-RUBY + class CreateKeys < ActiveRecord::Migration; end + RUBY + + boot_rails + + Dir.chdir(app_path) do + output = `bundle exec rake railties:install:migrations`.split("\n") + + assert_match(/Copied migration \d+_create_users.core_engine.rb from core_engine/, output.first) + assert_match(/Copied migration \d+_create_keys.api_engine.rb from api_engine/, output.last) + end + end + test "mountable engine should copy migrations within engine_path" do @plugin.write "lib/bukkits.rb", <<-RUBY module Bukkits @@ -454,7 +523,7 @@ YAML end end - test "engine is a rack app and can have his own middleware stack" do + test "engine is a rack app and can have its own middleware stack" do add_to_config("config.action_dispatch.show_exceptions = false") @plugin.write "lib/bukkits.rb", <<-RUBY @@ -592,11 +661,15 @@ YAML @plugin.write "app/models/bukkits/post.rb", <<-RUBY module Bukkits class Post - extend ActiveModel::Naming + include ActiveModel::Model def to_param "1" end + + def persisted? + true + end end end RUBY @@ -704,8 +777,7 @@ YAML @plugin.write "app/models/bukkits/post.rb", <<-RUBY module Bukkits class Post - extend ActiveModel::Naming - include ActiveModel::Conversion + include ActiveModel::Model attr_accessor :title def to_param @@ -1077,6 +1149,7 @@ YAML RUBY add_to_config("config.railties_order = [:all, :main_app, Blog::Engine]") + add_to_env_config "development", "config.assets.digest = false" boot_rails diff --git a/railties/test/railties/mounted_engine_test.rb b/railties/test/railties/mounted_engine_test.rb index 0ef2ff2e2e..fb2071c7c3 100644 --- a/railties/test/railties/mounted_engine_test.rb +++ b/railties/test/railties/mounted_engine_test.rb @@ -88,18 +88,14 @@ module ApplicationTests @plugin.write "app/models/blog/post.rb", <<-RUBY module Blog class Post - extend ActiveModel::Naming + include ActiveModel::Model def id 44 end - def to_param - id.to_s - end - - def new_record? - false + def persisted? + true end end end diff --git a/railties/test/railties/railtie_test.rb b/railties/test/railties/railtie_test.rb index 4cbd4822be..5042d628cf 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 + $before_configuration = 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 |