Module: Base::ClassMethods

Defined in:
lib/activerecord/base/class_methods.rb

Instance Method Summary collapse

Instance Method Details

#has_tableless(column) ⇒ Object

Macro to attach a tableless model to a parent, table-based model. The parent model is expected to own a property/column having as name the first argument (or the key if the argument is a hash )

Can be used this way:

class Parent < ActiveRecord::Base

  has_tableless :settings

  # or...

  has_tableless :settings => ParentSettings

end

NOTE: the serialized column is expected to be of type string or text in the database



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/activerecord/base/class_methods.rb', line 25

def has_tableless(column)
  column_name = column.class == Hash ? column.collect{|k,v| k}.first.to_sym : column
  
  # if only the column name is given, the tableless model's class is expected to have that name, classified, as class name
  class_type = column.class == Hash ? column.collect{|k,v| v}.last : column.to_s.classify.constantize


  # injecting in the parent object a getter and a setter for the
  # attribute that will store an instance of a tableless model
  class_eval do

    # Telling AR that the column has to store an instance of the given tableless model in 
    # YAML serialized format
    serialize column_name, ActiveRecord::TablelessModel

    # Adding getter for the serialized column,
    # making sure it always returns an instance of the specified tableless
    # model and not just a normal hash or the value of the attribute in the database,
    # which is plain text
    define_method column_name.to_s do
      instance = class_type.new(read_attribute(column_name.to_sym) || {})
      
      instance.__owner_object         = self
      instance.__serialized_attribute = column_name
      
      instance
    end

    # Adding setter for the serialized column,
    # making sure it always stores in it an instance of 
    # the specified tableless model (as the argument may also be a regular hash)
    define_method "#{column_name.to_s}=" do |value|
      super class_type.new(value)
    end
  end
end