From 10f6f90d9d1bbc9598bffea90752fc6bd76904cd Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Sun, 28 Oct 2012 14:18:31 -0500 Subject: AR::AttributeMethods#[] raises AM::AttributeMissingError for missing attributes. This fixes the following behaviour: class Person < ActiveRecord::Base belongs_to :company end # Before: person = Person.select('id').first person[:name] # => nil person.name # => ActiveModel::MissingAttributeError: missing_attribute: name person[:company_id] # => nil person.company # => nil # After: person = Person.select('id').first person[:name] # => ActiveModel::MissingAttributeError: missing_attribute: name person.name # => ActiveModel::MissingAttributeError: missing_attribute: name person[:company_id] # => ActiveModel::MissingAttributeError: missing_attribute: company_id person.company # => ActiveModel::MissingAttributeError: missing_attribute: company_id Fixes #5433. --- activerecord/CHANGELOG.md | 25 +++++++++++++++++++++- .../lib/active_record/attribute_methods.rb | 10 +++++++-- activerecord/test/cases/attribute_methods_test.rb | 6 ++++++ 3 files changed, 38 insertions(+), 3 deletions(-) (limited to 'activerecord') diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 815902a129..f630be6f70 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,5 +1,28 @@ ## Rails 4.0.0 (unreleased) ## +* `ActiveRecord::AttributeMethods#[]` raises `ActiveModel::MissingAttributeError` + error if the given attribute is missing. Fixes #5433. + + class Person < ActiveRecord::Base + belongs_to :company + end + + # Before: + person = Person.select('id').first + person[:name] # => nil + person.name # => ActiveModel::MissingAttributeError: missing_attribute: name + person[:company_id] # => nil + person.company # => nil + + # After: + person = Person.select('id').first + person[:name] # => ActiveModel::MissingAttributeError: missing_attribute: name + person.name # => ActiveModel::MissingAttributeError: missing_attribute: name + person[:company_id] # => ActiveModel::MissingAttributeError: missing_attribute: company_id + person.company # => ActiveModel::MissingAttributeError: missing_attribute: company_id + + *Francesco Rodriguez* + * Small binary fields use the `VARBINARY` MySQL type, instead of `TINYBLOB`. *Victor Costan* @@ -51,7 +74,7 @@ *Scott Willson* -* Fix bug where sum(expression) returns string '0' for no matching records +* Fix bug where sum(expression) returns string '0' for no matching records. Fixes #7439 *Tim Macfarlane* diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index 9a4fcdfda3..101c641877 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -266,16 +266,22 @@ module ActiveRecord # Returns the value of the attribute identified by attr_name after 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)). - # (Alias for the protected read_attribute method). + # (Alias for the protected read_attribute method). It raises an ActiveModel::MissingAttributeError + # error if the identified attribute is missing. # # class Person < ActiveRecord::Base + # belongs_to :organization # end # # person = Person.new(name: 'Francesco', age: '22' # person[:name] # => "Francesco" # person[:age] # => 22 + # + # person = Person.select('id').first + # person[:name] # => ActiveModel::MissingAttributeError: missing attribute: name + # person[:organization_id] # => ActiveModel::MissingAttributeError: missing attribute: organization_id def [](attr_name) - read_attribute(attr_name) + read_attribute(attr_name) { |n| missing_attribute(n, caller) } end # Updates the attribute identified by attr_name with the specified +value+. diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb index c2b58fd7d1..8b82b79219 100644 --- a/activerecord/test/cases/attribute_methods_test.rb +++ b/activerecord/test/cases/attribute_methods_test.rb @@ -287,6 +287,12 @@ class AttributeMethodsTest < ActiveRecord::TestCase assert_equal "Don't change the topic", topic[:title] end + def test_read_attribute_raises_missing_attribute_error_when_not_exists + computer = Computer.select('id').first + assert_raises(ActiveModel::MissingAttributeError) { computer[:developer] } + assert_raises(ActiveModel::MissingAttributeError) { computer[:extendedWarranty] } + end + def test_read_attribute_when_false topic = topics(:first) topic.approved = false -- cgit v1.2.3