diff --git a/lib/citier/class_methods.rb b/lib/citier/class_methods.rb index 935e145..6fd8708 100644 --- a/lib/citier/class_methods.rb +++ b/lib/citier/class_methods.rb @@ -2,6 +2,7 @@ module Citier module ClassMethods # any method placed here will apply to classes def acts_as_citier(options = {}) + set_acts_as_citier(true) # Option for setting the inheritance columns, default value = 'type' db_type_field = (options[:db_type_field] || :type).to_s @@ -41,54 +42,6 @@ def acts_as_citier(options = {}) citier_debug("table_name -> #{self.table_name}") - def self.find(*args) #overrides find to get all attributes - # With option :no_children set to true, only records of type self will be returned. - # So Root.all(:no_children => true) won't return Child records. - options = args.last.is_a?(Hash) ? args.last : {} - no_children = options.delete(:no_children) - self_type = self.superclass == ActiveRecord::Base ? nil : self.name - return self.where(:type => self_type).find(*args) if no_children - - tuples = super - - # If the tuple is already of this class's type, we don't need to reload it. - return tuples if tuples.kind_of?(Array) ? tuples.all? { |tuple| tuple.class == self } : (tuples.class == self) - - # In case of multiple tuples, find the correct ones using one query per type. - if tuples.kind_of?(Array) - found_records = [] - ids_wanted = {} - - # Map all the ids wanted per type - tuples.each do |tuple| - if tuple.class == self # We don't need to find the record again if this is already the correct one - found_records << tuple - next - end - - type_ids_wanted = ids_wanted[tuple.class] - type_ids_wanted ||= ids_wanted[tuple.class] = [] - type_ids_wanted << tuple.id - end - - # Find all wanted records - ids_wanted.each do |type, ids| - found_records.push(*type.find(ids)) - end - - # Make a new array with the found records at the right places - tuples.each do |tuple| - found_record = found_records.find { |found| found.id == tuple.id } - tuple.force_attributes(found_record.instance_variable_get(:@attributes), :merge => true, :clear_caches => false) - end - - return tuples - end - - # In case of only one tuple, return it reloaded. - return tuples.reload - end - # Add the functions required for root classes only send :include, Citier::RootInstanceMethods end diff --git a/lib/citier/core_ext.rb b/lib/citier/core_ext.rb index 09cb0a3..8624484 100644 --- a/lib/citier/core_ext.rb +++ b/lib/citier/core_ext.rb @@ -1,4 +1,12 @@ -class ActiveRecord::Base +class ActiveRecord::Base + + def self.set_acts_as_citier(citier) + @acts_as_citier = citier + end + + def self.acts_as_citier? + @acts_as_citier || false + end def self.[](column_name) arel_table[column_name] @@ -7,17 +15,6 @@ def self.[](column_name) def is_new_record(state) @new_record = state end - - # For some reason need to override this so it uses my modified find function which reloads each object to pull in all properties. - def self.all(*args) - return find(:all, *args) - end - def self.first(*args) - return find(:first, *args) - end - def self.last(*args) - return find(:last, *args) - end def self.create_class_writable(class_reference) #creation of a new class which inherits from ActiveRecord::Base Class.new(ActiveRecord::Base) do diff --git a/lib/citier/relation_methods.rb b/lib/citier/relation_methods.rb index 28192df..36422bb 100644 --- a/lib/citier/relation_methods.rb +++ b/lib/citier/relation_methods.rb @@ -3,33 +3,89 @@ class Relation alias_method :relation_delete_all, :delete_all def delete_all(conditions = nil) - if conditions - relation_delete_all(conditions) - else - deleted = true - ids = nil - c = @klass - - bind_values.each do |bind_value| - if bind_value[0].name == "id" - ids = bind_value[1] - break - end + return relation_delete_all(conditions) if !@klass.acts_as_citier? + + return relation_delete_all(conditions) if conditions + + deleted = true + ids = nil + c = @klass + + bind_values.each do |bind_value| + if bind_value[0].name == "id" + ids = bind_value[1] + break end - ids ||= where_values_hash["id"] || where_values_hash[:id] - where_hash = ids ? { :id => ids } : nil - - deleted &= c.base_class.where(where_hash).relation_delete_all - while c.superclass != ActiveRecord::Base - if c.const_defined?(:Writable) - citier_debug("Deleting back up hierarchy #{c}") - deleted &= c::Writable.where(where_hash).delete_all - end - c = c.superclass + end + ids ||= where_values_hash["id"] || where_values_hash[:id] + where_hash = ids ? { :id => ids } : nil + + deleted &= c.base_class.where(where_hash).relation_delete_all + while c.superclass != ActiveRecord::Base + if c.const_defined?(:Writable) + citier_debug("Deleting back up hierarchy #{c}") + deleted &= c::Writable.where(where_hash).delete_all end - deleted + c = c.superclass end + + deleted + end + + alias_method :relation_to_a, :to_a + def to_a + return relation_to_a if !@klass.acts_as_citier? + + records = relation_to_a + + c = @klass + + if records.all? { |record| record.class == c } + return records + end + + full_records = [] + ids_wanted = {} + + # Map all the ids wanted per type + records.each do |record| + if record.class == c # We don't need to find the record again if this is already the correct one + full_records << record + next + end + + ids_wanted[record.class] ||= [] + ids_wanted[record.class] << record.id + end + + # Find all wanted records + ids_wanted.each do |type_class, ids| + full_records.push(*type_class.find(ids)) + end + + # Make a new array with the found records at the right places + records.each do |record| + full_record = full_records.find { |full_record| full_record.id == record.id } + record.force_attributes(full_record.instance_variable_get(:@attributes), :merge => true, :clear_caches => false) + end + + return records + end + + alias_method :relation_apply_finder_options, :apply_finder_options + def apply_finder_options(options) + return relation_apply_finder_options(options) if !@klass.acts_as_citier? + + puts "Using custom apply_finder_options!" + # With option :no_children set to true, only records of type self will be returned. + # So Root.all(:no_children => true) won't return Child records. + no_children = options.delete(:no_children) + if no_children + self_type = self.superclass == ActiveRecord::Base ? nil : self.name + options[:conditions] = (options[:conditions] || {}).merge( :type => self_type ) + end + + relation_apply_finder_options(options) end - end end \ No newline at end of file