Module: CastAttribute

Defined in:
lib/cast_attribute.rb

Overview

CastAttribute is an extension to ActiveRecord for casting attributes to different types. For example, let’s say you have a model called Product, and some of your products have Japanese characters in their names, so you want to use your UnicodeString class with your Product model. You can do this with CastAttribute like so:

class Product < ActiveRecord::Base
  cast_attribute :name, :as => UnicodeString
end

Now the name attribute on your Product model will be an instance of UnicodeString:

>> Product.first.name.class
=> UnicodeString

Caveats

CastAttribute will not install itself into ActiveRecord::Base unless explicitly instructed to:

CastAttribute.install!

CastAttribute defines accessor methods for the attributes you want to cast. (I.e., in the example above, cast_attribute defines two instance methods in Product: name and name=.) If you want to add any functionality to a cast attribute’s accessors, you must use method chaining. Sorry.

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object

:nodoc:



37
38
39
# File 'lib/cast_attribute.rb', line 37

def self.included(base) # :nodoc:
  base.extend(self)
end

.install!Object

Installs CastAttribute into ActiveRecord::Base.



31
32
33
34
35
# File 'lib/cast_attribute.rb', line 31

def self.install!
  ActiveRecord::Base.class_eval do
    include CastAttribute
  end
end

Instance Method Details

#cast_attribute(name, *options) ⇒ Object

Causes the values of the attribute specified by name to be instances of the class specified in the :as key of options. For example, to make the title attribute of a Book model use UnicodeString instead of the regular String:

class Book < ActiveRecord::Base
  cast_attribute :title, :as => UnicodeString
end

You can cast more than one attribute at a time like so:

class Book < ActiveRecord::Base
  cast_attribute :title, :summary, :as => UnicodeString
end


56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/cast_attribute.rb', line 56

def cast_attribute(name, *options)
  # Extract and check arguments.
  names = [name] + options
  options = names.pop
  
  unless options.is_a?(Hash)
    raise TypeError, 'last argument must be a Hash'
  end
  if names.empty?
    raise ArgumentError, 'no attribute names specified'
  end
  
  klass = options.delete(:as)
  
  unless options.empty?
    raise ArgumentError, "unknown key(s): `#{options.keys.join("', `")}'"
  end
  unless klass.is_a?(Class)
    raise TypeError, 'value of :as option must be a Class'
  end
  
  # Create attribute reader and writer methods.
  names.each do |name|
    unless columns_hash[name.to_s]
      raise ArgumentError, "#{self} has no `#{name}' attribute"
    end
    
    class_eval <<-EOS
      def #{name}
        @cast_attribute_#{name} ||= #{klass}.new(read_attribute(:#{name}))
      end
      
      def #{name}=(value)
        @cast_attribute_#{name} = nil
        super
      end
    EOS
  end
end