diff options
10 files changed, 99 insertions, 34 deletions
diff --git a/activemodel/lib/active_model/type.rb b/activemodel/lib/active_model/type.rb index 313f17830f..0d3349e236 100644 --- a/activemodel/lib/active_model/type.rb +++ b/activemodel/lib/active_model/type.rb @@ -27,7 +27,7 @@ module ActiveModel delegate :add_modifier, to: :registry # Add a new type to the registry, allowing it to be referenced as a - # symbol by ActiveModel::Attributes::ClassMethods#attribute. If your + # symbol by ActiveRecord::Attributes::ClassMethods#attribute. If your # type is only meant to be used with a specific database adapter, you can # do so by passing +adapter: :postgresql+. If your type has the same # name as a native type for the current adapter, an exception will be diff --git a/activerecord/lib/active_record/attributes.rb b/activerecord/lib/active_record/attributes.rb index 4b92e5835f..dcbfca1c04 100644 --- a/activerecord/lib/active_record/attributes.rb +++ b/activerecord/lib/active_record/attributes.rb @@ -116,7 +116,7 @@ module ActiveRecord # Users may also define their own custom types, as long as they respond # to the methods defined on the value type. The method +deserialize+ or # +cast+ will be called on your type object, with raw input from the - # database or from your controllers. See ActiveRecord::Type::Value for the + # database or from your controllers. See ActiveModel::Type::Value for the # expected API. It is recommended that your type objects inherit from an # existing type, or from ActiveRecord::Type::Value # @@ -143,7 +143,7 @@ module ActiveRecord # store_listing.price_in_cents # => 1000 # # For more details on creating custom types, see the documentation for - # ActiveRecord::Type::Value. For more details on registering your types + # ActiveModel::Type::Value. For more details on registering your types # to be referenced by a symbol, see ActiveRecord::Type.register. You can # also pass a type object directly, in place of a symbol. # @@ -190,7 +190,7 @@ module ActiveRecord # The type of an attribute is given the opportunity to change how dirty # tracking is performed. The methods +changed?+ and +changed_in_place?+ # will be called from ActiveModel::Dirty. See the documentation for those - # methods in ActiveRecord::Type::Value for more details. + # methods in ActiveModel::Type::Value for more details. def attribute(name, cast_type, **options) name = name.to_s reload_schema_from_cache diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index ffde4f2c93..83d1d7cd01 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -475,7 +475,7 @@ module ActiveRecord # Checks to see if a column exists. # - # t.string(:name) unless t.column_exists?(:name, :string) + # t.string(:name) unless t.column_exists?(:name, :string) # # See {connection.column_exists?}[rdoc-ref:SchemaStatements#column_exists?] def column_exists?(column_name, type = nil, options = {}) @@ -496,9 +496,9 @@ module ActiveRecord # Checks to see if an index exists. # - # unless t.index_exists?(:branch_id) - # t.index(:branch_id) - # end + # unless t.index_exists?(:branch_id) + # t.index(:branch_id) + # end # # See {connection.index_exists?}[rdoc-ref:SchemaStatements#index_exists?] def index_exists?(column_name, options = {}) diff --git a/activerecord/lib/active_record/log_subscriber.rb b/activerecord/lib/active_record/log_subscriber.rb index ad71c6cde8..4b8d8d9105 100644 --- a/activerecord/lib/active_record/log_subscriber.rb +++ b/activerecord/lib/active_record/log_subscriber.rb @@ -15,16 +15,6 @@ module ActiveRecord rt end - def render_bind(attr, type_casted_value) - value = if attr.type.binary? && attr.value - "<#{attr.value_for_database.to_s.bytesize} bytes of binary data>" - else - type_casted_value - end - - [attr.name, value] - end - def sql(event) self.class.runtime += event.duration return unless logger.debug? @@ -39,7 +29,8 @@ module ActiveRecord binds = nil unless (payload[:binds] || []).empty? - binds = " " + payload[:binds].zip(payload[:type_casted_binds]).map { |attr, value| + casted_params = type_casted_binds(payload[:binds], payload[:type_casted_binds]) + binds = " " + payload[:binds].zip(casted_params).map { |attr, value| render_bind(attr, value) }.inspect end @@ -52,6 +43,20 @@ module ActiveRecord private + def type_casted_binds(binds, casted_binds) + casted_binds || binds.map { |attr| type_cast attr.value_for_database } + end + + def render_bind(attr, type_casted_value) + value = if attr.type.binary? && attr.value + "<#{attr.value_for_database.to_s.bytesize} bytes of binary data>" + else + type_casted_value + end + + [attr.name, value] + end + def colorize_payload_name(name, payload_name) if payload_name.blank? || payload_name == "SQL" # SQL vs Model Load/Exists color(name, MAGENTA, true) @@ -84,6 +89,10 @@ module ActiveRecord def logger ActiveRecord::Base.logger end + + def type_cast(value) + ActiveRecord::Base.connection.type_cast(value) + end end end diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb index 16cf2bd2d0..4cd258695d 100644 --- a/activerecord/test/cases/query_cache_test.rb +++ b/activerecord/test/cases/query_cache_test.rb @@ -10,9 +10,30 @@ class QueryCacheTest < ActiveRecord::TestCase fixtures :tasks, :topics, :categories, :posts, :categories_posts - teardown do + class ShouldNotHaveExceptionsLogger < ActiveRecord::LogSubscriber + attr_reader :logger + + def initialize + super + @logger = ::Logger.new File::NULL + @exception = false + end + + def exception? + @exception + end + + def sql(event) + super + rescue + @exception = true + end + end + + def teardown Task.connection.clear_query_cache ActiveRecord::Base.connection.disable_query_cache! + super end def test_exceptional_middleware_clears_and_disables_cache_on_error @@ -121,6 +142,19 @@ class QueryCacheTest < ActiveRecord::TestCase end end + def test_cache_does_not_raise_exceptions + logger = ShouldNotHaveExceptionsLogger.new + subscriber = ActiveSupport::Notifications.subscribe "sql.active_record", logger + + ActiveRecord::Base.cache do + assert_queries(1) { Task.find(1); Task.find(1) } + end + + assert_not_predicate logger, :exception? + ensure + ActiveSupport::Notifications.unsubscribe subscriber + end + def test_cache_is_flat Task.cache do assert_queries(1) { Topic.find(1); Topic.find(1); } diff --git a/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb b/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb index b1e6fe71e0..1e82b4acc2 100644 --- a/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +++ b/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb @@ -34,7 +34,7 @@ class Module # end # # Current.new.user # => NoMethodError - def thread_mattr_reader(*syms) + def thread_mattr_reader(*syms) # :nodoc: options = syms.extract_options! syms.each do |sym| @@ -77,7 +77,7 @@ class Module # end # # Current.new.user = "DHH" # => NoMethodError - def thread_mattr_writer(*syms) + def thread_mattr_writer(*syms) # :nodoc: options = syms.extract_options! syms.each do |sym| raise NameError.new("invalid attribute name: #{sym}") unless /^[_A-Za-z]\w*$/.match?(sym) diff --git a/activesupport/test/evented_file_update_checker_test.rb b/activesupport/test/evented_file_update_checker_test.rb index cc47318974..77d8dcb0f8 100644 --- a/activesupport/test/evented_file_update_checker_test.rb +++ b/activesupport/test/evented_file_update_checker_test.rb @@ -36,6 +36,8 @@ class EventedFileUpdateCheckerTest < ActiveSupport::TestCase end test "notifies forked processes" do + jruby_skip "Forking not available on JRuby" + FileUtils.touch(tmpfiles) checker = new_checker(tmpfiles) {} diff --git a/activesupport/test/file_update_checker_shared_tests.rb b/activesupport/test/file_update_checker_shared_tests.rb index cd6a58e840..48cd387196 100644 --- a/activesupport/test/file_update_checker_shared_tests.rb +++ b/activesupport/test/file_update_checker_shared_tests.rb @@ -49,6 +49,7 @@ module FileUpdateCheckerSharedTests checker = new_checker(tmpfiles) { i += 1 } touch(tmpfiles) + wait assert checker.execute_if_updated assert_equal 1, i @@ -62,6 +63,7 @@ module FileUpdateCheckerSharedTests checker = new_checker(tmpfiles) { i += 1 } touch(tmpfiles) + wait assert checker.execute_if_updated assert_equal 1, i @@ -75,6 +77,7 @@ module FileUpdateCheckerSharedTests checker = new_checker(tmpfiles) { i += 1 } rm_f(tmpfiles) + wait assert checker.execute_if_updated assert_equal 1, i @@ -87,6 +90,7 @@ module FileUpdateCheckerSharedTests assert !checker.updated? touch(tmpfiles) + wait assert checker.updated? end @@ -100,6 +104,7 @@ module FileUpdateCheckerSharedTests assert !checker.updated? touch(tmpfiles) + wait assert checker.updated? end @@ -113,6 +118,7 @@ module FileUpdateCheckerSharedTests assert !checker.updated? rm_f(tmpfiles) + wait assert checker.updated? end @@ -129,6 +135,7 @@ module FileUpdateCheckerSharedTests checker = new_checker(tmpfiles) { i += 1 } touch(tmpfiles[1..-1]) + wait assert checker.execute_if_updated assert_equal 1, i @@ -145,6 +152,7 @@ module FileUpdateCheckerSharedTests checker = new_checker(tmpfiles) { i += 1 } touch(tmpfiles[1..-1]) + wait assert checker.execute_if_updated assert_equal 1, i @@ -157,6 +165,7 @@ module FileUpdateCheckerSharedTests assert !checker.updated? touch(tmpfiles) + wait assert checker.updated? checker.execute @@ -169,6 +178,7 @@ module FileUpdateCheckerSharedTests checker = new_checker([], tmpdir => :rb) { i += 1 } touch(tmpfile("foo.rb")) + wait assert checker.execute_if_updated assert_equal 1, i @@ -180,11 +190,13 @@ module FileUpdateCheckerSharedTests checker = new_checker([], tmpdir => [:rb, :txt]) { i += 1 } touch(tmpfile("foo.rb")) + wait assert checker.execute_if_updated assert_equal 1, i touch(tmpfile("foo.txt")) + wait assert checker.execute_if_updated assert_equal 2, i @@ -196,6 +208,7 @@ module FileUpdateCheckerSharedTests checker = new_checker([], tmpdir => :txt) { i += 1 } touch(tmpfile("foo.rb")) + wait assert !checker.execute_if_updated assert_equal 0, i @@ -208,6 +221,7 @@ module FileUpdateCheckerSharedTests checker = new_checker([non_existing]) { i += 1 } touch(non_existing) + wait assert checker.execute_if_updated assert_equal 1, i @@ -226,6 +240,7 @@ module FileUpdateCheckerSharedTests assert_equal 0, i touch(File.join(subdir, "nested.rb")) + wait assert checker.execute_if_updated assert_equal 1, i @@ -240,17 +255,20 @@ module FileUpdateCheckerSharedTests checker = new_checker([], tmpdir => :rb, subdir => :txt) { i += 1 } touch(tmpfile("new.txt")) + wait assert !checker.execute_if_updated assert_equal 0, i # subdir does not look for Ruby files, but its parent tmpdir does. touch(File.join(subdir, "nested.rb")) + wait assert checker.execute_if_updated assert_equal 1, i touch(File.join(subdir, "nested.txt")) + wait assert checker.execute_if_updated assert_equal 2, i diff --git a/guides/source/active_record_migrations.md b/guides/source/active_record_migrations.md index a45becf670..d91c9bd606 100644 --- a/guides/source/active_record_migrations.md +++ b/guides/source/active_record_migrations.md @@ -467,6 +467,8 @@ the first time (i.e. on the date the migration is applied). Some adapters may support additional options; see the adapter specific API docs for further information. +NOTE: `null` and `default` cannot be specified via command line. + ### Foreign Keys While it's not required you might want to add foreign key constraints to @@ -1018,10 +1020,10 @@ such features, the `execute` method can be used to execute arbitrary SQL. Migrations and Seed Data ------------------------ -The main purpose of Rails' migration feature is to issue commands that modify the -schema using a consistent process. Migrations can also be used -to add or modify data. This is useful in an existing database that can't be destroyed -and recreated, such as a production database. +The main purpose of Rails' migration feature is to issue commands that modify the +schema using a consistent process. Migrations can also be used +to add or modify data. This is useful in an existing database that can't be destroyed +and recreated, such as a production database. ```ruby class AddInitialProducts < ActiveRecord::Migration[5.0] @@ -1037,10 +1039,10 @@ class AddInitialProducts < ActiveRecord::Migration[5.0] end ``` -To add initial data after a database is created, Rails has a built-in -'seeds' feature that makes the process quick and easy. This is especially -useful when reloading the database frequently in development and test environments. -It's easy to get started with this feature: just fill up `db/seeds.rb` with some +To add initial data after a database is created, Rails has a built-in +'seeds' feature that makes the process quick and easy. This is especially +useful when reloading the database frequently in development and test environments. +It's easy to get started with this feature: just fill up `db/seeds.rb` with some Ruby code, and run `rails db:seed`: ```ruby diff --git a/guides/source/active_support_core_extensions.md b/guides/source/active_support_core_extensions.md index 60a6c37f82..70b04a9695 100644 --- a/guides/source/active_support_core_extensions.md +++ b/guides/source/active_support_core_extensions.md @@ -2661,7 +2661,7 @@ The method `transform_keys` accepts a block and returns a hash that has applied ```ruby {nil => nil, 1 => 1, a: :a}.transform_keys { |key| key.to_s.upcase } -# => {"" => nil, "A" => :a, "1" => 1} +# => {"" => nil, "1" => 1, "A" => :a} ``` In case of key collision, one of the values will be chosen. The chosen value may not always be the same given the same hash: @@ -2703,7 +2703,7 @@ The method `stringify_keys` returns a hash that has a stringified version of the ```ruby {nil => nil, 1 => 1, a: :a}.stringify_keys -# => {"" => nil, "a" => :a, "1" => 1} +# => {"" => nil, "1" => 1, "a" => :a} ``` In case of key collision, one of the values will be chosen. The chosen value may not always be the same given the same hash: @@ -2745,7 +2745,7 @@ The method `symbolize_keys` returns a hash that has a symbolized version of the ```ruby {nil => nil, 1 => 1, "a" => "a"}.symbolize_keys -# => {1=>1, nil=>nil, :a=>"a"} +# => {nil=>nil, 1=>1, :a=>"a"} ``` WARNING. Note in the previous example only one key was symbolized. @@ -2822,7 +2822,7 @@ Ruby has built-in support for taking slices out of strings and arrays. Active Su ```ruby {a: 1, b: 2, c: 3}.slice(:a, :c) -# => {:c=>3, :a=>1} +# => {:a=>1, :c=>3} {a: 1, b: 2, c: 3}.slice(:b, :X) # => {:b=>2} # non-existing keys are ignored |