module NormalizeIt::ClassMethods
normalize_it makes it easy to seamlessly manage database tables that have been normalized.
Example:
create_table :customer_statuses, :force => true do |t| t.string :customer_status end create_table :email_addresses, :force => true do |t| t.string :email_address end create_table :customers, :force => true do |t| t.string :name t.integer :customer_status_id t.integer :email_address_id end class CustomerStatus < ActiveRecord::Base normalizes :customers, :with_field => :customer_status validates :customer_status, :presence => true validates_uniqueness_of :customer_status end class EmailAddress < ActiveRecord::Base normalizes :customers, :allow_inserts => true validates :email_address, :presence => true validates_uniqueness_of :email_address end class Customer < ActiveRecord::Base has_normalized :customer_status has_normalized :email_address, :allow_inserts => true end after calling normalizes: * if :allow_inserts is false (default), a :with_field argument must be passed in ** new objects of CustomerStatus may not be created by the app ** CustomerStatus objects may be referenced by [] notation, eg CustomerStatus[:new] or CustomerStatus['new'] ** CustomerStatus is given a has_many association to Customer, has_many options may be passed in to normalizes * if :allow_inserts is true ** only the has_many association is set up ** [] notation may be used only if the :with_field option is passed after calling has_normalized: * if :allow_inserts is false (default) ** customer.customer_status = 'new' will only search for CustomerStatus['new'] and assign it if it is found * if :allow_inserts is true ** customer.email_address = 'x@example.com' will search for the email address, and create it if not found * all columns on the normalized tables are delegated to the parent object. e.g. customer.email_address * static rails-like finders may be used. e.g. Customer.find_by_email_address 'x@example.com' * new objects may be initialized either with attributes or through later assignment. e.g. Customer.new(:email_address => 'x@example.com')
Attributes
_normalized_models[R]
Public Instance Methods
has_normalized(model, options = {})
click to toggle source
# File lib/normalize_it.rb, line 65 def has_normalized(model, options = {}) include NormalizeIt::BaseClassMethods @_normalized_models ||= [] allow_inserts = options.try(:delete, :allow_inserts) || false opts = { :class_name => model.to_s.camelize, :autosave => true, :foreign_key => model.to_s.foreign_key }.merge!(options) belongs_to "__#{opts[:class_name].underscore}".to_sym, opts validates "__#{opts[:class_name].underscore}".to_sym, :presence => true validates_associated "__#{opts[:class_name].underscore}".to_sym @_normalized_models << opts.merge( { :allow_inserts => allow_inserts } ) opts[:class_name].constantize.content_columns.each do |column| next if ['created_at', 'updated_at'].include?(column.name) delegate "#{column.name}", "#{column.name}?", :to => "__#{opts[:class_name].underscore}".to_sym if allow_inserts delegate "#{column.name}=", :to => "__#{opts[:class_name].underscore}".to_sym else self.class_eval do define_method "#{column.name}=" do |value| self.send("__#{opts[:class_name].underscore}=", value.is_a?(opts[:class_name].constantize) ? value : opts[:class_name].constantize[value] ) end end end eval <<-NEWFINDERS def self.find_by_#{column.name} value self.send("find_by_#{opts[:foreign_key]}", #{opts[:class_name]}.send("find_by_#{column.name}", value) ) end def self.find_all_by_#{column.name} value self.send("find_all_by_#{opts[:foreign_key]}", #{opts[:class_name]}.send("find_by_#{column.name}", value) ) end NEWFINDERS end before_validation :handle_normalized_objects if allow_inserts end
normalizes(model, options = {})
click to toggle source
# File lib/normalize_it.rb, line 108 def normalizes(model, options = {}) include NormalizeIt::NormalizedClassMethods allow_inserts = options.try(:delete, :allow_inserts) || false if !allow_inserts normalized_field = options.try(:delete, :with_field) raise NormalizeItException, "Normalized field must be specified on static tables!" unless normalized_field before_create :disallow_create unless allow_inserts if normalized_field eval <<-HASHNOTATIONACCESS def self.[] value @@#{self.name.underscore.pluralize} ||= HashWithIndifferentAccess.new @@#{self.name.underscore.pluralize}[value] ||= find_by_#{normalized_field.to_s}(value.to_s) @@#{self.name.underscore.pluralize}[value] end HASHNOTATIONACCESS end end has_many model, options end