class Syncify::Sync
Attributes
has_and_belongs_to_many_associations[RW]
identified_records[RW]
Public Instance Methods
execute()
click to toggle source
# File lib/syncify/sync.rb, line 18 def execute puts 'Identifying records to sync...' @identified_records = Set[] @has_and_belongs_to_many_associations = {} remote do associations = normalized_associations(association) initial_query.each do |root_record| identify_associated_records(root_record, associations) end end puts "\nIdentified #{identified_records.size} records to sync." callback.call(identified_records) if callback.present? sync_records end
Private Instance Methods
cache_has_and_belongs_to_many_association(record, association, associated_records)
click to toggle source
# File lib/syncify/sync.rb, line 136 def cache_has_and_belongs_to_many_association(record, association, associated_records) has_and_belongs_to_many_associations[record] ||= {} has_and_belongs_to_many_associations[record][association] = Array(associated_records) end
classify_identified_instances()
click to toggle source
# File lib/syncify/sync.rb, line 178 def classify_identified_instances puts "Classifying #{identified_records.size} records for bulk import..." identified_records.each_with_object({}) do |instance, memo| clazz = instance.class class_name = clazz.name memo[class_name] ||= [] memo[class_name] << clone_instance(instance) end end
clone_instance(instance)
click to toggle source
# File lib/syncify/sync.rb, line 189 def clone_instance(instance) clazz = instance.class new_instance = clazz.new instance.attributes.each do |attribute, value| new_instance[attribute.to_s] = value end new_instance end
has_and_belongs_to_many_association?(record, association)
click to toggle source
# File lib/syncify/sync.rb, line 141 def has_and_belongs_to_many_association?(record, association) record.class.reflect_on_association(association).class == ActiveRecord::Reflection::HasAndBelongsToManyReflection end
id_xor_where_present?()
click to toggle source
# File lib/syncify/sync.rb, line 47 def id_xor_where_present? unless id? ^ where? errors.add(:id, 'Please provide either the id argument or the where argument, but not both.') end end
identify_associated_records(root, associations)
click to toggle source
# File lib/syncify/sync.rb, line 62 def identify_associated_records(root, associations) identified_records << root print_status standard_associations = associations.reject(&method(:includes_polymorphic_association)) polymorphic_associations = associations.select(&method(:includes_polymorphic_association)) standard_associations.each do |association| # begin traverse_associations(root.class.eager_load(association).find(root.id), association) # rescue StandardError => e # binding.pry # x = 1231231231 # end end identify_polymorphic_associated_records(root, polymorphic_associations) end
identify_polymorphic_associated_records(root, polymorphic_associations)
click to toggle source
# File lib/syncify/sync.rb, line 81 def identify_polymorphic_associated_records(root, polymorphic_associations) polymorphic_associations.each do |polymorphic_association| property = polymorphic_association.keys.first nested_associations = polymorphic_association[property] referenced_objects = Array.wrap(root.__send__(property)) next if referenced_objects.empty? referenced_objects.each do |referenced_object| # TODO: there's got to be a better way to express this if polymorphic_association.values.first.keys.all? { |key| key.is_a? Class } # TODO: please, Doug. Fix the names!!! associated_types = nested_associations.keys referenced_type = associated_types.find { |type| referenced_object.is_a?(type) } identify_associated_records( referenced_object, normalized_associations(nested_associations[referenced_type]) ) else identify_associated_records(referenced_object, normalized_associations(nested_associations)) end end end end
includes_polymorphic_association(association)
click to toggle source
# File lib/syncify/sync.rb, line 200 def includes_polymorphic_association(association) return false if association.nil? return false if association == {} return true if association.keys.all? { |key| key.is_a? Class } includes_polymorphic_association(association.values.first) end
initial_query()
click to toggle source
# File lib/syncify/sync.rb, line 39 def initial_query if id? klass.where(id: id) else klass.where(where) end end
normalized_associations(association)
click to toggle source
# File lib/syncify/sync.rb, line 208 def normalized_associations(association) Syncify::NormalizeAssociations.run!(association: association) end
print_status()
click to toggle source
# File lib/syncify/sync.rb, line 54 def print_status @identified_records_count ||= identified_records.size if @identified_records_count != identified_records.size puts "Identified #{identified_records.size} records..." @identified_records_count = identified_records.size end end
remote() { || ... }
click to toggle source
# File lib/syncify/sync.rb, line 212 def remote run_in_environment(remote_database) { yield } end
run_in_environment(environment) { || ... }
click to toggle source
# File lib/syncify/sync.rb, line 216 def run_in_environment(environment) initial_config = ActiveRecord::Base.connection_config ActiveRecord::Base.establish_connection environment yield ensure ActiveRecord::Base.establish_connection initial_config end
sync_records()
click to toggle source
# File lib/syncify/sync.rb, line 151 def sync_records ActiveRecord::Base.connection.disable_referential_integrity do classify_identified_instances.each do |class_name, new_instances| puts "Syncing #{new_instances.size} #{class_name} objects" clazz = Object.const_get(class_name) clazz.where(id: new_instances.map(&:id)).delete_all clazz.import(new_instances, validate: false) end has_and_belongs_to_many_associations.each do |record, associations| associations.each do |association, associated_records| # begin local_record = record.class.find(record.id) local_associated_records = associated_records.map do |associated_record| associated_record.class.find(associated_record.id) end local_record.__send__(association) << local_associated_records local_record.save # rescue StandardError => e # binding.pry # x = 123 # end end end end end
through_association?(record, association)
click to toggle source
# File lib/syncify/sync.rb, line 146 def through_association?(record, association) record.class.reflect_on_association(association).class == ActiveRecord::Reflection::ThroughReflection end
traverse_associations(records, associations)
click to toggle source
# File lib/syncify/sync.rb, line 107 def traverse_associations(records, associations) records = Array(records) identified_records.merge records print_status records.each do |record| associations.each do |association, nested_associations| puts "Traversing #{record.class.name}##{association}" if through_association?(record, association) traverse_associations( record.__send__( record.class.reflect_on_association(association).through_reflection.name ), associations ) else associated_records = record.__send__(association) if has_and_belongs_to_many_association?(record, association) cache_has_and_belongs_to_many_association(record, association, associated_records) end traverse_associations(associated_records, nested_associations) end end end end