diff options
Diffstat (limited to 'railties')
31 files changed, 385 insertions, 546 deletions
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index 84f8ad59fb..18f2546c73 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,296 +1 @@ -* Use single quotes in generated files. - - *Cristian Mircea Messel*, *Chulki Lee* - -* Only lookup `config.log_level` for stdlib `::Logger` instances. - Assign it as is for third party loggers like `Log4r::Logger`. - - Fixes #13421. - - *Yves Senn* - -* The `Gemfile` of new applications depends on SDoc ~> 0.4.0. - - *Xavier Noria* - -* `test_help.rb` now automatically checks/maintains your test database - schema. (Use `config.active_record.maintain_test_schema = false` to - disable.) - - *Jon Leighton* - -* Configure `secrets.yml` and `database.yml` to read configuration - from the system environment by default for production. - - *José Valim* - -* `config.assets.raise_runtime_errors` is set to true by default - - 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. - - *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. - - The secrets added to this file will be accessible via `Rails.application.secrets`. - For example, with the following `secrets.yml`: - - development: - secret_key_base: 3b7cd727ee24e8444053437c36cc66c3 - some_api_key: SOMEKEY - - `Rails.application.secrets.some_api_key` will return `SOMEKEY` in the development - environment. - - *Guillermo Iguaran* - -* Add `ENV['DATABASE_URL']` support in `rails dbconsole`. Fixes #13320. - - *Huiming Teo* - -* Add `Application#message_verifier` method to return a message verifier. - - This verifier can be used to generate and verify signed messages in the application. - - message = Rails.application.message_verifier(:sensitive_data).generate('my sensible data') - Rails.application.message_verifier(:sensitive_data).verify(message) - # => 'my sensible data' - - It is recommended not to use the same verifier for different things, so you can get different - verifiers passing the name argument. - - message = Rails.application.message_verifier(:cookies).generate('my sensible cookie data') - - See the `ActiveSupport::MessageVerifier` documentation for more information. - - *Rafael Mendonça França* - -* The [Spring application - preloader](https://github.com/rails/spring) is now installed - by default for new applications. It uses the development group of - the Gemfile, so will not be installed in production. - - *Jon Leighton* - -* Uses .railsrc while creating new plugin if it is available. - Fixes #10700. - - *Prathamesh Sonpatki* - -* Remove turbolinks when generating a new application based on a template that skips it. - - Example: - - Skips turbolinks adding `add_gem_entry_filter { |gem| gem.name != "turbolinks" }` - to the template. - - *Lauro Caetano* - -* 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. - - Registering subscriber examples: - - # 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 - - # my_engine/lib/my_engine/engine.rb - module MyEngine - class Engine < ::Rails::Engine - config.before_initialize do - ActiveSupport::Notifications.subscribe('load_config_initializer.railties') do |*args| - event = ActiveSupport::Notifications::Event.new(*args) - puts "Loaded initializer #{event.payload[:initializer]} (#{event.duration}ms)" - end - end - end - end - - *Paul Nikitochkin* - -* Support for Pathnames in eager load paths. - - *Mike Pack* - -* Fixed missing line and shadow on service pages(404, 422, 500). - - *Dmitry Korotkov* - -* `BACKTRACE` environment variable to show unfiltered backtraces for - test failures. - - Example: - - $ BACKTRACE=1 ruby -Itest ... - # or with rake - $ BACKTRACE=1 bin/rake - - *Yves Senn* - -* Removal of all javascript stuff (gems and files) when generating a new - application using the `--skip-javascript` option. - - *Robin Dupret* - -* Make the application name snake cased when it contains spaces - - 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. - - *Robin Dupret* - -* Added `--model-name` option to `ScaffoldControllerGenerator`. - - *yalab* - -* Expose MiddlewareStack#unshift to environment configuration. - - *Ben Pickles* - -* `rails server` will only extend the logger to output to STDOUT - in development environment. - - *Richard Schneeman* - -* Don't require passing path to app before options in `rails new` - and `rails plugin new` - - *Piotr Sarnacki* - -* rake notes now searches *.less files - - *Josh Crowder* - -* Generate nested route for namespaced controller generated using - `rails g controller`. - Fixes #11532. - - Example: - - rails g controller admin/dashboard index - - # Before: - get "dashboard/index" - - # After: - namespace :admin do - get "dashboard/index" - end - - *Prathamesh Sonpatki* - -* Fix the event name of action_dispatch requests. - - *Rafael Mendonça França* - -* Make `config.log_level` work with custom loggers. - - *Max Shytikov* - -* Changed stylesheet load order in the stylesheet manifest generator. - Fixes #11639. - - *Pawel Janiak* - -* Added generated unit test for generator generator using new - `test:generators` rake task. - - *Josef Šimánek* - -* Removed `update:application_controller` rake task. - - *Josef Šimánek* - -* Fix `rake environment` to do not eager load modules - - *Paul Nikitochkin* - -* Fix `rake notes` to look into `*.sass` files - - *Yuri Artemev* - -* Removed deprecated `Rails.application.railties.engines`. - - *Arun Agrawal* - -* Removed deprecated threadsafe! from Rails Config. - - *Paul Nikitochkin* - -* Remove deprecated `ActiveRecord::Generators::ActiveModel#update_attributes` in - favor of `ActiveRecord::Generators::ActiveModel#update`. - - *Vipul A M* - -* Remove deprecated `config.whiny_nils` option. - - *Vipul A M* - -* Rename `commands/plugin_new.rb` to `commands/plugin.rb` and fix references - - *Richard Schneeman* - -* Fix `rails plugin --help` command. - - *Richard Schneeman* - -* Omit turbolinks configuration completely on skip_javascript generator option. - - *Nikita Fedyashev* - -* Removed deprecated rake tasks for running tests: `rake test:uncommitted` and - `rake test:recent`. - - *John Wang* - -* Clearing autoloaded constants triggers routes reloading. - Fixes #10685. - - *Xavier Noria* - -* Fixes bug with scaffold generator with `--assets=false --resource-route=false`. - Fixes #9525. - - *Arun Agrawal* - -* 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. - - *John Wang* - -* Changes repetitive th tags to use colspan attribute in `index.html.erb` template. - - *Sıtkı Bağdat* - -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/lib/rails/app_rails_loader.rb b/railties/lib/rails/app_rails_loader.rb index 1610751844..56f05b3844 100644 --- a/railties/lib/rails/app_rails_loader.rb +++ b/railties/lib/rails/app_rails_loader.rb @@ -55,7 +55,7 @@ EOS end def self.find_executable - EXECUTABLES.find { |exe| File.exist?(exe) } + EXECUTABLES.find { |exe| File.file?(exe) } end end end diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 05acd78d98..e37347b576 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -205,7 +205,8 @@ module Rails "action_dispatch.http_auth_salt" => config.action_dispatch.http_auth_salt, "action_dispatch.signed_cookie_salt" => config.action_dispatch.signed_cookie_salt, "action_dispatch.encrypted_cookie_salt" => config.action_dispatch.encrypted_cookie_salt, - "action_dispatch.encrypted_signed_cookie_salt" => config.action_dispatch.encrypted_signed_cookie_salt + "action_dispatch.encrypted_signed_cookie_salt" => config.action_dispatch.encrypted_signed_cookie_salt, + "action_dispatch.cookies_serializer" => config.action_dispatch.cookies_serializer }) end end @@ -307,7 +308,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 diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb index 33bcab1e57..a26d41c0cf 100644 --- a/railties/lib/rails/application/bootstrap.rb +++ b/railties/lib/rails/application/bootstrap.rb @@ -53,11 +53,7 @@ INFO logger end - if ::Logger === Rails.logger - Rails.logger.level = ActiveSupport::Logger.const_get(config.log_level.to_s.upcase) - else - Rails.logger.level = config.log_level - end + Rails.logger.level = ActiveSupport::Logger.const_get(config.log_level.to_s.upcase) end # Initialize cache early in the stack so railties can make use of it. diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index e902205a13..20e3de32aa 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -109,6 +109,8 @@ module Rails 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 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..9c3332927f --- /dev/null +++ b/railties/lib/rails/generators/actions/create_migration.rb @@ -0,0 +1,68 @@ +require 'thor/actions/create_file' + +module Rails + module Generators + module Actions + class CreateMigration < Thor::Actions::CreateFile + + def migration_dir + File.dirname(@destination) + end + + def migration_file_name + @base.migration_file_name + end + + def identical? + exists? && File.binread(existing_migration) == render + end + + def revoke! + say_destination = exists? ? relative_existing_migration : relative_destination + say_status :remove, :red, say_destination + return unless exists? + ::FileUtils.rm_rf(existing_migration) unless pretend? + existing_migration + end + + def relative_existing_migration + base.relative_to_original_destination_root(existing_migration) + end + + def existing_migration + @existing_migration ||= begin + @base.class.migration_exists?(migration_dir, migration_file_name) || + File.exist?(@destination) && @destination + end + end + alias :exists? :existing_migration + + protected + + def on_conflict_behavior(&block) + options = base.options.merge(config) + if identical? + say_status :identical, :blue, relative_existing_migration + elsif options[:force] + say_status :remove, :green, relative_existing_migration + say_status :create, :green + unless pretend? + ::FileUtils.rm_rf(existing_migration) + block.call + end + elsif options[:skip] + say_status :skip, :yellow + else + say_status :conflict, :red + raise Error, "Another migration is already named #{migration_file_name}: " + + "#{existing_migration}. Use --force to replace this migration file." + end + end + + def say_status(status, color, message = relative_destination) + base.shell.say_status(status, message, color) if config[:verbose] + end + end + end + end +end diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index 55709b80ae..b2ecc22294 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -14,7 +14,6 @@ module Rails DATABASES.concat(JDBC_DATABASES) attr_accessor :rails_template - attr_accessor :app_template add_shebang_option! argument :app_path, type: :string @@ -27,9 +26,6 @@ module Rails class_option :template, type: :string, aliases: '-m', desc: "Path to some #{name} template (can be a filesystem path or URL)" - class_option :app_template, type: :string, aliases: '-n', - desc: "Path to some #{name} template (can be a filesystem path or URL)" - class_option :skip_gemfile, type: :boolean, default: false, desc: "Don't create a Gemfile" @@ -115,7 +111,6 @@ module Rails javascript_gemfile_entry, jbuilder_gemfile_entry, sdoc_gemfile_entry, - platform_dependent_gemfile_entry, spring_gemfile_entry, @extra_entries].flatten.find_all(&@gem_filter) end @@ -126,10 +121,6 @@ module Rails }.curry[@gem_filter] end - def remove_gem(name) - add_gem_entry_filter { |gem| gem.name != name } - end - def builder @builder ||= begin builder_class = get_builder_class @@ -149,92 +140,21 @@ 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 remove_gem(*args, &block) - @target.send :remove_gem, *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: self) if rails_template - apply(app_template, target: @recorder) if app_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 = expand_template options[:template] - self.app_template = expand_template options[:app_template] - end - - def expand_template(name) - case name - when /^https?:\/\// - name - when String - File.expand_path(name, Dir.pwd) - else - name + self.rails_template = case options[:template] + when /^https?:\/\// + options[:template] + when String + File.expand_path(options[:template], Dir.pwd) + else + options[:template] end end @@ -337,14 +257,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) @@ -412,7 +324,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/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/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..c4f45d344b --- /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 = "The model name '%s' was recognized as a plural, using the singular '%s'. " \ + "Override with --force-plural or setup custom inflection rules for this noun before running the generator." + mattr_accessor :skip_warn + + def self.included(base) #:nodoc: + base.class_option :force_plural, type: :boolean, default: false, desc: 'Forces the use of the given model name' + end + + def initialize(args, *_options) + super + if name == name.pluralize && name.singularize != name.pluralize && !options[:force_plural] + singular = name.singularize + unless ModelHelpers.skip_warn + say PLURAL_MODEL_NAME_WARN_MESSAGE % [name, singular] + ModelHelpers.skip_warn = true + end + name.replace singular + assign_names!(name) + end + end + end + end +end diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index d2eca5b2fb..83cb1dc0d5 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -166,7 +166,6 @@ module Rails end public_task :set_default_accessors! - public_task :apply_rails_template public_task :create_root def create_root_files @@ -236,8 +235,7 @@ module Rails build(:leftovers) end - public_task :run_bundle - public_task :replay_template + public_task :apply_rails_template, :run_bundle public_task :generate_spring_binstubs protected diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile index 6d017e187d..a9b6787894 100644 --- a/railties/lib/rails/generators/rails/app/templates/Gemfile +++ b/railties/lib/rails/generators/rails/app/templates/Gemfile @@ -14,7 +14,7 @@ source 'https://rubygems.org' <% end -%> # Use ActiveModel has_secure_password -# gem 'bcrypt-ruby', '~> 3.1.2' +# gem 'bcrypt', '~> 3.1.7' # Use unicorn as the app server # gem 'unicorn' diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt index cce4743a33..de12565a73 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt @@ -35,4 +35,7 @@ Rails.application.configure do # 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..b789ed9a94 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt @@ -5,7 +5,7 @@ Rails.application.configure do config.cache_classes = true # Eager load code on boot. This eager loads most of Rails and - # your application in memory, allowing both thread web servers + # your application in memory, allowing both threaded web servers # and those relying on copy on write to perform better. # Rake tasks automatically ignore this option for performance. config.eager_load = true @@ -35,6 +35,10 @@ Rails.application.configure do # Version of your assets, change this if you want to expire all your assets. config.assets.version = '1.0' + + # Precompile additional assets. + # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. + # config.assets.precompile += %w( search.js ) <%- end -%> # Specifies the header that your server uses for sending files. @@ -59,12 +63,6 @@ Rails.application.configure do # Enable serving of images, stylesheets, and JavaScripts from an asset server. # config.action_controller.asset_host = "http://assets.example.com" - <%- unless options.skip_sprockets? -%> - # Precompile additional assets. - # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. - # config.assets.precompile += %w( search.js ) - <%- end -%> - # Ignore bad email addresses and do not raise email delivery errors. # Set this to true and configure the email server for immediate delivery to raise delivery errors. # config.action_mailer.raise_delivery_errors = false @@ -81,4 +79,9 @@ Rails.application.configure do # Use default logging formatter so that PID and timestamp are not suppressed. config.log_formatter = ::Logger::Formatter.new + <%- unless options.skip_active_record? -%> + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false + <%- end -%> end diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt index a90361725b..053f5b66d7 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt @@ -33,4 +33,7 @@ Rails.application.configure do # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr + + # Raises error for missing translations + # config.action_view.raise_on_missing_translations = true end diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/cookies_serializer.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/cookies_serializer.rb new file mode 100644 index 0000000000..7a06a89f0f --- /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
\ No newline at end of file diff --git a/railties/lib/rails/generators/rails/model/model_generator.rb b/railties/lib/rails/generators/rails/model/model_generator.rb index ea3d69d7c9..87bab129bb 100644 --- a/railties/lib/rails/generators/rails/model/model_generator.rb +++ b/railties/lib/rails/generators/rails/model/model_generator.rb @@ -1,6 +1,10 @@ +require 'rails/generators/model_helpers' + module Rails module Generators class ModelGenerator < NamedBase # :nodoc: + include Rails::Generators::ModelHelpers + argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]" hook_for :orm, required: true end diff --git a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb index dbe1e37d8e..f6f529b80a 100644 --- a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb +++ b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb @@ -185,7 +185,6 @@ task default: :test end public_task :set_default_accessors! - public_task :apply_rails_template public_task :create_root def create_root_files @@ -242,6 +241,7 @@ task default: :test build(:leftovers) end + public_task :apply_rails_template, :run_bundle def name @name ||= begin @@ -255,9 +255,6 @@ task default: :test end end - public_task :run_bundle - public_task :replay_template - protected def app_templates_dir diff --git a/railties/lib/rails/generators/rails/plugin/templates/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/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/version.rb b/railties/lib/rails/version.rb index 923cab4e2a..79313c936a 100644 --- a/railties/lib/rails/version.rb +++ b/railties/lib/rails/version.rb @@ -1,9 +1,9 @@ module Rails module VERSION MAJOR = 4 - MINOR = 1 + MINOR = 2 TINY = 0 - PRE = "beta1" + PRE = "alpha" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end diff --git a/railties/test/app_rails_loader_test.rb b/railties/test/app_rails_loader_test.rb index 92cb3233d8..1d3b80253a 100644 --- a/railties/test/app_rails_loader_test.rb +++ b/railties/test/app_rails_loader_test.rb @@ -22,8 +22,14 @@ class AppRailsLoaderTest < ActiveSupport::TestCase exe = "#{script_dir}/rails" test "is not in a Rails application if #{exe} is not found in the current or parent directories" do - File.stubs(:exist?).with('bin/rails').returns(false) - File.stubs(:exist?).with('script/rails').returns(false) + File.stubs(:file?).with('bin/rails').returns(false) + File.stubs(:file?).with('script/rails').returns(false) + + assert !Rails::AppRailsLoader.exec_app_rails + end + + test "is not in a Rails application if #{exe} exists but is a folder" do + FileUtils.mkdir_p(exe) assert !Rails::AppRailsLoader.exec_app_rails end diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index 02d8b2c91d..b39cd3747b 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -336,6 +336,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 @@ -754,7 +762,7 @@ module ApplicationTests end end - test "lookup config.log_level with custom logger (stdlib Logger)" do + test "config.log_level with custom logger" do make_basic_app do |app| app.config.logger = Logger.new(STDOUT) app.config.log_level = :info @@ -762,24 +770,28 @@ module ApplicationTests assert_equal Logger::INFO, Rails.logger.level end - test "assign log_level as is with custom logger (third party logger)" do - logger_class = Class.new do - attr_accessor :level - end - logger_instance = logger_class.new - make_basic_app do |app| - app.config.logger = logger_instance - app.config.log_level = :info - end - assert_equal logger_instance, Rails.logger - assert_equal :info, Rails.logger.level - end - test "respond_to? accepts include_private" do make_basic_app 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 end end diff --git a/railties/test/application/rake/migrations_test.rb b/railties/test/application/rake/migrations_test.rb index 33c753868c..b7fd5d02c5 100644 --- a/railties/test/application/rake/migrations_test.rb +++ b/railties/test/application/rake/migrations_test.rb @@ -153,6 +153,37 @@ module ApplicationTests assert_match(/up\s+\d{3,}\s+Add email to users/, output) end end + + test 'schema generation when dump_schema_after_migration is set' do + add_to_config('config.active_record.dump_schema_after_migration = false') + + Dir.chdir(app_path) do + `rails generate model book title:string; + bundle exec rake db:migrate` + + assert !File.exist?("db/schema.rb") + end + + add_to_config('config.active_record.dump_schema_after_migration = true') + + Dir.chdir(app_path) do + `rails generate model author name:string; + bundle exec rake db:migrate` + + structure_dump = File.read("db/schema.rb") + assert_match(/create_table "authors"/, structure_dump) + end + end + + test 'default schema generation after migration' do + Dir.chdir(app_path) do + `rails generate model book title:string; + bundle exec rake db:migrate` + + structure_dump = File.read("db/schema.rb") + assert_match(/create_table "books"/, structure_dump) + end + end end end end diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index ddecee2ca1..5ebdadacbf 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -163,73 +163,6 @@ class AppGeneratorTest < Rails::Generators::TestCase end end - def test_arbitrary_code - output = Tempfile.open('my_template') do |template| - template.puts 'puts "You are using Rails version #{Rails::VERSION::STRING}."' - template.close - run_generator([destination_root, "-m", template.path]) - end - assert_match 'You are using', output - 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, "-n", 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.close - - run_generator([destination_root, "-n", template.path]) - assert_file "Gemfile" do |contents| - assert_no_match 'jbuilder', contents - end - end - end - - def test_remove_gem - Tempfile.open 'my_template' do |template| - template.puts 'remove_gem "jbuilder"' - template.close - - run_generator([destination_root, "-n", 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, "-n", 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 - end - end - def test_config_another_database run_generator([destination_root, "-d", "mysql"]) assert_file "config/database.yml", /mysql/ @@ -332,13 +265,6 @@ class AppGeneratorTest < Rails::Generators::TestCase end end - def test_inclusion_of_plateform_dependent_gems - run_generator([destination_root]) - if RUBY_ENGINE == 'rbx' - assert_gem 'rubysl' - end - end - def test_jquery_is_the_default_javascript_library run_generator assert_file "app/assets/javascripts/application.js" do |contents| diff --git a/railties/test/generators/create_migration_test.rb b/railties/test/generators/create_migration_test.rb new file mode 100644 index 0000000000..e16a77479a --- /dev/null +++ b/railties/test/generators/create_migration_test.rb @@ -0,0 +1,134 @@ +require 'generators/generators_test_helper' +require 'rails/generators/rails/migration/migration_generator' + +class CreateMigrationTest < Rails::Generators::TestCase + include GeneratorsTestHelper + + class Migrator < Rails::Generators::MigrationGenerator + include Rails::Generators::Migration + + def self.next_migration_number(dirname) + current_migration_number(dirname) + 1 + end + end + + tests Migrator + + def default_destination_path + "db/migrate/create_articles.rb" + end + + def create_migration(destination_path = default_destination_path, config = {}, generator_options = {}, &block) + migration_name = File.basename(destination_path, '.rb') + generator([migration_name], generator_options) + generator.set_migration_assigns!(destination_path) + + dir, base = File.split(destination_path) + timestamped_destination_path = File.join(dir, ["%migration_number%", base].join('_')) + + @migration = Rails::Generators::Actions::CreateMigration.new(generator, timestamped_destination_path, block || "contents", config) + end + + def migration_exists!(*args) + @existing_migration = create_migration(*args) + invoke! + @generator = nil + end + + def invoke! + capture(:stdout) { @migration.invoke! } + end + + def revoke! + capture(:stdout) { @migration.revoke! } + end + + def test_invoke + create_migration + + assert_match(/create db\/migrate\/1_create_articles.rb\n/, invoke!) + assert_file @migration.destination + end + + def test_invoke_pretended + create_migration(default_destination_path, {}, { pretend: true }) + + assert_no_file @migration.destination + end + + def test_invoke_when_exists + migration_exists! + create_migration + + assert_equal @existing_migration.destination, @migration.existing_migration + end + + def test_invoke_when_exists_identical + migration_exists! + create_migration + + assert_match(/identical db\/migrate\/1_create_articles.rb\n/, invoke!) + assert @migration.identical? + end + + def test_invoke_when_exists_not_identical + migration_exists! + create_migration { "different content" } + + assert_raise(Rails::Generators::Error) { invoke! } + end + + def test_invoke_forced_when_exists_not_identical + dest = "db/migrate/migration.rb" + migration_exists!(dest) + create_migration(dest, force: true) { "different content" } + + stdout = invoke! + assert_match(/remove db\/migrate\/1_migration.rb\n/, stdout) + assert_match(/create db\/migrate\/2_migration.rb\n/, stdout) + assert_file @migration.destination + assert_no_file @existing_migration.destination + end + + def test_invoke_forced_pretended_when_exists_not_identical + migration_exists! + create_migration(default_destination_path, { force: true }, { pretend: true }) do + "different content" + end + + stdout = invoke! + assert_match(/remove db\/migrate\/1_create_articles.rb\n/, stdout) + assert_match(/create db\/migrate\/2_create_articles.rb\n/, stdout) + assert_no_file @migration.destination + end + + def test_invoke_skipped_when_exists_not_identical + migration_exists! + create_migration(default_destination_path, {}, { skip: true }) { "different content" } + + assert_match(/skip db\/migrate\/2_create_articles.rb\n/, invoke!) + assert_no_file @migration.destination + end + + def test_revoke + migration_exists! + create_migration + + assert_match(/remove db\/migrate\/1_create_articles.rb\n/, revoke!) + assert_no_file @existing_migration.destination + end + + def test_revoke_pretended + migration_exists! + create_migration(default_destination_path, {}, { pretend: true }) + + assert_match(/remove db\/migrate\/1_create_articles.rb\n/, revoke!) + assert_file @existing_migration.destination + end + + def test_revoke_when_no_exists + create_migration + + assert_match(/remove db\/migrate\/1_create_articles.rb\n/, revoke!) + end +end diff --git a/railties/test/generators/generator_test.rb b/railties/test/generators/generator_test.rb index 94d2c1bf50..7871399dd7 100644 --- a/railties/test/generators/generator_test.rb +++ b/railties/test/generators/generator_test.rb @@ -1,7 +1,6 @@ require 'active_support/test_case' require 'active_support/testing/autorun' require 'rails/generators/app_base' -require 'rails/generators/rails/app/app_generator' module Rails module Generators diff --git a/railties/test/generators/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/model_generator_test.rb b/railties/test/generators/model_generator_test.rb index 01ab77ee20..bdf51b457c 100644 --- a/railties/test/generators/model_generator_test.rb +++ b/railties/test/generators/model_generator_test.rb @@ -34,6 +34,13 @@ class ModelGeneratorTest < Rails::Generators::TestCase assert_no_migration "db/migrate/create_accounts.rb" end + def test_plural_names_are_singularized + content = run_generator ["accounts".freeze] + assert_file "app/models/account.rb", /class Account < ActiveRecord::Base/ + assert_file "test/models/account_test.rb", /class AccountTest/ + assert_match(/The model name 'accounts' was recognized as a plural, using the singular 'account'\. Override with --force-plural or setup custom inflection rules for this noun before running the generator\./, content) + end + def test_model_with_underscored_parent_option run_generator ["account", "--parent", "admin/account"] assert_file "app/models/account.rb", /class Account < Admin::Account/ diff --git a/railties/test/generators/resource_generator_test.rb b/railties/test/generators/resource_generator_test.rb index 3d4e694361..55c8d92ee8 100644 --- a/railties/test/generators/resource_generator_test.rb +++ b/railties/test/generators/resource_generator_test.rb @@ -63,7 +63,7 @@ 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(/The model name 'accounts' was recognized as a plural, using the singular 'account'\. 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 |