# Only needs to be an Include module for the generated classes, not for all ARs module ActiveRecord class Base class << self alias old_new new def new(*args) obj = old_new(*args) unless self.methods.include? 'generate_validations' self.send(:include, DrNicMagicModels::Validations) self.generate_validations end obj end alias old_allocate allocate def allocate obj = old_allocate unless self.methods.include? 'generate_validations' self.send(:include, DrNicMagicModels::Validations) self.generate_validations end obj end cattr_accessor :known_unknowns # Returns the AssociationReflection object for the named +aggregation+ (use the symbol). Example: # Account.reflect_on_association(:owner) # returns the owner AssociationReflection # Invoice.reflect_on_association(:line_items).macro # returns :has_many def reflect_on_association(association) puts "Known association? #{association.to_sym.inspect} -> #{reflections[association]}" reflections[association].is_a?(AssociationReflection) ? reflections[association] : nil end def assess_unknown_method(instance, method, *args, &block) result = find_belongs_to instance, method, *args, &block result = find_has_some instance, method, *args, &block if not result result = find_has_some_indirect instance, method, *args, &block if not result result end def add_known_unknown(method) known_unknowns ||= {} known_unknowns[method] = true end def unknown_method?(method) known_unknowns.nil? or known_unknowns.include? method end def find_belongs_to(instance, method, *args, &block) foreign_key = self.columns.select {|column| column.name == method.to_s.foreign_key}.first return add_belongs_to(instance, method, *args, &block) if foreign_key end def add_belongs_to(instance, method, *args, &block) self.send 'belongs_to', method instance.send(method, *args, &block) end def find_has_some(instance, method, *args, &block) klass = Module.const_get method.to_s.downcase.singularize.camelize rescue nil foreign_key = klass.columns.select {|column| column.name == self.name.foreign_key}.first if klass return add_has_some(instance, method, *args, &block) if foreign_key end def add_has_some(instance, method, *args, &block) _method = method.to_s association = _method.singularize == _method ? 'has_one' : 'has_many' self.send association, method instance.send(instance, method, *args, &block) end def find_has_some_indirect(instance, method, *args, &block) klass = Module.const_get method.to_s.downcase.singularize.camelize rescue return join_table = nil self.connection.tables.each do |table| unless [self.table_name, klass.table_name].include? table columns = self.connection.columns(table).map(&:name) join_table = table if columns.include?(self.to_s.foreign_key) and columns.include?(klass.to_s.foreign_key) end break if join_table end return add_has_some_through(instance, join_table, method, *args, &block) if join_table end def add_has_some_through(instance, join_table, method, *args, &block) puts "self.class.send 'has_many', #{method}, :through => #{join_table.inspect}" self.send 'has_many', method, :through => join_table.to_sym instance.send(method, *args, &block) end end class_eval do alias :normal_method_missing :method_missing def method_missing(method, *args, &block) if unknown_method? method self.class.assess_unknown_method(self, method, *args, &block) end add_known_unknown method normal_method_missing(method, *args, &block) end end end end