Module: NormalizeIt::ClassMethods
- Defined in:
- lib/normalize_it.rb
Overview
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 = '[email protected]' 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 '[email protected]'
* new objects may be initialized either with attributes or through later assignment. e.g. Customer.new(:email_address => '[email protected]')
Instance Attribute Summary collapse
-
#_normalized_models ⇒ Object
readonly
Returns the value of attribute _normalized_models.
Instance Method Summary collapse
Instance Attribute Details
#_normalized_models ⇒ Object (readonly)
Returns the value of attribute _normalized_models.
63 64 65 |
# File 'lib/normalize_it.rb', line 63 def _normalized_models @_normalized_models end |
Instance Method Details
#has_normalized(model, options = {}) ⇒ Object
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 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/normalize_it.rb', line 65 def has_normalized(model, = {}) include NormalizeIt::BaseClassMethods @_normalized_models ||= [] allow_inserts = .try(:delete, :allow_inserts) || false opts = { :class_name => model.to_s.camelize, :autosave => true, :foreign_key => model.to_s.foreign_key }.merge!() 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 = {}) ⇒ Object
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/normalize_it.rb', line 108 def normalizes(model, = {}) include NormalizeIt::NormalizedClassMethods allow_inserts = .try(:delete, :allow_inserts) || false if !allow_inserts normalized_field = .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, end |