Returns true
if the provided attribute is being cached.
# File lib/active_record/attribute_methods/read.rb, line 29 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 18 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 24 def cached_attributes @cached_attributes ||= columns.select { |c| cacheable_column?(c) }.map { |col| col.name }.to_set end
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.
We are also defining a constant to hold the frozen string of the attribute name. Using a constant means that we do not have to allocate an object on each call to the attribute method. Making it frozen means that it doesn't get duped when used to key the @attributes_cache in read_attribute.
# File lib/active_record/attribute_methods/read.rb, line 50 def define_method_attribute(name) safe_name = name.unpack('h*').first generated_attribute_methods.module_eval " def __temp__#{safe_name} read_attribute(AttrNames::ATTR_#{safe_name}) { |n| missing_attribute(n, caller) } end alias_method #{name.inspect}, :__temp__#{safe_name} undef_method :__temp__#{safe_name} ", __FILE__, __LINE__ + 1 end
# File lib/active_record/attribute_methods/read.rb, line 63 def cacheable_column?(column) if attribute_types_cached_by_default == ATTRIBUTE_TYPES_CACHED_BY_DEFAULT ! serialized_attributes.include? column.name else attribute_types_cached_by_default.include?(column.type) end end