123456789_123456789_123456789_123456789_123456789_

Module: ActiveRecord::Store

Relationships & Source Files
Namespace Children
Modules:
Classes:
Extension / Inclusion / Inheritance Descendants
Included In:
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
Defined in: activerecord/lib/active_record/store.rb

Overview

Store gives you a thin wrapper around serialize for the purpose of storing hashes in a single column. It’s like a simple key/value store baked into your record when you don’t care about being able to query that store outside the context of a single record.

You can then declare accessors to this store that are then accessible just like any other attribute of the model. This is very helpful for easily exposing store keys to a form or elsewhere that’s already built around just accessing attributes on the model.

Every accessor comes with dirty tracking methods (key_changed?, key_was and key_change) and methods to access the changes made during the last save (saved_change_to_key?, saved_change_to_key and key_before_last_save).

NOTE: There is no key_will_change! method for accessors, use store_will_change! instead.

Make sure that you declare the database column used for the serialized store as a text, so there’s plenty of room.

You can set custom coder to encode/decode your serialized attributes to/from different formats. JSON, YAML, Marshal are supported out of the box. Generally it can be any wrapper that provides load and dump.

NOTE: If you are using structured database data types (e.g. PostgreSQL hstore+/+json, MySQL 5.7+ json, or SQLite 3.38+ json) there is no need for the serialization provided by .store. Simply use .store_accessor instead to generate the accessor methods. Be aware that these columns use a string keyed hash and do not allow access using a symbol.

NOTE: The default validations with the exception of uniqueness will work. For example, if you want to check for uniqueness with hstore you will need to use a custom validation to handle it.

Examples:

class User < ActiveRecord::Base
  store :settings, accessors: [ :color, :homepage ], coder: JSON
  store :parent, accessors: [ :name ], coder: JSON, prefix: true
  store :spouse, accessors: [ :name ], coder: JSON, prefix: :partner
  store :settings, accessors: [ :two_factor_auth ], suffix: true
  store :settings, accessors: [ : ], suffix: :config
end

u = User.new(color: 'black', homepage: '37signals.com', parent_name: 'Mary', partner_name: 'Lily')
u.color                          # Accessor stored attribute
u.parent_name                    # Accessor stored attribute with prefix
u.partner_name                   # Accessor stored attribute with custom prefix
u.two_factor_auth_settings       # Accessor stored attribute with suffix
u.             # Accessor stored attribute with custom suffix
u.settings[:country] = 'Denmark' # Any attribute, even if not specified with an accessor

# There is no difference between strings and symbols for accessing custom attributes
u.settings[:country]  # => 'Denmark'
u.settings['country'] # => 'Denmark'

# Dirty tracking
u.color = 'green'
u.color_changed? # => true
u.color_was # => 'black'
u.color_change # => ['black', 'green']

# Add additional accessors to an existing store through store_accessor
class SuperUser < User
  store_accessor :settings, :privileges, :servants
  store_accessor :parent, :birthday, prefix: true
  store_accessor :settings, :secret_question, suffix: :config
end

The stored attribute names can be retrieved using .stored_attributes.

User.stored_attributes[:settings] # => [:color, :homepage, :two_factor_auth, :login_retry]

Overwriting default accessors

All stored values are automatically available through accessors on the Active Record object, but sometimes you want to specialize this behavior. This can be done by overwriting the default accessors (using the same name as the attribute) and calling super to actually change things.

class Song < ActiveRecord::Base
  # Uses a stored integer to hold the volume adjustment of the song
  store :settings, accessors: [:volume_adjustment]

  def volume_adjustment=(decibels)
    super(decibels.to_i)
  end

  def volume_adjustment
    super.to_i
  end
end

Class Method Summary

::ActiveSupport::Concern - Extended

class_methods

Define class methods from given block.

included

Evaluate given block in context of base class, so that you can write class macros here.

prepended

Evaluate given block in context of base class, so that you can write class macros here.

append_features, prepend_features

Instance Method Summary

DSL Calls

included

[ GitHub ]


99
100
101
102
103
# File 'activerecord/lib/active_record/store.rb', line 99

included do
  class << self
    attr_accessor :local_stored_attributes
  end
end

Instance Method Details

#read_store_attribute(store_attribute, key) (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/store.rb', line 209

def read_store_attribute(store_attribute, key) # :doc:
  accessor = store_accessor_for(store_attribute)
  accessor.read(self, store_attribute, key)
end

#store_accessor_for(store_attribute) (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/store.rb', line 219

def store_accessor_for(store_attribute)
  type_for_attribute(store_attribute).tap do |type|
    unless type.respond_to?(:accessor)
      raise ConfigurationError, "the column '#{store_attribute}' has not been configured as a store. Please make sure the column is declared serializable via 'ActiveRecord.store' or, if your database supports it, use a structured column type like hstore or json."
    end
  end.accessor
end

#write_store_attribute(store_attribute, key, value) (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/store.rb', line 214

def write_store_attribute(store_attribute, key, value) # :doc:
  accessor = store_accessor_for(store_attribute)
  accessor.write(self, store_attribute, key, value)
end