module ActiveRecord::AttributeMethods::Read::ClassMethods

Public Instance Methods

cache_attribute?(attr_name) click to toggle source

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(*attribute_names) click to toggle source

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
cached_attributes() click to toggle source

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

Protected Instance Methods

define_method_attribute(name) click to toggle source

We want to generate the methods via module_eval rather than define_method, because define_method is slower on dispatch. Evaluating many similar methods may use more memory as the instruction sequences are duplicated and cached (in MRI). define_method may be slower on dispatch, but if you're careful about the closure created, then define_method will consume much less memory.

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 53
        def define_method_attribute(name)
          safe_name = name.unpack('h*').first
          generated_attribute_methods::AttrNames.set_name_cache safe_name, name

          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

Private Instance Methods

cacheable_column?(column) click to toggle source
# File lib/active_record/attribute_methods/read.rb, line 68
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