Module: ActiveRecord::Attributes::ClassMethods

Defined in:
activerecord/lib/active_record/attributes.rb

Overview

:nodoc:

Instance Method Summary collapse

Instance Method Details

#attribute(name, cast_type, options = {}) ⇒ Object

Defines or overrides a attribute on this model. This allows customization of Active Record's type casting behavior, as well as adding support for user defined types.

name The name of the methods to define attribute methods for, and the column which this will persist to.

cast_type A type object that contains information about how to type cast the value. See the examples section for more information.

Options

The options hash accepts the following options:

default is the default value that the column should use on a new record.

Examples

The type detected by Active Record can be overridden.

# db/schema.rb
create_table :store_listings, force: true do |t|
  t.decimal :price_in_cents
end

# app/models/store_listing.rb
class StoreListing < ActiveRecord::Base
end

store_listing = StoreListing.new(price_in_cents: '10.1')

# before
store_listing.price_in_cents # => BigDecimal.new(10.1)

class StoreListing < ActiveRecord::Base
  attribute :price_in_cents, Type::Integer.new
end

# after
store_listing.price_in_cents # => 10

Users may also define their own custom types, as long as they respond to the methods defined on the value type. The `type_cast` method on your type object will be called with values both from the database, and from your controllers. See `ActiveRecord::Attributes::Type::Value` for the expected API. It is recommended that your type objects inherit from an existing type, or the base value type.

class MoneyType < ActiveRecord::Type::Integer
  def type_cast(value)
    if value.include?('$')
      price_in_dollars = value.gsub(/\$/, '').to_f
      price_in_dollars * 100
    else
      value.to_i
    end
  end
end

class StoreListing < ActiveRecord::Base
  attribute :price_in_cents, MoneyType.new
end

store_listing = StoreListing.new(price_in_cents: '$10.00')
store_listing.price_in_cents # => 1000

80
81
82
83
84
85
86
87
88
89
# File 'activerecord/lib/active_record/attributes.rb', line 80

def attribute(name, cast_type, options = {})
  name = name.to_s
  clear_caches_calculated_from_columns  # Assign a new hash to ensure that subclasses do not share a hash

  self.user_provided_columns = user_provided_columns.merge(name => cast_type)

  if options.key?(:default)
    self.user_provided_defaults = user_provided_defaults.merge(name => options[:default])
  end
end

#columnsObject

Returns an array of column objects for the table associated with this class.


92
93
94
# File 'activerecord/lib/active_record/attributes.rb', line 92

def columns
  @columns ||= add_user_provided_columns(connection.schema_cache.columns(table_name))
end

#columns_hashObject

Returns a hash of column objects for the table associated with this class.


97
98
99
# File 'activerecord/lib/active_record/attributes.rb', line 97

def columns_hash
  @columns_hash ||= Hash[columns.map { |c| [c.name, c] }]
end

#persistable_attribute_namesObject

:nodoc:


101
102
103
# File 'activerecord/lib/active_record/attributes.rb', line 101

def persistable_attribute_names # :nodoc:
  @persistable_attribute_names ||= connection.schema_cache.columns_hash(table_name).keys
end

#reset_column_informationObject

:nodoc:


105
106
107
108
# File 'activerecord/lib/active_record/attributes.rb', line 105

def reset_column_information # :nodoc:
  super
  clear_caches_calculated_from_columns
end