module ActiveRecord::AttributeMethods::Read::ClassMethods
Public Instance Methods
Returns true
if the provided attribute is being cached.
# File lib/active_record/attribute_methods/read.rb, line 28 def cache_attribute?(attr_name) cached_attributes.include?(attr_name) end
cache_attributes
allows you to declare which converted
attribute values should be cached. Usually caching only pays off for
attributes with expensive conversion methods, like time related columns
(e.g. created_at
, updated_at
).
# File lib/active_record/attribute_methods/read.rb, line 17 def cache_attributes(*attribute_names) cached_attributes.merge attribute_names.map { |attr| attr.to_s } end
Returns the attributes which are cached. By default time related columns
with datatype :datetime, :timestamp, :time, :date
are cached.
# File lib/active_record/attribute_methods/read.rb, line 23 def cached_attributes @cached_attributes ||= columns.select { |c| cacheable_column?(c) }.map { |col| col.name }.to_set end
# File lib/active_record/attribute_methods/read.rb, line 32 def undefine_attribute_methods generated_external_attribute_methods.module_eval do instance_methods.each { |m| undef_method(m) } end super end
Protected Instance Methods
We want to generate the methods via module_eval rather than define_method, because define_method is slower on dispatch and uses more memory (because it creates a closure).
But sometimes the database might return columns with characters that are not allowed in normal method names (like 'my_column(omg)'. So to work around this we first define with the __temp__ identifier, and then use alias method to rename it to what we want.
# File lib/active_record/attribute_methods/read.rb, line 69 def define_method_attribute(attr_name) generated_attribute_methods.module_eval " def __temp__ #{internal_attribute_access_code(attr_name, attribute_cast_code(attr_name))} end alias_method '#{attr_name}', :__temp__ undef_method :__temp__ ", __FILE__, __LINE__ + 1 end
Private Instance Methods
# File lib/active_record/attribute_methods/read.rb, line 119 def attribute_cast_code(attr_name) columns_hash[attr_name].type_cast_code('v') end
# File lib/active_record/attribute_methods/read.rb, line 91 def cacheable_column?(column) attribute_types_cached_by_default.include?(column.type) end
# File lib/active_record/attribute_methods/read.rb, line 81 def define_external_attribute_method(attr_name) generated_external_attribute_methods.module_eval " def __temp__(v, attributes, attributes_cache, attr_name) #{external_attribute_access_code(attr_name, attribute_cast_code(attr_name))} end alias_method '#{attr_name}', :__temp__ undef_method :__temp__ ", __FILE__, __LINE__ + 1 end
# File lib/active_record/attribute_methods/read.rb, line 109 def external_attribute_access_code(attr_name, cast_code) access_code = "v && #{cast_code}" if cache_attribute?(attr_name) access_code = "attributes_cache[attr_name] ||= (#{access_code})" end access_code end
# File lib/active_record/attribute_methods/read.rb, line 95 def internal_attribute_access_code(attr_name, cast_code) access_code = "(v=@attributes[attr_name]) && #{cast_code}" unless attr_name == primary_key access_code.insert(0, "missing_attribute(attr_name, caller) unless @attributes.has_key?(attr_name); ") end if cache_attribute?(attr_name) access_code = "@attributes_cache[attr_name] ||= (#{access_code})" end "attr_name = '#{attr_name}'; #{access_code}" end