aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--activerecord/CHANGELOG2
-rwxr-xr-xactiverecord/lib/active_record/base.rb13
-rwxr-xr-xactiverecord/test/base_test.rb5
3 files changed, 13 insertions, 7 deletions
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index 957f13b7f9..549665f28f 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -1,5 +1,7 @@
*SVN*
+* Define attribute query methods to avoid method_missing calls. #3677 [jonathan@bluewire.net.nz]
+
* ActiveRecord::Base.remove_connection explicitly closes database connections and doesn't corrupt the connection cache. Introducing the disconnect! instance method for the PostgreSQL, MySQL, and SQL Server adapters; implementations for the others are welcome. #3591 [Simon Stapleton, Tom Ward]
* Added support for nested scopes #3407 [anna@wota.jp]. Examples:
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 70c44b838d..88baaecfd3 100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -1544,19 +1544,19 @@ module ActiveRecord #:nodoc:
# table with a master_id foreign key can instantiate master through Client#master.
def method_missing(method_id, *args, &block)
method_name = method_id.to_s
- if @attributes.include?(method_name)
+ if @attributes.include?(method_name) or
+ (md = /\?$/.match(method_name) and
+ @attributes.include?(method_name = md.pre_match))
define_read_methods if self.class.read_methods.empty? && self.class.generate_read_methods
- read_attribute(method_name)
+ md ? query_attribute(method_name) : read_attribute(method_name)
elsif self.class.primary_key.to_s == method_name
id
- elsif md = /(=|\?|_before_type_cast)$/.match(method_name)
+ elsif md = /(=|_before_type_cast)$/.match(method_name)
attribute_name, method_type = md.pre_match, md.to_s
if @attributes.include?(attribute_name)
case method_type
when '='
write_attribute(attribute_name, args.first)
- when '?'
- query_attribute(attribute_name)
when '_before_type_cast'
read_attribute_before_type_cast(attribute_name)
end
@@ -1610,12 +1610,15 @@ module ActiveRecord #:nodoc:
unless attr_name.to_s == self.class.primary_key.to_s
access_code = access_code.insert(0, "raise NoMethodError, 'missing attribute: #{attr_name}', caller unless @attributes.has_key?('#{attr_name}'); ")
self.class.read_methods << attr_name
+ self.class.read_methods << "#{attr_name}?"
end
begin
self.class.class_eval("def #{symbol}; #{access_code}; end")
+ self.class.class_eval("def #{symbol}?; query_attribute('#{attr_name}'); end")
rescue SyntaxError => err
self.class.read_methods.delete(attr_name)
+ self.class.read_methods.delete("#{attr_name}?")
if logger
logger.warn "Exception occured during reader method compilation."
logger.warn "Maybe #{attr_name} is not a valid Ruby identifier?"
diff --git a/activerecord/test/base_test.rb b/activerecord/test/base_test.rb
index 4349d92eeb..4cdf24c03d 100755
--- a/activerecord/test/base_test.rb
+++ b/activerecord/test/base_test.rb
@@ -1163,7 +1163,8 @@ class BasicsTest < Test::Unit::TestCase
private
def assert_readers(model, exceptions)
- expected_readers = model.column_names - (model.serialized_attributes.keys + exceptions + ['id'])
- assert_equal expected_readers.sort, model.read_methods.to_a.sort
+ expected_readers = Set.new(model.column_names - (model.serialized_attributes.keys + exceptions + ['id']))
+ expected_readers += expected_readers.map { |col| "#{col}?" }
+ assert_equal expected_readers, model.read_methods
end
end