From 4f107da4ffafa2b77d87fc5a6fb09fa34343184c Mon Sep 17 00:00:00 2001
From: Ernie Miller <ernie@erniemiller.org>
Date: Thu, 6 Sep 2012 15:39:42 -0400
Subject: Raise MissingAttributeError on query methods

When calling a query method on an attribute that was not selected by
an ActiveRecord query, an ActiveModel::MissingAttributeError is not
raised. Instead, a nil value is returned, which will return false once
cast to boolean.

This is undesirable, as we should not give the impression that we know
the attribute's boolean value when we haven't loaded the attribute's
(possibly) non-boolean value from the database.

This issue is present on versions going back as far as 2.3, at least.
---
 activerecord/CHANGELOG.md                                 | 6 ++++++
 activerecord/lib/active_record/attribute_methods/query.rb | 2 +-
 activerecord/test/cases/finder_test.rb                    | 1 +
 3 files changed, 8 insertions(+), 1 deletion(-)

(limited to 'activerecord')

diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index b4a04e32d7..6f7b2cb108 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,5 +1,11 @@
 ## Rails 4.0.0 (unreleased) ##
 
+*   Attribute predicate methods, such as `article.title?`, will now raise
+    `ActiveModel::MissingAttributeError` if the attribute being queried for
+    truthiness was not read from the database, instead of just returning false.
+
+    *Ernie Miller*
+
 *   `ActiveRecord::SchemaDumper` uses Ruby 1.9 style hash, which means that the
     schema.rb file will be generated using this new syntax from now on.
 
diff --git a/activerecord/lib/active_record/attribute_methods/query.rb b/activerecord/lib/active_record/attribute_methods/query.rb
index 483fd8f4f8..0f9723febb 100644
--- a/activerecord/lib/active_record/attribute_methods/query.rb
+++ b/activerecord/lib/active_record/attribute_methods/query.rb
@@ -8,7 +8,7 @@ module ActiveRecord
       end
 
       def query_attribute(attr_name)
-        value = read_attribute(attr_name)
+        value = read_attribute(attr_name) { |n| missing_attribute(n, caller) }
 
         case value
         when true        then true
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index 20c8e8894d..d44ac21b05 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -276,6 +276,7 @@ class FinderTest < ActiveRecord::TestCase
   def test_find_only_some_columns
     topic = Topic.all.merge!(:select => "author_name").find(1)
     assert_raise(ActiveModel::MissingAttributeError) {topic.title}
+    assert_raise(ActiveModel::MissingAttributeError) {topic.title?}
     assert_nil topic.read_attribute("title")
     assert_equal "David", topic.author_name
     assert !topic.attribute_present?("title")
-- 
cgit v1.2.3