diff options
-rw-r--r-- | activerecord/CHANGELOG.md | 17 | ||||
-rw-r--r-- | activerecord/lib/active_record/persistence.rb | 24 | ||||
-rw-r--r-- | activerecord/test/cases/adapter_test.rb | 14 | ||||
-rw-r--r-- | activerecord/test/cases/base_test.rb | 7 | ||||
-rw-r--r-- | activesupport/CHANGELOG.md | 5 | ||||
-rw-r--r-- | activesupport/lib/active_support/core_ext/date_time/calculations.rb | 2 | ||||
-rw-r--r-- | activesupport/lib/active_support/json/encoding.rb | 23 | ||||
-rw-r--r-- | activesupport/test/core_ext/date_time_ext_test.rb | 3 | ||||
-rw-r--r-- | guides/source/4_0_release_notes.md | 2 |
9 files changed, 84 insertions, 13 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index b3301f70dc..ecdf829823 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,5 +1,18 @@ ## Rails 4.0.0 (unreleased) ## +* Fixing issue #8345. Now throwing an error when one attempts to touch a + new object that has not yet been persisted. For instance: + + Example: + + ball = Ball.new + ball.touch :updated_at # => raises error + + It is not until the ball object has been persisted that it can be touched. + This follows the behavior of update_column. + + *John Wang* + * Preloading ordered `has_many :through` associations no longer applies invalid ordering to the `:through` association. Fixes #8663. @@ -21,7 +34,9 @@ Example: - after_commit :update_cache on: [:create, :update] + after_commit :update_cache on: [:create, :update] + + *Yves Senn* * Rename related indexes on `rename_table` and `rename_column`. This does not affect indexes with custom names. diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index 066f93635a..347f023793 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -367,7 +367,16 @@ module ActiveRecord # # # triggers @brake.car.touch and @brake.car.corporation.touch # @brake.touch + # + # Note that +touch+ must be used on a persisted object, or else an + # ActiveRecordError will be thrown. For example: + # + # ball = Ball.new + # ball.touch(:updated_at) # => raises ActiveRecordError + # def touch(name = nil) + raise ActiveRecordError, "can not touch on a new record object" unless persisted? + attributes = timestamp_attributes_for_update_in_model attributes << name if name @@ -420,13 +429,22 @@ module ActiveRecord # Returns the number of affected rows. def update_record(attribute_names = @attributes.keys) attributes_with_values = arel_attributes_with_values_for_update(attribute_names) - if attributes_with_values.empty? 0 else klass = self.class - stmt = klass.unscoped.where(klass.arel_table[klass.primary_key].eq(id)).arel.compile_update(attributes_with_values) - klass.connection.update stmt + column_hash = klass.connection.schema_cache.columns_hash klass.table_name + db_columns_with_values = attributes_with_values.map { |attr,value| + real_column = column_hash[attr.name] + [real_column, value] + } + bind_attrs = attributes_with_values.dup + bind_attrs.keys.each_with_index do |column, i| + real_column = db_columns_with_values[i].first + bind_attrs[column] = klass.connection.substitute_at(real_column, i) + end + stmt = klass.unscoped.where(klass.arel_table[klass.primary_key].eq(id)).arel.compile_update(bind_attrs) + klass.connection.update stmt, 'SQL', db_columns_with_values end end diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb index f9149c1819..0af7cbf74f 100644 --- a/activerecord/test/cases/adapter_test.rb +++ b/activerecord/test/cases/adapter_test.rb @@ -1,4 +1,5 @@ require "cases/helper" +require "models/book" module ActiveRecord class AdapterTest < ActiveRecord::TestCase @@ -6,6 +7,19 @@ module ActiveRecord @connection = ActiveRecord::Base.connection end + ## + # PostgreSQL does not support null bytes in strings + unless current_adapter?(:PostgreSQLAdapter) + def test_update_prepared_statement + b = Book.create(name: "my \x00 book") + b.reload + assert_equal "my \x00 book", b.name + b.update_attributes(name: "my other \x00 book") + b.reload + assert_equal "my other \x00 book", b.name + end + end + def test_tables tables = @connection.tables assert tables.include?("accounts") diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index fbc66540d6..af1845c937 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1447,6 +1447,13 @@ class BasicsTest < ActiveRecord::TestCase assert_match(/\/#{dev.id}$/, dev.cache_key) end + def test_touch_should_raise_error_on_a_new_object + company = Company.new(:rating => 1, :name => "37signals", :firm_name => "37signals") + assert_raises(ActiveRecord::ActiveRecordError) do + company.touch :updated_at + end + end + def test_cache_key_format_is_precise_enough dev = Developer.first key = dev.cache_key diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index 2515d378fd..b07ab749a3 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,5 +1,10 @@ ## Rails 4.0.0 (unreleased) ## +* Prevent `DateTime#change` from truncating the second fraction, when seconds + do not need to be changed. + + *Chris Baynes* + * Added `ActiveSupport::TimeWithZone#to_r` for `Time#at` compatibility. Before this change: diff --git a/activesupport/lib/active_support/core_ext/date_time/calculations.rb b/activesupport/lib/active_support/core_ext/date_time/calculations.rb index 97aad008f5..9f0864d9bb 100644 --- a/activesupport/lib/active_support/core_ext/date_time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/date_time/calculations.rb @@ -59,7 +59,7 @@ class DateTime options.fetch(:day, day), options.fetch(:hour, hour), options.fetch(:min, options[:hour] ? 0 : min), - options.fetch(:sec, (options[:hour] || options[:min]) ? 0 : sec), + options.fetch(:sec, (options[:hour] || options[:min]) ? 0 : sec + sec_fraction), options.fetch(:offset, offset), options.fetch(:start, start) ) diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb index 8f5db5968c..9bf1ea35b3 100644 --- a/activesupport/lib/active_support/json/encoding.rb +++ b/activesupport/lib/active_support/json/encoding.rb @@ -38,6 +38,7 @@ module ActiveSupport class CircularReferenceError < StandardError; end class Encoder + attr_reader :options def initialize(options = nil) @options = options || {} @@ -62,9 +63,9 @@ module ActiveSupport if value.is_a?(Array) || value.is_a?(Hash) # hashes and arrays need to get encoder in the options, so that # they can detect circular references. - @options.merge(:encoder => self) + options.merge(:encoder => self) else - @options.dup + options.dup end end @@ -252,6 +253,18 @@ end module Enumerable def as_json(options = nil) #:nodoc: + to_a.as_json(options) + end +end + +class Range + def as_json(options = nil) #:nodoc: + to_s + end +end + +class Array + def as_json(options = nil) #:nodoc: # use encoder as a proxy to call as_json on all elements, to protect from circular references encoder = options && options[:encoder] || ActiveSupport::JSON::Encoding::Encoder.new(options) map { |v| encoder.as_json(v, options) } @@ -263,12 +276,6 @@ module Enumerable end end -class Range - def as_json(options = nil) #:nodoc: - to_s - end -end - class Hash def as_json(options = nil) #:nodoc: # create a subset of the hash by applying :only or :except diff --git a/activesupport/test/core_ext/date_time_ext_test.rb b/activesupport/test/core_ext/date_time_ext_test.rb index 59ca2a4059..7be578599b 100644 --- a/activesupport/test/core_ext/date_time_ext_test.rb +++ b/activesupport/test/core_ext/date_time_ext_test.rb @@ -129,6 +129,9 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase assert_equal DateTime.civil(2005,2,22,16), DateTime.civil(2005,2,22,15,15,10).change(:hour => 16) assert_equal DateTime.civil(2005,2,22,16,45), DateTime.civil(2005,2,22,15,15,10).change(:hour => 16, :min => 45) assert_equal DateTime.civil(2005,2,22,15,45), DateTime.civil(2005,2,22,15,15,10).change(:min => 45) + + # datetime with fractions of a second + assert_equal DateTime.civil(2005,2,1,15,15,10.7), DateTime.civil(2005,2,22,15,15,10.7).change(:day => 1) end def test_advance diff --git a/guides/source/4_0_release_notes.md b/guides/source/4_0_release_notes.md index 9c157ec0b3..463da488f2 100644 --- a/guides/source/4_0_release_notes.md +++ b/guides/source/4_0_release_notes.md @@ -200,6 +200,8 @@ Please refer to the [Changelog](https://github.com/rails/rails/blob/master/activ * Remove IdentityMap. +* Remove automatic execution of EXPLAIN queries. The option `active_record.auto_explain_threshold_in_seconds` is no longer used and should be removed. + * Adds `ActiveRecord::NullRelation` and `ActiveRecord::Relation#none` implementing the null object pattern for the Relation class. * Added `create_join_table` migration helper to create HABTM join tables. |