module SugarCRM; module AttributeMethods
module ClassMethods
# Returns a hash of the module fields from the module
def attributes_from_module_fields
fields = {}.with_indifferent_access
self._module.fields.keys.sort.each do |k|
fields[k.to_s] = nil
end
fields
end
end
# Determines if attributes have been changed
def changed?
@modified_attributes.length > 0
end
# Is this a new record?
def new?
@id.blank?
end
# Converts the attributes hash into format recognizable by Sugar
# { :last_name => "Smith"}
# becomes
# { :last_name => {:name => "last_name", :value => "Smith"}}
def serialize_attributes
attr_hash = {}
@attributes.each_pair do |name,value|
attr_hash[name] = serialize_attribute(name,value)
end
attr_hash[:id] = serialize_id unless new?
attr_hash
end
# Converts the modified_attributes hash into format recognizable by Sugar
# { :last_name => {:old => "Smit", :new => "Smith"}}
# becomes
# { :last_name => {:name => "last_name", :value => "Smith"}}
def serialize_modified_attributes
attr_hash = {}
@modified_attributes.each_pair do |name,hash|
attr_hash[name] = serialize_attribute(name,hash[:new])
end
attr_hash[:id] = serialize_id unless new?
attr_hash
end
# Checks to see if we have all the neccessary attributes
def valid?
valid = true
self.class._module.required_fields.each do |attribute|
case attr_type_for(attribute)
when "bool"
case @attributes[attribute]
when TrueClass:
next
when FalseClass:
next
else
@errors.add "#{attribute} must be true or false"
valid = false
end
else
if @attributes[attribute].blank?
@errors.add "#{attribute} cannot be blank"
valid = false
end
end
end
valid
end
# List the required attributes for save
def required_attributes
self.class._module.required_fields
end
# Serializes the id
def serialize_id
{:name => "id", :value => @id.to_s}
end
# Un-typecasts the attribute - false becomes 0
def serialize_attribute(name,value)
attr_value = value
case attr_type_for(name)
when "bool"
attr_value = 0
attr_value = 1 if value
end
{:name => name, :value => attr_value}
end
# Generates get/set methods for keys in the attributes hash
def define_attribute_methods
return if attribute_methods_generated?
@attributes.each_pair do |k,v|
self.class.module_eval %Q?
def #{k}
read_attribute :#{k}
end
def #{k}=(value)
write_attribute :#{k},value
end
?
end
self.class.attribute_methods_generated = true
end
# Returns an #inspect-like string for the value of the
# attribute +attr_name+. String attributes are elided after 50
# characters, and Date and Time attributes are returned in the
# :db format. Other attributes return the value of
# #inspect without modification.
#
# person = Person.create!(:name => "David Heinemeier Hansson " * 3)
#
# person.attribute_for_inspect(:name)
# # => '"David Heinemeier Hansson David Heinemeier Hansson D..."'
#
# person.attribute_for_inspect(:created_at)
# # => '"2009-01-12 04:48:57"'
def attribute_for_inspect(attr_name)
value = read_attribute(attr_name)
if value.is_a?(String) && value.length > 50
"#{value[0..50]}...".inspect
elsif value.is_a?(Date) || value.is_a?(Time)
%("#{value.to_s(:db)}")
else
value.inspect
end
end
protected
# Returns the attribute type for a given attribute
def attr_type_for(attribute)
field = self.class._module.fields[attribute]
return false unless field
field["type"]
end
# Attempts to typecast each attribute based on the module field type
def typecast_attributes
@attributes.each_pair do |name,value|
attr_type = attr_type_for(name)
next unless attr_type
case attr_type
when "bool"
@attributes[name] = (value == "1")
end
end
@attributes
end
# Wrapper around attributes hash
def read_attribute(key)
@attributes[key]
end
# Wrapper around attributes hash
def write_attribute(key, value)
@modified_attributes[key] = { :old => @attributes[key].to_s, :new => value }
@attributes[key] = value
end
end; end