Created
June 29, 2012 03:44
-
-
Save t3hk0d3/3015549 to your computer and use it in GitHub Desktop.
CTI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module ActiveRecord | |
module ClassTableInheritance | |
extend ActiveSupport::Concern | |
module ClassMethods | |
def class_table_inheritance | |
self.send(:include, ActiveRecord::ClassTableInheritance::Implementation) | |
end | |
end | |
module Implementation | |
def self.included(base) | |
base.extend(ClassMethods) | |
end | |
private | |
def create | |
if self.class == self.class.base_class | |
return super | |
end | |
puts "Creating " + self.class.name | |
self.id ||= self.class.cti_insert(arel_attributes_values(!id.nil?)) | |
IdentityMap.add(self) if IdentityMap.enabled? | |
@new_record = false | |
id | |
end | |
module ClassMethods | |
def self.extended(base) | |
base.setup_inheritance | |
end | |
def setup_inheritance | |
@parent_models = [] | |
@models_map = {} | |
klass = self.superclass | |
until klass == ActiveRecord::Base | |
# Save only real models, not STI models | |
if klass.base_class == klass || klass.base_class.table_name != klass.table_name | |
@parent_models << klass | |
@models_map[klass.table_name] = klass | |
end | |
klass = klass.superclass | |
end | |
self.primary_key = compute_foreign_key | |
# self.primary_key = "#{self.base_class.table_name}.#{self.base_class.primary_key}" | |
end | |
def compute_foreign_key | |
"#{self.base_class.to_s.underscore.singularize}_#{self.base_class.primary_key}" | |
end | |
def columns | |
unless defined? @columns_map | |
@columns_map = {} | |
@parent_models.each do |parent| | |
@columns_map[parent.table_name] = parent.columns | |
end | |
@columns_map[table_name] = super | |
@columns = @columns_map.values.flatten.uniq | |
end | |
super | |
end | |
def compute_table_name | |
if parent < ActiveRecord::Base && !parent.abstract_class? | |
contained = parent.table_name | |
contained = contained.singularize if parent.pluralize_table_names | |
contained += '_' | |
end | |
"#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{table_name_suffix}" | |
end | |
def fields_map | |
unless defined? @fields_map | |
# Call to create columns map | |
columns unless defined? @columns_map | |
@fields_map = {} | |
@columns_map.map do |table, columns| | |
columns.each { |column| @fields_map[column.name.to_s.underscore] = table } | |
end | |
end | |
@fields_map | |
end | |
def cti_insert(attributes) | |
class_attrs = {} | |
attributes.map do |attr, value| | |
table = fields_map[attr.name] | |
class_attrs[table] = {} if class_attrs[table].nil? | |
if @models_map.include? table # Fix attribute table | |
attr.relation = @models_map[table].arel_table | |
end | |
class_attrs[table][attr] = value | |
end | |
parent_primary_key = nil | |
# Insert parents data starting base class (to obtain primary key) | |
([self] + @parent_models).reverse.each do |parent| | |
unless class_attrs.include? parent.table_name | |
# no data for this parent table | |
next | |
end | |
data = class_attrs[parent.table_name] | |
if !parent_primary_key.nil? | |
data[parent.arel_table[parent.primary_key]] = parent_primary_key | |
end | |
key = parent.unscoped.insert data | |
if (parent == self.base_class) | |
parent_primary_key = key | |
end | |
end | |
parent_primary_key | |
end | |
protected | |
def expand_hash_conditions_for_aggregates(opts) | |
unless defined? @columns_map | |
return super opts | |
end | |
fixed_opts = {} | |
map = fields_map | |
opts.map do |key, value| | |
key = key.to_s | |
if !key.include?(".") and map.key? key.underscore | |
key = "#{fields_map[key.underscore]}.#{key}" | |
end | |
fixed_opts[key] = value | |
end | |
super fixed_opts | |
end | |
private | |
def relation | |
relation = super | |
relation = relation.select(self.arel_table[Arel.star]) | |
@parent_models.each do |model| | |
foreign_table = model.arel_table | |
relation = relation.joins( | |
foreign_table.create_join(foreign_table, | |
foreign_table.create_on(foreign_table[model.primary_key].eq(self.arel_table[primary_key])) | |
) | |
) | |
relation = relation.select(foreign_table[Arel.star]) | |
end | |
relation | |
end | |
end | |
end | |
end | |
end | |
class ActiveRecord::Base | |
include ActiveRecord::ClassTableInheritance | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment