From 9e5f7cc62e9ef1e865c6eba28be69e935434f8e6 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Fri, 5 Oct 2012 19:23:25 +0100 Subject: Revert "Key the attributes hash with symbols" This reverts commit 86c3dfbd47cb96af02daaa655963292b1a1b110e. Conflicts: activerecord/lib/active_record/attribute_methods/read.rb Reason: whilst this increased performance, it also presents a DoS risk via memory exhaustion if users were allowing user input to dictate the arguments of read/write_attribute. I will investigate alternative ways to cut down on string allocations here. --- activerecord/lib/active_record/attribute_methods/read.rb | 14 +++++--------- .../attribute_methods/time_zone_conversion.rb | 2 +- activerecord/lib/active_record/attribute_methods/write.rb | 4 ++-- activerecord/test/cases/attribute_methods_test.rb | 4 ++-- 4 files changed, 10 insertions(+), 14 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb index 6213b5dcd5..a26c5e0f5b 100644 --- a/activerecord/lib/active_record/attribute_methods/read.rb +++ b/activerecord/lib/active_record/attribute_methods/read.rb @@ -46,7 +46,7 @@ module ActiveRecord def define_method_attribute(attr_name) generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1 def __temp__ - read_attribute(:'#{attr_name}') { |n| missing_attribute(n, caller) } + read_attribute('#{attr_name}') { |n| missing_attribute(n, caller) } end alias_method '#{attr_name}', :__temp__ undef_method :__temp__ @@ -70,17 +70,13 @@ module ActiveRecord # it has been typecast (for example, "2004-12-12" in a data column is cast # to a date object, like Date.new(2004, 12, 12)). def read_attribute(attr_name) - return unless attr_name - name_sym = attr_name.to_sym - # If it's cached, just return it # We use #[] first as a perf optimization for non-nil values. See https://gist.github.com/3552829. - @attributes_cache[name_sym] || @attributes_cache.fetch(name_sym) { - name = attr_name.to_s - + name = attr_name.to_s + @attributes_cache[name] || @attributes_cache.fetch(name) { column = @columns_hash.fetch(name) { return @attributes.fetch(name) { - if name_sym == :id && self.class.primary_key != name + if name == 'id' && self.class.primary_key != name read_attribute(self.class.primary_key) end } @@ -91,7 +87,7 @@ module ActiveRecord } if self.class.cache_attribute?(name) - @attributes_cache[name_sym] = column.type_cast(value) + @attributes_cache[name] = column.type_cast(value) else column.type_cast value end diff --git a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb index b9a69cdb0a..f36a5806a9 100644 --- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb +++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb @@ -50,7 +50,7 @@ module ActiveRecord if (rounded_value != rounded_time) || (!rounded_value && original_time) write_attribute("#{attr_name}", original_time) #{attr_name}_will_change! - @attributes_cache[:"#{attr_name}"] = zoned_time + @attributes_cache["#{attr_name}"] = zoned_time end end EOV diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb index 6eb9e25fd9..fa9097db1f 100644 --- a/activerecord/lib/active_record/attribute_methods/write.rb +++ b/activerecord/lib/active_record/attribute_methods/write.rb @@ -26,13 +26,13 @@ module ActiveRecord def write_attribute(attr_name, value) attr_name = attr_name.to_s attr_name = self.class.primary_key if attr_name == 'id' && self.class.primary_key - @attributes_cache.delete(attr_name.to_sym) + @attributes_cache.delete(attr_name) column = column_for_attribute(attr_name) # If we're dealing with a binary column, write the data to the cache # so we don't attempt to typecast multiple times. if column && column.binary? - @attributes_cache[attr_name.to_sym] = value + @attributes_cache[attr_name] = value end if column || @attributes.has_key?(attr_name) diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb index d08b157011..c2b58fd7d1 100644 --- a/activerecord/test/cases/attribute_methods_test.rb +++ b/activerecord/test/cases/attribute_methods_test.rb @@ -542,10 +542,10 @@ class AttributeMethodsTest < ActiveRecord::TestCase val = t.send attr_name unless attr_name == "type" if attribute_gets_cached assert cached_columns.include?(attr_name) - assert_equal val, cache[attr_name.to_sym] + assert_equal val, cache[attr_name] else assert uncached_columns.include?(attr_name) - assert !cache.include?(attr_name.to_sym) + assert !cache.include?(attr_name) end end end -- cgit v1.2.3