diff options
37 files changed, 722 insertions, 105 deletions
diff --git a/.travis.yml b/.travis.yml index f1031a3750..5c2699371b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,6 +25,7 @@ env: - "GEM=guides" rvm: - 2.2.4 + - 2.3.0 - ruby-head matrix: allow_failures: diff --git a/actioncable/lib/action_cable/connection/base.rb b/actioncable/lib/action_cable/connection/base.rb index f7b18a85ae..977856d656 100644 --- a/actioncable/lib/action_cable/connection/base.rb +++ b/actioncable/lib/action_cable/connection/base.rb @@ -48,11 +48,9 @@ module ActionCable include InternalChannel include Authorization - attr_reader :server, :env, :subscriptions + attr_reader :server, :env, :subscriptions, :logger delegate :worker_pool, :pubsub, to: :server - attr_reader :logger - def initialize(server, env) @server, @env = server, env @@ -123,7 +121,6 @@ module ActionCable transmit ActiveSupport::JSON.encode(identifier: ActionCable::INTERNAL[:identifiers][:ping], message: Time.now.to_i) end - protected # The request that initiated the WebSocket connection is available here. This gives access to the environment, cookies, etc. def request @@ -138,8 +135,6 @@ module ActionCable request.cookie_jar end - - protected attr_reader :websocket attr_reader :message_buffer @@ -170,7 +165,6 @@ module ActionCable disconnect if respond_to?(:disconnect) end - def allow_request_origin? return true if server.config.disable_request_forgery_protection @@ -193,7 +187,6 @@ module ActionCable [ 404, { 'Content-Type' => 'text/plain' }, [ 'Page not found' ] ] end - # Tags are declared in the server but computed in the connection. This allows us per-connection tailored tags. def new_tagged_logger TaggedLoggerProxy.new server.logger, diff --git a/actioncable/lib/action_cable/connection/subscriptions.rb b/actioncable/lib/action_cable/connection/subscriptions.rb index 65d6634bb0..d7f95e6a62 100644 --- a/actioncable/lib/action_cable/connection/subscriptions.rb +++ b/actioncable/lib/action_cable/connection/subscriptions.rb @@ -49,7 +49,6 @@ module ActionCable find(data).perform_action ActiveSupport::JSON.decode(data['data']) end - def identifiers subscriptions.keys end diff --git a/actionpack/lib/action_dispatch/middleware/ssl.rb b/actionpack/lib/action_dispatch/middleware/ssl.rb index 47f475559a..8f8f1bab8b 100644 --- a/actionpack/lib/action_dispatch/middleware/ssl.rb +++ b/actionpack/lib/action_dispatch/middleware/ssl.rb @@ -1,19 +1,21 @@ module ActionDispatch - # This middleware is added to the stack when `config.force_ssl = true`. - # It does three jobs to enforce secure HTTP requests: + # This middleware is added to the stack when `config.force_ssl = true`, and is passed + # the options set in `config.ssl_options`. It does three jobs to enforce secure HTTP + # requests: # - # 1. TLS redirect. http:// requests are permanently redirected to https:// - # with the same URL host, path, etc. Pass `:host` and/or `:port` to - # modify the destination URL. This is always enabled. + # 1. TLS redirect: Permanently redirects http:// requests to https:// + # with the same URL host, path, etc. This is always enabled. Set + # `config.ssl_options` to modify the destination URL + # (e.g. `redirect: { host: "secure.widgets.com", port: 8080 }`) # - # 2. Secure cookies. Sets the `secure` flag on cookies to tell browsers they + # 2. Secure cookies: Sets the `secure` flag on cookies to tell browsers they # mustn't be sent along with http:// requests. This is always enabled. # - # 3. HTTP Strict Transport Security (HSTS). Tells the browser to remember + # 3. HTTP Strict Transport Security (HSTS): Tells the browser to remember # this site as TLS-only and automatically redirect non-TLS requests. # Enabled by default. Pass `hsts: false` to disable. # - # Configure HSTS with `hsts: { … }`: + # Set `config.ssl_options` with `hsts: { … }` to configure HSTS: # * `expires`: How long, in seconds, these settings will stick. Defaults to # `180.days` (recommended). The minimum required to qualify for browser # preload lists is `18.weeks`. @@ -26,10 +28,10 @@ module ActionDispatch # gap, browser vendors include a baked-in list of HSTS-enabled sites. # Go to https://hstspreload.appspot.com to submit your site for inclusion. # - # Disabling HSTS: To turn off HSTS, omitting the header is not enough. - # Browsers will remember the original HSTS directive until it expires. - # Instead, use the header to tell browsers to expire HSTS immediately. - # Setting `hsts: false` is a shortcut for `hsts: { expires: 0 }`. + # To turn off HSTS, omitting the header is not enough. Browsers will remember the + # original HSTS directive until it expires. Instead, use the header to tell browsers to + # expire HSTS immediately. Setting `hsts: false` is a shortcut for + # `hsts: { expires: 0 }`. class SSL # Default to 180 days, the low end for https://www.ssllabs.com/ssltest/ # and greater than the 18-week requirement for browser preload lists. diff --git a/actionpack/lib/action_dispatch/middleware/stack.rb b/actionpack/lib/action_dispatch/middleware/stack.rb index 44fc1ee736..0b4bee5462 100644 --- a/actionpack/lib/action_dispatch/middleware/stack.rb +++ b/actionpack/lib/action_dispatch/middleware/stack.rb @@ -14,6 +14,15 @@ module ActionDispatch def name; klass.name; end + def ==(middleware) + case middleware + when Middleware + klass == middleware.klass + when Class + klass == middleware + end + end + def inspect if klass.is_a?(Class) klass.to_s diff --git a/actionpack/test/dispatch/middleware_stack_test.rb b/actionpack/test/dispatch/middleware_stack_test.rb index 33aa616474..a8c8e0784f 100644 --- a/actionpack/test/dispatch/middleware_stack_test.rb +++ b/actionpack/test/dispatch/middleware_stack_test.rb @@ -131,4 +131,20 @@ class MiddlewareStackTest < ActiveSupport::TestCase assert_equal BazMiddleware, @stack.last.klass end end + + test "can check if Middleware are equal - Class" do + assert_equal @stack.last, BarMiddleware + end + + test "includes a class" do + assert_equal true, @stack.include?(BarMiddleware) + end + + test "can check if Middleware are equal - Middleware" do + assert_equal @stack.last, @stack.last + end + + test "includes a middleware" do + assert_equal true, @stack.include?(ActionDispatch::MiddlewareStack::Middleware.new(BarMiddleware, nil, nil)) + end end diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md index a43d9039db..85d91825ac 100644 --- a/actionview/CHANGELOG.md +++ b/actionview/CHANGELOG.md @@ -1,3 +1,8 @@ +* Fix regression in `submit_tag` when a symbol is used as label argument. + + *Yuuji Yaginuma* + + ## Rails 5.0.0.beta1 (December 18, 2015) ## * `I18n.translate` helper will wrap the missing translation keys diff --git a/actionview/lib/action_view/helpers/form_tag_helper.rb b/actionview/lib/action_view/helpers/form_tag_helper.rb index 0191064326..79a1a242bf 100644 --- a/actionview/lib/action_view/helpers/form_tag_helper.rb +++ b/actionview/lib/action_view/helpers/form_tag_helper.rb @@ -447,7 +447,7 @@ module ActionView unless tag_options["data-disable-with"] == false || (tag_options["data"] && tag_options["data"][:disable_with] == false) disable_with_text = tag_options["data-disable-with"] disable_with_text ||= tag_options["data"][:disable_with] if tag_options["data"] - disable_with_text ||= value.clone + disable_with_text ||= value.to_s.clone tag_options.deep_merge!("data" => { "disable_with" => disable_with_text }) else tag_options["data"].delete(:disable_with) if tag_options["data"] diff --git a/actionview/lib/action_view/helpers/number_helper.rb b/actionview/lib/action_view/helpers/number_helper.rb index 0c5cecae01..161aa031c6 100644 --- a/actionview/lib/action_view/helpers/number_helper.rb +++ b/actionview/lib/action_view/helpers/number_helper.rb @@ -63,6 +63,14 @@ module ActionView # Formats a +number+ into a currency string (e.g., $13.65). You # can customize the format in the +options+ hash. # + # The currency unit and number formatting of the current locale will be used + # unless otherwise specified in the provided options. No currency conversion + # is performed. If the user is given a way to change their locale, they will + # also be able to change the relative value of the currency displayed with + # this helper. If your application will ever support multiple locales, you + # may want to specify a constant <tt>:locale</tt> option or consider + # using a library capable of currency conversion. + # # ==== Options # # * <tt>:locale</tt> - Sets the locale to be used for formatting diff --git a/actionview/lib/action_view/template/resolver.rb b/actionview/lib/action_view/template/resolver.rb index 7859c58b43..6ddd2b66b3 100644 --- a/actionview/lib/action_view/template/resolver.rb +++ b/actionview/lib/action_view/template/resolver.rb @@ -3,7 +3,7 @@ require "active_support/core_ext/class" require "active_support/core_ext/module/attribute_accessors" require "action_view/template" require "thread" -require "concurrent" +require "concurrent/map" module ActionView # = Action View Resolver diff --git a/actionview/test/template/form_tag_helper_test.rb b/actionview/test/template/form_tag_helper_test.rb index de1eb89dc5..359ecbc637 100644 --- a/actionview/test/template/form_tag_helper_test.rb +++ b/actionview/test/template/form_tag_helper_test.rb @@ -510,6 +510,13 @@ class FormTagHelperTest < ActionView::TestCase ) end + def test_submit_tag_with_symbol_value + assert_dom_equal( + %(<input data-disable-with="Save" name='commit' type="submit" value="Save" />), + submit_tag(:Save) + ) + end + def test_button_tag assert_dom_equal( diff --git a/activejob/CHANGELOG.md b/activejob/CHANGELOG.md index c4c49af53a..8687af5eba 100644 --- a/activejob/CHANGELOG.md +++ b/activejob/CHANGELOG.md @@ -28,7 +28,7 @@ *Jean Boussier* -* Include I18n.locale into job serialization/deserialization and use it around +* Include `I18n.locale` into job serialization/deserialization and use it around `perform`. Fixes #20799. diff --git a/activemodel/lib/active_model/validations/numericality.rb b/activemodel/lib/active_model/validations/numericality.rb index 9c1e8b4ba7..ad7012df48 100644 --- a/activemodel/lib/active_model/validations/numericality.rb +++ b/activemodel/lib/active_model/validations/numericality.rb @@ -39,6 +39,10 @@ module ActiveModel return end + unless raw_value.is_a?(Numeric) + value = parse_raw_value_as_a_number(raw_value) + end + options.slice(*CHECKS.keys).each do |option, option_value| case option when :odd, :even @@ -63,12 +67,15 @@ module ActiveModel protected def is_number?(raw_value) - parsed_value = Kernel.Float(raw_value) if raw_value !~ /\A0[xX]/ - !parsed_value.nil? + !parse_raw_value_as_a_number(raw_value).nil? rescue ArgumentError, TypeError false end + def parse_raw_value_as_a_number(raw_value) + Kernel.Float(raw_value) if raw_value !~ /\A0[xX]/ + end + def is_integer?(raw_value) /\A[+-]?\d+\z/ === raw_value.to_s end diff --git a/activemodel/test/cases/validations/numericality_validation_test.rb b/activemodel/test/cases/validations/numericality_validation_test.rb index 04ec74bad3..74a048537d 100644 --- a/activemodel/test/cases/validations/numericality_validation_test.rb +++ b/activemodel/test/cases/validations/numericality_validation_test.rb @@ -79,6 +79,13 @@ class NumericalityValidationTest < ActiveModel::TestCase valid!([97.18, 98, BigDecimal.new('98')]) # Notice the 97.18 as a float is greater than 97.18 as a BigDecimal due to floating point precision end + def test_validates_numericality_with_greater_than_using_string_value + Topic.validates_numericality_of :approved, greater_than: 10 + + invalid!(['-10', '9', '9.9', '10'], 'must be greater than 10') + valid!(['10.1', '11']) + end + def test_validates_numericality_with_greater_than_or_equal Topic.validates_numericality_of :approved, greater_than_or_equal_to: 10 @@ -93,6 +100,13 @@ class NumericalityValidationTest < ActiveModel::TestCase valid!([97.18, 98, BigDecimal.new('97.19')]) end + def test_validates_numericality_with_greater_than_or_equal_using_string_value + Topic.validates_numericality_of :approved, greater_than_or_equal_to: 10 + + invalid!(['-10', '9', '9.9'], 'must be greater than or equal to 10') + valid!(['10', '10.1', '11']) + end + def test_validates_numericality_with_equal_to Topic.validates_numericality_of :approved, equal_to: 10 @@ -107,6 +121,13 @@ class NumericalityValidationTest < ActiveModel::TestCase valid!([BigDecimal.new('97.18')]) end + def test_validates_numericality_with_equal_to_using_string_value + Topic.validates_numericality_of :approved, equal_to: 10 + + invalid!(['-10', '9', '9.9', '10.1', '11'], 'must be equal to 10') + valid!(['10']) + end + def test_validates_numericality_with_less_than Topic.validates_numericality_of :approved, less_than: 10 @@ -121,6 +142,13 @@ class NumericalityValidationTest < ActiveModel::TestCase valid!([-97.0, 97.0, -97, 97, BigDecimal.new('-97'), BigDecimal.new('97')]) end + def test_validates_numericality_with_less_than_using_string_value + Topic.validates_numericality_of :approved, less_than: 10 + + invalid!(['10', '10.1', '11'], 'must be less than 10') + valid!(['-10', '9', '9.9']) + end + def test_validates_numericality_with_less_than_or_equal_to Topic.validates_numericality_of :approved, less_than_or_equal_to: 10 @@ -135,6 +163,13 @@ class NumericalityValidationTest < ActiveModel::TestCase valid!([-97.18, BigDecimal.new('-97.18'), BigDecimal.new('97.18')]) end + def test_validates_numericality_with_less_than_or_equal_using_string_value + Topic.validates_numericality_of :approved, less_than_or_equal_to: 10 + + invalid!(['10.1', '11'], 'must be less than or equal to 10') + valid!(['-10', '9', '9.9', '10']) + end + def test_validates_numericality_with_odd Topic.validates_numericality_of :approved, odd: true @@ -163,6 +198,13 @@ class NumericalityValidationTest < ActiveModel::TestCase valid!([-1, 42]) end + def test_validates_numericality_with_other_than_using_string_value + Topic.validates_numericality_of :approved, other_than: 0 + + invalid!(['0', '0.0']) + valid!(['-1', '1.1', '42']) + end + def test_validates_numericality_with_proc Topic.send(:define_method, :min_approved, lambda { 5 }) Topic.validates_numericality_of :approved, greater_than_or_equal_to: Proc.new(&:min_approved) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index fb6c5e7e81..2551841aaf 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -50,7 +50,7 @@ change, passing a string containing a comma to `limit` has been deprecated, and passing an Arel node to `limit` is no longer supported. - Fixes #22250 + Fixes #22250. *Sean Griffin* @@ -312,7 +312,7 @@ * Don't cache arguments in `#find_by` if they are an `ActiveRecord::Relation`. - Fixes #20817 + Fixes #20817. *Hiroaki Izu* @@ -441,9 +441,9 @@ * Ensure `select` quotes aliased attributes, even when using `from`. - Fixes #21488 + Fixes #21488. - *Sean Griffin & @johanlunds* + *Sean Griffin*, *@johanlunds* * MySQL: support `unsigned` numeric data types. @@ -769,7 +769,7 @@ * Include the `Enumerable` module in `ActiveRecord::Relation` - *Sean Griffin & bogdan* + *Sean Griffin*, *bogdan* * Use `Enumerable#sum` in `ActiveRecord::Relation` if a block is given. @@ -805,7 +805,7 @@ Fixes #20515. - *Sean Griffin & jmondo* + *Sean Griffin*, *jmondo* * Deprecate the PostgreSQL `:point` type in favor of a new one which will return `Point` objects instead of an `Array` @@ -1195,13 +1195,16 @@ *Sean Griffin* * `scoping` no longer pollutes the current scope of sibling classes when using - STI. e.x. + STI. + + Fixes #18806. + + Example: StiOne.none.scoping do StiTwo.all end - Fixes #18806. *Sean Griffin* @@ -1242,7 +1245,7 @@ * Use `SCHEMA` instead of `DB_STRUCTURE` for specifying a structure file. - This makes the db:structure tasks consistent with test:load_structure. + This makes the `db:structure` tasks consistent with `test:load_structure`. *Dieter Komendera* @@ -1278,7 +1281,7 @@ Fixes #17621. - *Eileen M. Uchitelle, Aaron Patterson* + *Eileen M. Uchitelle*, *Aaron Patterson* * Fix n+1 query problem when eager loading nil associations (fixes #18312) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb index 7e0b449c99..d3bc378bea 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -344,18 +344,12 @@ module ActiveRecord # The default strategy for an UPDATE with joins is to use a subquery. This doesn't work # on MySQL (even when aliasing the tables), but MySQL allows using JOIN directly in # an UPDATE statement, so in the MySQL adapters we redefine this to do that. - def join_to_update(update, select) #:nodoc: - key = update.key + def join_to_update(update, select, key) # :nodoc: subselect = subquery_for(key, select) update.where key.in(subselect) end - - def join_to_delete(delete, select, key) #:nodoc: - subselect = subquery_for(key, select) - - delete.where key.in(subselect) - end + alias join_to_delete join_to_update protected diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index af10703e0e..37e4eb24a8 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -31,8 +31,6 @@ module ActiveRecord def extract_default if blob_or_text_column? @default = null || strict ? nil : '' - elsif missing_default_forged_as_empty_string?(default) - @default = nil end end @@ -59,17 +57,6 @@ module ActiveRecord private - # MySQL misreports NOT NULL column default when none is given. - # We can't detect this for columns which may have a legitimate '' - # default (string) but we can for others (integer, datetime, boolean, - # and the rest). - # - # Test whether the column has default '', is not null, and is not - # a type allowing default ''. - def missing_default_forged_as_empty_string?(default) - type != :string && !null && default == '' - end - def assert_valid_default(default) if blob_or_text_column? && default.present? raise ArgumentError, "#{type} columns cannot have a default value: #{default.inspect}" @@ -431,7 +418,7 @@ module ActiveRecord # In the simple case, MySQL allows us to place JOINs directly into the UPDATE # query. However, this does not allow for LIMIT, OFFSET and ORDER. To support # these, we must use a subquery. - def join_to_update(update, select) #:nodoc: + def join_to_update(update, select, key) # :nodoc: if select.limit || select.offset || select.orders.any? super else diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 2cf19c76c5..316b0d6308 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -371,11 +371,11 @@ module ActiveRecord stmt.set Arel.sql(@klass.send(:sanitize_sql_for_assignment, updates)) stmt.table(table) - stmt.key = table[primary_key] if joins_values.any? - @klass.connection.join_to_update(stmt, arel) + @klass.connection.join_to_update(stmt, arel, table[primary_key]) else + stmt.key = table[primary_key] stmt.take(arel.limit) stmt.order(*arel.orders) stmt.wheres = arel.constraints diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index f343a15317..ba3e16bdb2 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1252,6 +1252,7 @@ class BasicsTest < ActiveRecord::TestCase original_logger = ActiveRecord::Base.logger log = StringIO.new ActiveRecord::Base.logger = ActiveSupport::Logger.new(log) + ActiveRecord::Base.logger.level = Logger::DEBUG ActiveRecord::Base.benchmark("Logging", :level => :debug, :silence => false) { ActiveRecord::Base.logger.debug "Quiet" } assert_match(/Quiet/, log.string) ensure diff --git a/activerecord/test/cases/column_definition_test.rb b/activerecord/test/cases/column_definition_test.rb index da0d7f5195..783a374116 100644 --- a/activerecord/test/cases/column_definition_test.rb +++ b/activerecord/test/cases/column_definition_test.rb @@ -49,6 +49,16 @@ module ActiveRecord assert_equal "a", varbinary_column.default end + def test_should_be_empty_string_default_for_mysql_binary_data_types + type = SqlTypeMetadata.new(type: :binary, sql_type: "binary(1)") + binary_column = AbstractMysqlAdapter::Column.new("title", "", type, false) + assert_equal "", binary_column.default + + type = SqlTypeMetadata.new(type: :binary, sql_type: "varbinary") + varbinary_column = AbstractMysqlAdapter::Column.new("title", "", type, false) + assert_equal "", varbinary_column.default + end + def test_should_not_set_default_for_blob_and_text_data_types assert_raise ArgumentError do AbstractMysqlAdapter::Column.new("title", "a", SqlTypeMetadata.new(sql_type: "blob")) diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index 1f459a843d..1ba52444c1 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -10,14 +10,14 @@ module Current thread_mattr_accessor :account thread_mattr_accessor :user - + def self.reset() self.account = self.user = nil end end class ApplicationController < ActiveController::Base before_action :set_current after_action { Current.reset } - + private def set_current Current.account = Account.find(params[:account_id]) @@ -34,7 +34,7 @@ class Message < ApplicationRecord has_many :events after_create :track_created - + private def track_created events.create! origin: self, action: :create @@ -58,9 +58,9 @@ *Yuichiro Kaneko* -* `ActiveSupport::Cache::Store#namespaced_key`, - `ActiveSupport::Cache::MemCachedStore#escape_key`, and - `ActiveSupport::Cache::FileStore#key_file_path` +* `ActiveSupport::Cache::Store#namespaced_key`, + `ActiveSupport::Cache::MemCachedStore#escape_key`, and + `ActiveSupport::Cache::FileStore#key_file_path` are deprecated and replaced with `normalize_key` that now calls `super`. `ActiveSupport::Cache::LocaleCache#set_cache_value` is deprecated and replaced with `write_cache_value`. @@ -119,7 +119,7 @@ *Konstantinos Rousis* -* Handle invalid UTF-8 strings when HTML escaping +* Handle invalid UTF-8 strings when HTML escaping. Use `ActiveSupport::Multibyte::Unicode.tidy_bytes` to handle invalid UTF-8 strings in `ERB::Util.unwrapped_html_escape` and `ERB::Util.html_escape_once`. @@ -160,7 +160,7 @@ * Short-circuit `blank?` on date and time values since they are never blank. - Fixes #21657 + Fixes #21657. *Andrew White* @@ -198,7 +198,7 @@ * ActiveSupport::HashWithIndifferentAccess `select` and `reject` will now return enumerator if called without block. - Fixes #20095 + Fixes #20095. *Bernard Potocki* @@ -212,11 +212,11 @@ *Simon Eskildsen* -* Fix setting `default_proc` on `HashWithIndifferentAccess#dup` +* Fix setting `default_proc` on `HashWithIndifferentAccess#dup`. *Simon Eskildsen* -* Fix a range of values for parameters of the Time#change +* Fix a range of values for parameters of the Time#change. *Nikolay Kondratyev* @@ -228,7 +228,7 @@ *Kevin Deisz* * Add a bang version to `ActiveSupport::OrderedOptions` get methods which will raise - an `KeyError` if the value is `.blank?` + an `KeyError` if the value is `.blank?`. Before: diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb index 595b0339cc..f741c0bfb8 100644 --- a/activesupport/lib/active_support/inflector/methods.rb +++ b/activesupport/lib/active_support/inflector/methods.rb @@ -173,7 +173,7 @@ module ActiveSupport # # Singular names are not handled correctly: # - # classify('calculus') # => "Calculu" + # classify('calculus') # => "Calculus" def classify(table_name) # strip out any leading schema name camelize(singularize(table_name.to_s.sub(/.*\./, ''.freeze))) diff --git a/activesupport/lib/active_support/logger.rb b/activesupport/lib/active_support/logger.rb index 82117a64d2..520268b244 100644 --- a/activesupport/lib/active_support/logger.rb +++ b/activesupport/lib/active_support/logger.rb @@ -46,6 +46,20 @@ module ActiveSupport super @formatter = SimpleFormatter.new @broadcast_messages = true + after_initialize if respond_to? :after_initialize + end + + def add(severity, message = nil, progname = nil, &block) + return true if @logdev.nil? || (severity || UNKNOWN) < level + super + end + + Logger::Severity.constants.each do |severity| + class_eval(<<-EOT, __FILE__, __LINE__ + 1) + def #{severity.downcase}? # def debug? + Logger::#{severity} >= level # DEBUG >= level + end # end + EOT end # Simple formatter which only displays the message. diff --git a/activesupport/lib/active_support/logger_silence.rb b/activesupport/lib/active_support/logger_silence.rb index 7d92256f24..690e5596f7 100644 --- a/activesupport/lib/active_support/logger_silence.rb +++ b/activesupport/lib/active_support/logger_silence.rb @@ -1,22 +1,42 @@ require 'active_support/concern' require 'active_support/core_ext/module/attribute_accessors' +require 'concurrent' module LoggerSilence extend ActiveSupport::Concern included do cattr_accessor :silencer + attr_reader :local_levels self.silencer = true end + def after_initialize + @local_levels = Concurrent::Map.new(:initial_capacity => 2) + end + + def local_log_id + Thread.current.__id__ + end + + def level + local_levels[local_log_id] || super + end + # Silences the logger for the duration of the block. def silence(temporary_level = Logger::ERROR) if silencer begin - old_logger_level, self.level = level, temporary_level + old_local_level = local_levels[local_log_id] + local_levels[local_log_id] = temporary_level + yield self ensure - self.level = old_logger_level + if old_local_level + local_levels[local_log_id] = old_local_level + else + local_levels.delete(local_log_id) + end end else yield self diff --git a/activesupport/lib/active_support/number_helper.rb b/activesupport/lib/active_support/number_helper.rb index 191ac0dac5..64d9e71f37 100644 --- a/activesupport/lib/active_support/number_helper.rb +++ b/activesupport/lib/active_support/number_helper.rb @@ -47,6 +47,14 @@ module ActiveSupport # Formats a +number+ into a currency string (e.g., $13.65). You # can customize the format in the +options+ hash. # + # The currency unit and number formatting of the current locale will be used + # unless otherwise specified in the provided options. No currency conversion + # is performed. If the user is given a way to change their locale, they will + # also be able to change the relative value of the currency displayed with + # this helper. If your application will ever support multiple locales, you + # may want to specify a constant <tt>:locale</tt> option or consider + # using a library capable of currency conversion. + # # ==== Options # # * <tt>:locale</tt> - Sets the locale to be used for formatting diff --git a/activesupport/test/logger_test.rb b/activesupport/test/logger_test.rb index d2801849ca..a57dc7a241 100644 --- a/activesupport/test/logger_test.rb +++ b/activesupport/test/logger_test.rb @@ -3,6 +3,7 @@ require 'multibyte_test_helpers' require 'stringio' require 'fileutils' require 'tempfile' +require 'concurrent/atomics' class LoggerTest < ActiveSupport::TestCase include MultibyteTestHelpers @@ -113,6 +114,7 @@ class LoggerTest < ActiveSupport::TestCase end def test_buffer_multibyte + @logger.level = Logger::INFO @logger.info(UNICODE_STRING) @logger.info(BYTE_STRING) assert @output.string.include?(UNICODE_STRING) @@ -120,14 +122,93 @@ class LoggerTest < ActiveSupport::TestCase byte_string.force_encoding("ASCII-8BIT") assert byte_string.include?(BYTE_STRING) end - + def test_silencing_everything_but_errors @logger.silence do @logger.debug "NOT THERE" @logger.error "THIS IS HERE" end - + assert !@output.string.include?("NOT THERE") assert @output.string.include?("THIS IS HERE") end + + def test_logger_level_per_object_thread_safety + logger1 = Logger.new(StringIO.new) + logger2 = Logger.new(StringIO.new) + + level = Logger::DEBUG + assert_equal level, logger1.level, "Expected level #{level_name(level)}, got #{level_name(logger1.level)}" + assert_equal level, logger2.level, "Expected level #{level_name(level)}, got #{level_name(logger2.level)}" + + logger1.level = Logger::ERROR + assert_equal level, logger2.level, "Expected level #{level_name(level)}, got #{level_name(logger2.level)}" + end + + def test_logger_level_main_thread_safety + @logger.level = Logger::INFO + assert_level(Logger::INFO) + + latch = Concurrent::CountDownLatch.new + latch2 = Concurrent::CountDownLatch.new + + t = Thread.new do + latch.wait + assert_level(Logger::INFO) + latch2.count_down + end + + @logger.silence(Logger::ERROR) do + assert_level(Logger::ERROR) + latch.count_down + latch2.wait + end + + t.join + end + + def test_logger_level_local_thread_safety + @logger.level = Logger::INFO + assert_level(Logger::INFO) + + thread_1_latch = Concurrent::CountDownLatch.new + thread_2_latch = Concurrent::CountDownLatch.new + + threads = (1..2).collect do |thread_number| + Thread.new do + # force thread 2 to wait until thread 1 is already in @logger.silence + thread_2_latch.wait if thread_number == 2 + + @logger.silence(Logger::ERROR) do + assert_level(Logger::ERROR) + @logger.silence(Logger::DEBUG) do + # allow thread 2 to finish but hold thread 1 + if thread_number == 1 + thread_2_latch.count_down + thread_1_latch.wait + end + assert_level(Logger::DEBUG) + end + end + + # allow thread 1 to finish + assert_level(Logger::INFO) + thread_1_latch.count_down if thread_number == 2 + end + end + + threads.each(&:join) + assert_level(Logger::INFO) + end + + private + def level_name(level) + ::Logger::Severity.constants.find do |severity| + Logger.const_get(severity) == level + end.to_s + end + + def assert_level(level) + assert_equal level, @logger.level, "Expected level #{level_name(level)}, got #{level_name(@logger.level)}" + end end diff --git a/guides/source/5_0_release_notes.md b/guides/source/5_0_release_notes.md index 2fbd75e1c8..3573cecbe0 100644 --- a/guides/source/5_0_release_notes.md +++ b/guides/source/5_0_release_notes.md @@ -7,7 +7,7 @@ Highlights in Rails 5.0: * Action Cable * Rails API -* Active Rcord Attributes API +* Active Record Attributes API * Test Runner * Exclusive use of `rails` CLI over Rake * Sprockets 3 @@ -63,7 +63,7 @@ Please refer to the [Changelog][railties] for detailed changes. ### Removals -* Removed debugger supprt use byebug instead. `debugger` is not supported by +* Removed debugger support, use byebug instead. `debugger` is not supported by Ruby 2.2. ([commit](https://github.com/rails/rails/commit/93559da4826546d07014f8cfa399b64b4a143127)) @@ -284,7 +284,7 @@ Please refer to the [Changelog][action-view] for detailed changes. directive inside templates. ([Pull Request](https://github.com/rails/rails/pull/20781)) -* Add wildcard matching to explicit dependencies. +* Added wildcard matching to explicit dependencies. ([Pull Request](https://github.com/rails/rails/pull/20904)) * Make `disable_with` the default behavior for submit tags. Disables the @@ -329,25 +329,107 @@ Please refer to the [Changelog][active-record] for detailed changes. ### Removals +* Removed deprecated behavior allowing nested arrays to be passed as query + values. ([Pull Request](https://github.com/rails/rails/pull/17919)) + +* Removed deprecated `ActiveRecord::Tasks::DatabaseTasks#load_schema`. This + method was replaced by `ActiveRecord::Tasks::DatabaseTasks#load_schema_for`. + ([commit](https://github.com/rails/rails/commit/ad783136d747f73329350b9bb5a5e17c8f8800da)) + +* Removed deprecated `serialized_attributes`. + ([commit](https://github.com/rails/rails/commit/82043ab53cb186d59b1b3be06122861758f814b2)) + +* Removed deprecated automatic counter caches on `has_many :through`. + ([commit](https://github.com/rails/rails/commit/87c8ce340c6c83342df988df247e9035393ed7a0)) + +* Removed deprecated `sanitize_sql_hash_for_conditions`. + ([commit](https://github.com/rails/rails/commit/3a59dd212315ebb9bae8338b98af259ac00bbef3)) + +* Removed deprecated `Reflection#source_macro`. + ([commit](https://github.com/rails/rails/commit/ede8c199a85cfbb6457d5630ec1e285e5ec49313)) + +* Removed deprecated `symbolized_base_class` and `symbolized_sti_name`. + ([commit](https://github.com/rails/rails/commit/9013e28e52eba3a6ffcede26f85df48d264b8951)) + +* Removed deprecated `ActiveRecord::Base.disable_implicit_join_references=`. + ([commit](https://github.com/rails/rails/commit/0fbd1fc888ffb8cbe1191193bf86933110693dfc)) + +* Removed deprecated access to connection specification using a string accessor. + ([commit](https://github.com/rails/rails/commit/efdc20f36ccc37afbb2705eb9acca76dd8aabd4f)) + +* Removed deprecated support to preload instance-dependent associations. + ([commit](https://github.com/rails/rails/commit/4ed97979d14c5e92eb212b1a629da0a214084078)) + +* Removed deprecated support for PostgreSQL ranges with exclusive lower bounds. + ([commit](https://github.com/rails/rails/commit/a076256d63f64d194b8f634890527a5ed2651115)) + +* Removed deprecation when modifying a relation with cached Arel. + This raises an `ImmutableRelation` error instead. + ([commit](https://github.com/rails/rails/commit/3ae98181433dda1b5e19910e107494762512a86c)) + +* Removed `ActiveRecord::Serialization::XmlSerializer` from core. This feature + has been extracted into the + [activemodel-serializers-xml](https://github.com/rails/activemodel-serializers-xml) + gem. ([Pull Request](https://github.com/rails/rails/pull/21161)) + +* Removed support for the legacy `mysql` database adapter from core. It will + live on in a separate gem for now, but most users should just use `mysql2`. + +* Removed support for the `protected_attributes` gem. + ([commit](https://github.com/rails/rails/commit/f4fbc0301021f13ae05c8e941c8efc4ae351fdf9)) + ### Deprecations +* Deprecated passing a class as a value in a query. Users should pass strings + instead. ([Pull Request](https://github.com/rails/rails/pull/17916)) + * Deprecated returning `false` as a way to halt Active Record callback chains. The recommended way is to `throw(:abort)`. ([Pull Request](https://github.com/rails/rails/pull/17227)) +* Deprecated `ActiveRecord::Base.errors_in_transactional_callbacks=`. + ([commit](https://github.com/rails/rails/commit/07d3d402341e81ada0214f2cb2be1da69eadfe72)) + +* Deprecated passing of `start` value to `find_in_batches` and `find_each` + in favour of `begin_at` value. + ([Pull Request](https://github.com/rails/rails/pull/18961)) + +* Deprecated `Relation#uniq` use `Relation#distinct` instead. + ([commit](https://github.com/rails/rails/commit/adfab2dcf4003ca564d78d4425566dd2d9cd8b4f)) + +* Deprecated the PostgreSQL `:point` type in favor of a new one which will return + `Point` objects instead of an `Array` + ([Pull Request](https://github.com/rails/rails/pull/20448)) + +* Deprecated force association reload by passing a truthy argument to + association method. + ([Pull Request](https://github.com/rails/rails/pull/20888)) + +* Deprecated the keys for association `restrict_dependent_destroy` errors in favor + of new key names. + ([Pull Request](https://github.com/rails/rails/pull/20668)) + * Synchronize behavior of `#tables`. ([Pull Request](https://github.com/rails/rails/pull/21601)) +* Deprecated `SchemaCache#tables`, `SchemaCache#table_exists?` and + `SchemaCache#clear_table_cache!` in favor of their new data source + counterparts. + ([Pull Request](https://github.com/rails/rails/pull/21715)) + * Deprecated `connection.tables` on the SQLite3 and MySQL adapters. + ([Pull Request](https://github.com/rails/rails/pull/21601)) * Deprecated passing arguments to `#tables` - the `#tables` method of some adapters (mysql2, sqlite3) would return both tables and views while others (postgresql) just return tables. To make their behavior consistent, `#tables` will return only tables in the future. + ([Pull Request](https://github.com/rails/rails/pull/21601)) * Deprecated `table_exists?` - The `#table_exists?` method would check both tables and views. To make their behavior consistent with `#tables`, `#table_exists?` will check only tables in the future. + ([Pull Request](https://github.com/rails/rails/pull/21601)) ### Notable changes @@ -370,6 +452,89 @@ Please refer to the [Changelog][active-record] for detailed changes. ([Pull Request](https://github.com/rails/rails/pull/18937)) - Deprecate `required` option in favor of `optional` for `belongs_to` +* Changed the default `null` value for `timestamps` to `false`. + ([commit](https://github.com/rails/rails/commit/a939506f297b667291480f26fa32a373a18ae06a)) + +* Added `ActiveRecord::SecureToken` in order to encapsulate generation of + unique tokens for attributes in a model using `SecureRandom`. + ([Pull Request](https://github.com/rails/rails/pull/18217)) + +* Added `:if_exists` option for `drop_table`. + ([Pull Request](https://github.com/rails/rails/pull/18597)) + +* Added `ActiveRecord::Base#accessed_fields`, which can be used to quickly + discover which fields were read from a model when you are looking to only + select the data you need from the database. + ([commit](https://github.com/rails/rails/commit/be9b68038e83a617eb38c26147659162e4ac3d2c)) + +* Added the `#or` method on `ActiveRecord::Relation`, allowing use of the OR + operator to combine WHERE or HAVING clauses. + ([commit](https://github.com/rails/rails/commit/b0b37942d729b6bdcd2e3178eda7fa1de203b3d0)) + +* Added `:time` option added for `#touch`. + ([Pull Request](https://github.com/rails/rails/pull/18956)) + +* Added `ActiveRecord::Base.suppress` to prevent the receiver from being saved + during the given block. + ([Pull Request](https://github.com/rails/rails/pull/18910)) + +* `belongs_to` will now trigger a validation error by default if the + association is not present. You can turn this off on a per-association basis + with `optional: true`. + ([Pull Request](https://github.com/rails/rails/pull/18937)) + +* Added `config.active_record.dump_schemas` to configure the behavior of + `db:structure:dump`. + ([Pull Request](https://github.com/rails/rails/pull/19347)) + +* Added `config.active_record.warn_on_records_fetched_greater_than` option. + ([Pull Request](https://github.com/rails/rails/pull/18846)) + +* Added `cache_key` to `ActiveRecord::Relation`. + ([Pull Request](https://github.com/rails/rails/pull/20884)) + +* Added a native JSON data type support in MySQL. + ([Pull Request](https://github.com/rails/rails/pull/21110)) + +* Added support for dropping indexes concurrently in PostgreSQL. + ([Pull Request](https://github.com/rails/rails/pull/21317)) + +* Added `#views` and `#view_exists?` methods on connection adapters. + ([Pull Request](https://github.com/rails/rails/pull/21609)) + +* Added `ActiveRecord::Base.ignored_columns` to make some columns + invisible from Active Record. + ([Pull Request](https://github.com/rails/rails/pull/21720)) + +* Added `connection.data_sources` and `connection.data_source_exists?`. + These methods determine what relations can be used to back Active Record + models (usually tables and views). + ([Pull Request](https://github.com/rails/rails/pull/21715)) + +* Allow fixtures files to set the model class in the YAML file itself. + ([Pull Request](https://github.com/rails/rails/pull/20574)) + +* Added ability to default to `uuid` as primary key when generating database + migrations. ([Pull Request](https://github.com/rails/rails/pull/21762)) + +* Added `ActiveRecord::Relation#left_joins` and + `ActiveRecord::Relation#left_outer_joins`. + ([Pull Request](https://github.com/rails/rails/pull/12071)) + +* Added `after_{create,update,delete}_commit` callbacks. + ([Pull Request](https://github.com/rails/rails/pull/22516)) + +* Version the API presented to migration classes, so we can change parameter + defaults without breaking existing migrations, or forcing them to be + rewritten through a deprecation cycle. + ([Pull Request](https://github.com/rails/rails/pull/21538)) + +* `ApplicationRecord` is a new superclass for all app models, analogous to app + controllers subclassing `ApplicationController` instead of + `ActionController::Base`. This gives apps a single spot to configure app-wide + model behavior. + ([Pull Request](https://github.com/rails/rails/pull/22567)) + Active Model ------------ @@ -378,6 +543,10 @@ Please refer to the [Changelog][active-model] for detailed changes. ### Removals +* Removed deprecated `ActiveModel::Dirty#reset_#{attribute}` and + `ActiveModel::Dirty#reset_changes`. + ([Pull Request](https://github.com/rails/rails/commit/37175a24bd508e2983247ec5d011d57df836c743)) + * Removed XML serialization. This feature has been extracted into the [activemodel-serializers-xml](https://github.com/rails/activemodel-serializers-xml) gem. ([Pull Request](https://github.com/rails/rails/pull/21161)) @@ -388,8 +557,32 @@ Please refer to the [Changelog][active-model] for detailed changes. `ActiveModel::Validations` callback chains. The recommended way is to `throw(:abort)`. ([Pull Request](https://github.com/rails/rails/pull/17227)) +* Deprecated `ActiveModel::Errors#get`, `ActiveModel::Errors#set` and + `ActiveModel::Errors#[]=` methods that have inconsistent behavior. + ([Pull Request](https://github.com/rails/rails/pull/18634)) + +* Deprecated the `:tokenizer` option for `validates_length_of`, in favor of + plain Ruby. + ([Pull Request](https://github.com/rails/rails/pull/19585)) + +* Deprecated `ActiveModel::Errors#add_on_empty` and `ActiveModel::Errors#add_on_blank` + with no replacement. + ([Pull Request](https://github.com/rails/rails/pull/18996)) + ### Notable changes +* Added `ActiveModel::Errors#details` to determine what validator has failed. + ([Pull Request](https://github.com/rails/rails/pull/18322)) + +* Extracted `ActiveRecord::AttributeAssignment` to `ActiveModel::AttributeAssignment` + allowing to use it for any object as an includable module. + ([Pull Request](https://github.com/rails/rails/pull/10776)) + +* Added `ActiveModel::Dirty#[attr_name]_previously_changed?` and + `ActiveModel::Dirty#[attr_name]_previous_change` to improve access + to recorded changes after the model has been saved. + ([Pull Request](https://github.com/rails/rails/pull/19847)) + * Validate multiple contexts on `valid?` and `invalid?` at once. ([Pull Request](https://github.com/rails/rails/pull/21069)) @@ -399,11 +592,24 @@ Active Job Please refer to the [Changelog][active-job] for detailed changes. -### Removals +### Notable changes -### Deprecations +* `ActiveJob::Base.deserialize` delegates to the job class. this allows jobs + to attach arbitrary metadata when they get serialized and read it back when + they get performed. + ([Pull Request](https://github.com/rails/rails/pull/18260)) -### Notable changes +* A generated job now inherits from `app/jobs/application_job.rb` by default. + ([Pull Request](https://github.com/rails/rails/pull/19034)) + +* Allow `DelayedJob`, `Sidekiq`, `qu`, and `que` to report the job id back to + `ActiveJob::Base` as `provider_job_id`. + ([Pull Request](https://github.com/rails/rails/pull/20064), + [Pull Request](https://github.com/rails/rails/pull/20056)) + +* Implement a simple `AsyncJob` processor and associated `AsyncAdapter` that + queue jobs to a `concurrent-ruby` thread pool. + ([Pull Request](https://github.com/rails/rails/pull/21257)) Active Support @@ -413,20 +619,135 @@ Please refer to the [Changelog][active-support] for detailed changes. ### Removals +* Removed deprecated `ActiveSupport::JSON::Encoding::CircularReferenceError`. + ([commit](https://github.com/rails/rails/commit/d6e06ea8275cdc3f126f926ed9b5349fde374b10)) + +* Removed deprecated methods `ActiveSupport::JSON::Encoding.encode_big_decimal_as_string=` + and `ActiveSupport::JSON::Encoding.encode_big_decimal_as_string`. + ([commit](https://github.com/rails/rails/commit/c8019c0611791b2716c6bed48ef8dcb177b7869c)) + +* Removed deprecated `ActiveSupport::SafeBuffer#prepend`. + ([commit](https://github.com/rails/rails/commit/e1c8b9f688c56aaedac9466a4343df955b4a67ec)) + +* Removed deprecated methods from `Kernel`. `silence_stderr`, `silence_stream`, + `capture` and `quietly`. + ([commit](https://github.com/rails/rails/commit/481e49c64f790e46f4aff3ed539ed227d2eb46cb)) + +* Removed deprecated `active_support/core_ext/big_decimal/yaml_conversions` + file. + ([commit](https://github.com/rails/rails/commit/98ea19925d6db642731741c3b91bd085fac92241)) + +* Removed deprecated methods `ActiveSupport::Cache::Store.instrument` and + `ActiveSupport::Cache::Store.instrument=`. + ([commit](https://github.com/rails/rails/commit/a3ce6ca30ed0e77496c63781af596b149687b6d7)) + +* Removed deprecated `Class#superclass_delegating_accessor`. + Use `Class#class_attribute` instead. + ([Pull Request](https://github.com/rails/rails/pull/16938)) + +* Removed deprecated `ThreadSafe::Cache`. Use `Concurrent::Map` instead. + ([Pull Request](https://github.com/rails/rails/pull/21679)) + ### Deprecations -* Replace `ActiveSupport::Concurrency::Latch` with +* Deprecated `MissingSourceFile` in favor of `LoadError`. + ([commit](https://github.com/rails/rails/commit/734d97d2)) + +* Deprecated `alias_method_chain` in favour of `Module#prepend` introduced in + Ruby 2.0. + ([Pull Request](https://github.com/rails/rails/pull/19434)) + +* Deprecated `ActiveSupport::Concurrency::Latch` in favor of `Concurrent::CountDownLatch` from concurrent-ruby. ([Pull Request](https://github.com/rails/rails/pull/20866)) +* Deprecated `:prefix` option of `number_to_human_size` with no replacement. + ([Pull Request](https://github.com/rails/rails/pull/21191)) + +* Deprecated `Module#qualified_const_` in favour of the builtin + `Module#const_` methods. + ([Pull Request](https://github.com/rails/rails/pull/17845)) + +* Deprecated passing string to define callback. + ([Pull Request](https://github.com/rails/rails/pull/22598)) + +* Deprecated `ActiveSupport::Cache::Store#namespaced_key`, + `ActiveSupport::Cache::MemCachedStore#escape_key`, and + `ActiveSupport::Cache::FileStore#key_file_path`. + Use `normalize_key` instead. + + Deprecated `ActiveSupport::Cache::LocaleCache#set_cache_value` in favor of `write_cache_value`. + ([Pull Request](https://github.com/rails/rails/pull/22215)) + ### Notable changes +* Added `#verified` and `#valid_message?` methods to + `ActiveSupport::MessageVerifier`. + ([Pull Request](https://github.com/rails/rails/pull/17727)) + +* Changed the way in which callback chains can be halted. The preferred method + to halt a callback chain from now on is to explicitly `throw(:abort)`. + ([Pull Request](https://github.com/rails/rails/pull/17227)) + * New config option `config.active_support.halt_callback_chains_on_return_false` to specify whether ActiveRecord, ActiveModel and ActiveModel::Validations callback chains can be halted by returning `false` in a 'before' callback. ([Pull Request](https://github.com/rails/rails/pull/17227)) +* Changed the default test order from `:sorted` to `:random`. + ([commit](https://github.com/rails/rails/commit/5f777e4b5ee2e3e8e6fd0e2a208ec2a4d25a960d)) + +* Added `#on_weekend?`, `#next_weekday`, `#prev_weekday` methods to `Date`, + `Time`, and `DateTime`. + ([Pull Request](https://github.com/rails/rails/pull/18335)) + +* Added `same_time` option to `#next_week` and `#prev_week` for `Date`, `Time`, + and `DateTime`. + ([Pull Request](https://github.com/rails/rails/pull/18335)) + +* Added `#prev_day` and `#next_day` counterparts to `#yesterday` and + `#tomorrow` for `Date`, `Time`, and `DateTime`. + ([Pull Request](httpshttps://github.com/rails/rails/pull/18335)) + +* Added `SecureRandom.base58` for generation of random base58 strings. + ([commit](https://github.com/rails/rails/commit/b1093977110f18ae0cafe56c3d99fc22a7d54d1b)) + +* Added `file_fixture` to `ActiveSupport::TestCase`. + It provides a simple mechanism to access sample files in your test cases. + ([Pull Request](https://github.com/rails/rails/pull/18658)) + +* Added `#without` on `Enumerable` and `Array` to return a copy of an + enumerable without the specified elements. + ([Pull Request](https://github.com/rails/rails/pull/19157)) + +* Added `ActiveSupport::ArrayInquirer` and `Array#inquiry`. + ([Pull Request](https://github.com/rails/rails/pull/18939)) + +* Added `ActiveSupport::TimeZone#strptime` to allow parsing times as if + from a given timezone. + ([commit](https://github.com/rails/rails/commit/a5e507fa0b8180c3d97458a9b86c195e9857d8f6)) + +* Added `Integer#positive?` and `Integer#negative?` query methods + in the vein of `Fixnum#zero?`. + ([commit](https://github.com/rails/rails/commit/e54277a45da3c86fecdfa930663d7692fd083daa)) + +* Added a bang version to `ActiveSupport::OrderedOptions` get methods which will raise + an `KeyError` if the value is `.blank?`. + ([Pull Request](https://github.com/rails/rails/pull/20208)) + +* Added `Time.days_in_year` to return the number of days in the given year, or the + current year if no argument is provided. + ([commit](https://github.com/rails/rails/commit/2f4f4d2cf1e4c5a442459fc250daf66186d110fa)) + +* Added an evented file watcher to asynchronously detect changes in the + application source code, routes, locales, etc. + ([Pull Request](https://github.com/rails/rails/pull/22254)) + +* Added thread_m/cattr_accessor/reader/writer suite of methods for declaring + class and module variables that live per-thread. + ([Pull Request](https://github.com/rails/rails/pull/22630)) + Credits ------- diff --git a/guides/source/action_view_overview.md b/guides/source/action_view_overview.md index d9037674ca..543937f8e5 100644 --- a/guides/source/action_view_overview.md +++ b/guides/source/action_view_overview.md @@ -599,7 +599,7 @@ This would add something like "Process data files (0.34523)" to the log, which y #### cache -A method for caching fragments of a view rather than an entire action or page. This technique is useful caching pieces like menus, lists of news topics, static HTML fragments, and so on. This method takes a block that contains the content you wish to cache. See `ActionController::Caching::Fragments` for more information. +A method for caching fragments of a view rather than an entire action or page. This technique is useful for caching pieces like menus, lists of news topics, static HTML fragments, and so on. This method takes a block that contains the content you wish to cache. See `ActionController::Caching::Fragments` for more information. ```erb <% cache do %> diff --git a/guides/source/configuring.md b/guides/source/configuring.md index 47acff7c3f..81e406ae2e 100644 --- a/guides/source/configuring.md +++ b/guides/source/configuring.md @@ -104,7 +104,7 @@ application. Accepts a valid week day symbol (e.g. `:monday`). you don't want shown in the logs, such as passwords or credit card numbers. New applications filter out passwords by adding the following `config.filter_parameters+=[:password]` in `config/initializers/filter_parameter_logging.rb`. -* `config.force_ssl` forces all requests to be under HTTPS protocol by using `ActionDispatch::SSL` middleware. +* `config.force_ssl` forces all requests to be served over HTTPS by using the `ActionDispatch::SSL` middleware. This can be configured by setting `config.ssl_options` - see the [ActionDispatch::SSL documentation](http://edgeapi.rubyonrails.org/classes/ActionDispatch/SSL.html) for details. * `config.log_formatter` defines the formatter of the Rails logger. This option defaults to an instance of `ActiveSupport::Logger::SimpleFormatter` for all modes except production, where it defaults to `Logger::Formatter`. @@ -198,7 +198,7 @@ The full set of methods that can be used in this block are as follows: Every Rails application comes with a standard set of middleware which it uses in this order in the development environment: -* `ActionDispatch::SSL` forces every request to be under HTTPS protocol. Will be available if `config.force_ssl` is set to `true`. Options passed to this can be configured by using `config.ssl_options`. +* `ActionDispatch::SSL` forces every request to be served using HTTPS. Enabled if `config.force_ssl` is set to `true`. Options passed to this can be configured by setting `config.ssl_options`. * `ActionDispatch::Static` is used to serve static assets. Disabled if `config.public_file_server.enabled` is `false`. Set `config.public_file_server.index_name` if you need to serve a static directory index file that is not named `index`. For example, to serve `main.html` instead of `index.html` for directory requests, set `config.public_file_server.index_name` to `"main"`. * `Rack::Lock` wraps the app in mutex so it can only be called by a single thread at a time. Only enabled when `config.cache_classes` is `false`. * `ActiveSupport::Cache::Strategy::LocalCache` serves as a basic memory backed cache. This cache is not thread safe and is intended only for serving as a temporary memory cache for a single thread. diff --git a/guides/source/routing.md b/guides/source/routing.md index 2b1254f7a0..9401132500 100644 --- a/guides/source/routing.md +++ b/guides/source/routing.md @@ -392,7 +392,7 @@ The comments resource here will have the following routes generated for it: ### Routing concerns -Routing Concerns allows you to declare common routes that can be reused inside other resources and routes. To define a concern: +Routing concerns allow you to declare common routes that can be reused inside other resources and routes. To define a concern: ```ruby concern :commentable do diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index 2f18619e30..064b109a6f 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -75,7 +75,7 @@ module Rails class_option :edge, type: :boolean, default: false, desc: "Setup the #{name} with Gemfile pointing to Rails repository" - class_option :rc, type: :string, default: false, + class_option :rc, type: :string, default: nil, desc: "Path to file containing extra configuration options for rails command" class_option :no_rc, type: :boolean, default: false, diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/active_record_belongs_to_required_by_default.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/active_record_belongs_to_required_by_default.rb index 40c831ec58..78f4530514 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/active_record_belongs_to_required_by_default.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/active_record_belongs_to_required_by_default.rb @@ -1,5 +1,5 @@ # Be sure to restart your server when you modify this file. -# Require `belongs_to` associations by default. This is a new Rails 5.0 default, +# Require `belongs_to` associations by default. This is a new Rails 5.0 default, # so introduced as a config to ensure apps made with earlier versions of Rails aren't affected when upgrading. Rails.application.config.active_record.belongs_to_required_by_default = true diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/callback_terminator.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/callback_terminator.rb index 43510c244b..0b718aa1c6 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/callback_terminator.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/callback_terminator.rb @@ -1,5 +1,5 @@ # Be sure to restart your server when you modify this file. -# Do not halt callback chains when a callback returns false. This is a new Rails 5.0 default, +# Do not halt callback chains when a callback returns false. This is a new Rails 5.0 default, # so introduced as a config to ensure apps made with earlier versions of Rails aren't affected when upgrading. ActiveSupport.halt_callback_chains_on_return_false = false diff --git a/railties/lib/rails/generators/rails/plugin/templates/README.md b/railties/lib/rails/generators/rails/plugin/templates/README.md index 61ad1ed36a..9d2b74416e 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/README.md +++ b/railties/lib/rails/generators/rails/plugin/templates/README.md @@ -1,3 +1,28 @@ # <%= camelized_modules %> +Short description and motivation. -This project rocks and uses MIT-LICENSE. +## Usage +How to use my plugin. + +## Installation +Add this line to your application's Gemfile: + +```ruby +gem '<%= name %>' +``` + +And then execute: +```bash +$ bundle +``` + +Or install it yourself as: +```bash +$ gem install <%= name %> +``` + +## Contributing +Contribution directions go here. + +## License +The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT). diff --git a/railties/lib/rails/test_unit/minitest_plugin.rb b/railties/lib/rails/test_unit/minitest_plugin.rb index d39d2f32bf..d4ab2ada66 100644 --- a/railties/lib/rails/test_unit/minitest_plugin.rb +++ b/railties/lib/rails/test_unit/minitest_plugin.rb @@ -3,16 +3,13 @@ require "rails/test_unit/reporter" require "rails/test_unit/test_requirer" module Minitest - mattr_accessor(:hide_aggregated_results) { false } - - module AggregatedResultSuppresion + class SuppressedSummaryReporter < SummaryReporter + # Disable extra failure output after a run if output is inline. def aggregated_results - super unless Minitest.hide_aggregated_results + super unless options[:output_inline] end end - SummaryReporter.prepend AggregatedResultSuppresion - def self.plugin_rails_options(opts, options) executable = ::Rails::TestUnitReporter.executable opts.separator "" @@ -49,6 +46,12 @@ module Minitest options[:fail_fast] = true end + opts.on("-c", "--[no-]color", + "Enable color in the output") do |value| + options[:color] = value + end + + options[:color] = true options[:output_inline] = true options[:patterns] = opts.order! end @@ -77,9 +80,8 @@ module Minitest Minitest.backtrace_filter = ::Rails.backtrace_cleaner if ::Rails.respond_to?(:backtrace_cleaner) end - # Disable the extra failure output after a run, unless output is deferred. - self.hide_aggregated_results = options[:output_inline] - + self.reporter.reporters.clear # Replace progress reporter for colors. + self.reporter << SuppressedSummaryReporter.new(options[:io], options) self.reporter << ::Rails::TestUnitReporter.new(options[:io], options) end diff --git a/railties/lib/rails/test_unit/reporter.rb b/railties/lib/rails/test_unit/reporter.rb index 695c67756b..73b8d7d27b 100644 --- a/railties/lib/rails/test_unit/reporter.rb +++ b/railties/lib/rails/test_unit/reporter.rb @@ -9,10 +9,16 @@ module Rails def record(result) super + if options[:verbose] + io.puts color_output(format_line(result), by: result) + else + io.print color_output(result.result_code, by: result) + end + if output_inline? && result.failure && (!result.skipped? || options[:verbose]) io.puts io.puts - io.puts format_failures(result) + io.puts format_failures(result).map { |line| color_output(line, by: result) } io.puts io.puts format_rerun_snippet(result) io.puts @@ -56,6 +62,10 @@ module Rails options[:fail_fast] end + def format_line(result) + "%s#%s = %.2f s = %s" % [result.class, result.name, result.time, result.result_code] + end + def format_failures(result) result.failures.map do |failure| "#{failure.result_label}:\n#{result.class}##{result.name}:\n#{failure.message}\n" @@ -76,5 +86,25 @@ module Rails def app_root @app_root ||= defined?(ENGINE_ROOT) ? ENGINE_ROOT : Rails.root end + + def colored_output? + options[:color] && io.respond_to?(:tty?) && io.tty? + end + + codes = { red: 31, green: 32, yellow: 33 } + COLOR_BY_RESULT_CODE = { + "." => codes[:green], + "E" => codes[:red], + "F" => codes[:red], + "S" => codes[:yellow] + } + + def color_output(string, by:) + if colored_output? + "\e[#{COLOR_BY_RESULT_CODE[by.result_code]}m#{string}\e[0m" + else + string + end + end end end diff --git a/railties/test/test_unit/reporter_test.rb b/railties/test/test_unit/reporter_test.rb index 3ff7cd18cd..2d08d4ec30 100644 --- a/railties/test/test_unit/reporter_test.rb +++ b/railties/test/test_unit/reporter_test.rb @@ -1,5 +1,6 @@ require 'abstract_unit' require 'rails/test_unit/reporter' +require 'minitest/mock' class TestUnitReporterTest < ActiveSupport::TestCase class ExampleTest < Minitest::Test @@ -61,7 +62,7 @@ class TestUnitReporterTest < ActiveSupport::TestCase @reporter.record(failed_test) @reporter.report - expect = %r{\A\n\nFailure:\nTestUnitReporterTest::ExampleTest#woot:\nboo\n\nbin/rails test test/test_unit/reporter_test.rb:\d+\n\n\z} + expect = %r{\AF\n\nFailure:\nTestUnitReporterTest::ExampleTest#woot:\nboo\n\nbin/rails test test/test_unit/reporter_test.rb:\d+\n\n\z} assert_match expect, @output.string end @@ -69,7 +70,7 @@ class TestUnitReporterTest < ActiveSupport::TestCase @reporter.record(errored_test) @reporter.report - expect = %r{\A\n\nError:\nTestUnitReporterTest::ExampleTest#woot:\nArgumentError: wups\n No backtrace\n\nbin/rails test .*test/test_unit/reporter_test.rb:6\n\n\z} + expect = %r{\AE\n\nError:\nTestUnitReporterTest::ExampleTest#woot:\nArgumentError: wups\n No backtrace\n\nbin/rails test .*test/test_unit/reporter_test.rb:\d+\n\n\z} assert_match expect, @output.string end @@ -78,7 +79,7 @@ class TestUnitReporterTest < ActiveSupport::TestCase verbose.record(skipped_test) verbose.report - expect = %r{\A\n\nSkipped:\nTestUnitReporterTest::ExampleTest#woot:\nskipchurches, misstemples\n\nbin/rails test test/test_unit/reporter_test.rb:\d+\n\n\z} + expect = %r{\ATestUnitReporterTest::ExampleTest#woot = 10\.00 s = S\n\n\nSkipped:\nTestUnitReporterTest::ExampleTest#woot:\nskipchurches, misstemples\n\nbin/rails test test/test_unit/reporter_test.rb:\d+\n\n\z} assert_match expect, @output.string end @@ -113,6 +114,36 @@ class TestUnitReporterTest < ActiveSupport::TestCase assert_no_match 'Failed tests:', @output.string end + test "outputs colored passing results" do + @output.stub(:tty?, true) do + colored = Rails::TestUnitReporter.new @output, color: true, output_inline: true + colored.record(passing_test) + + expect = %r{\e\[32m\.\e\[0m} + assert_match expect, @output.string + end + end + + test "outputs colored skipped results" do + @output.stub(:tty?, true) do + colored = Rails::TestUnitReporter.new @output, color: true, output_inline: true + colored.record(skipped_test) + + expect = %r{\e\[33mS\e\[0m} + assert_match expect, @output.string + end + end + + test "outputs colored failed results" do + @output.stub(:tty?, true) do + colored = Rails::TestUnitReporter.new @output, color: true, output_inline: true + colored.record(errored_test) + + expected = %r{\e\[31mE\e\[0m\n\n\e\[31mError:\nTestUnitReporterTest::ExampleTest#woot:\nArgumentError: wups\n No backtrace\n\e\[0m} + assert_match expected, @output.string + end + end + private def assert_rerun_snippet_count(snippet_count) assert_equal snippet_count, @output.string.scan(%r{^bin/rails test }).size @@ -145,6 +176,7 @@ class TestUnitReporterTest < ActiveSupport::TestCase rescue Minitest::Assertion => e e end + st.time = 10 st end end |