module DattsRight module InstanceMethods def add_dynamic_attribute(name, object_type, value=nil) key = name.to_s.underscore return false if self.class.columns_hash[key] # if key already exists as a normal attribute unless dynamic_attribute?(key) new_dynamic_attribute = dynamic_attributes.new :name => name, :attr_key => key, :object_type => object_type, "#{object_type}_value".to_sym => value @dynamic_attributes_cache[key.to_sym] = new_dynamic_attribute return new_dynamic_attribute end return false end def remove_dynamic_attribute(name) dynamic_attribute = dynamic_attributes.find_by_attr_key(name.to_s) if dynamic_attribute @dynamic_attributes_cache.delete(name.to_sym) dynamic_attribute.destroy end end # Give users access to the cache def dynamic_attribute_details(key) @dynamic_attributes_cache[key] end # Determines if the given attribute is a dynamic attribute. def dynamic_attribute?(attr) !@dynamic_attributes_cache[attr.to_sym].nil? end def update_dynamic_attributes(attributes) # The following transaction covers any possible database side-effects of the # attributes assignment. For example, setting the IDs of a child collection. with_transaction_returning_status do attributes.symbolize_keys.each do |k, v| self.write_dynamic_attribute(k, v) end save end end def update_dynamic_attributes!(attributes) with_transaction_returning_status do attributes.symbolize_keys.each do |k, v| self.write_dynamic_attribute(k, v) end save! end end # Like AR::Base#read_attribute def read_dynamic_attribute(attr_name) attr_name = attr_name.to_s if dynamic_attribute?(attr_name) #puts "Reading #{attr_name}. The whole cache: #{@dynamic_attributes_cache.inspect}" @dynamic_attributes_cache[attr_name.to_sym].value end end # Like AR::Base#write_attribute def write_dynamic_attribute(attr_name, value) #puts "attempting to write: #{attr_name} = #{value}" if dynamic_attribute?(attr_name) #puts "#{attr_name} is a dynamic_attribute" attr_name = attr_name.to_s #puts "Writing @dynamic_attributes_cache[:#{attr_name}].value = #{value}" dynamic_attribute = @dynamic_attributes_cache[attr_name.to_sym] dynamic_attribute.value = value #puts "In write_dynamic_attribute. Full cache: #{@dynamic_attributes_cache.inspect}" return dynamic_attribute.value end end private # Called after validation on update so that dynamic attributes behave # like normal attributes in the fact that the database is not touched # until save is called. def build_dynamic_attributes @dynamic_attributes_cache ||= {} @dynamic_attributes_cache.each do |k, v| v.save #dynamic_attribute = dynamic_attributes.find_by_attr_key(k.to_s) #value_column = "#{v[:object_type]}_value".to_sym #if dynamic_attribute #dynamic_attribute.update_attributes value_column => v[:value], :object_type => v[:object_type] #else ##@dynamic_attributes_cache[k] = dynamic_attributes.create! :name => k, :attr_key => k, value_column => v[:value], :object_type => v[:object_type] #@dynamic_attributes_cache[k].save #end end end def cache_dynamic_attributes @dynamic_attributes_cache = {} dynamic_attributes.each do |dynamic_attribute| @dynamic_attributes_cache[dynamic_attribute.attr_key.to_sym] = dynamic_attribute end @dynamic_attributes_cache end alias :add_datt :add_dynamic_attribute alias :remove_datt :remove_dynamic_attribute alias :read_datt :read_dynamic_attribute alias :write_datt :write_dynamic_attribute alias :datt_details :dynamic_attribute_details alias :update_dynamic_attribute :write_dynamic_attribute end end