From fafe7f3421b8f929739684b889f8d6cc93b32b52 Mon Sep 17 00:00:00 2001 From: Thorsten Eckel Date: Wed, 8 Mar 2017 16:02:56 +0100 Subject: [PATCH] Added generic resource import logic to provide base classes containing the generic core logic for importing single resources. Direct import from remote objects to local models is possible by using Import::ModelResource. --- lib/import/base_resource.rb | 84 ++++++++++++++++++++++++++++++ lib/import/model_resource.rb | 18 +++++++ spec/import/base_resource_spec.rb | 10 ++++ spec/import/model_resource_spec.rb | 35 +++++++++++++ 4 files changed, 147 insertions(+) create mode 100644 lib/import/base_resource.rb create mode 100644 lib/import/model_resource.rb create mode 100644 spec/import/base_resource_spec.rb create mode 100644 spec/import/model_resource_spec.rb diff --git a/lib/import/base_resource.rb b/lib/import/base_resource.rb new file mode 100644 index 000000000..ebb8d6283 --- /dev/null +++ b/lib/import/base_resource.rb @@ -0,0 +1,84 @@ +module Import + class BaseResource + include Import::Helper + + def initialize(resource) + import(resource) + end + + def import_class + raise "#{self.class.name} has no implmentation of the needed 'import_class' method" + end + + private + + def import(resource) + create_or_update(map(resource)) + end + + def create_or_update(resource) + return if updated?(resource) + create(resource) + end + + def updated?(resource) + @resource = lookup_existing(resource) + return false if !@resource + @resource.update_attributes(resource) + post_update( + instance: @resource, + attributes: resource + ) + true + end + + def lookup_existing(resource) + import_class.find_by(name: resource[:name]) + end + + def create(resource) + @resource = import_class.new(resource) + @resource.save + post_create( + instance: @resource, + attributes: resource + ) + end + + def defaults(_resource) + { + created_by_id: 1, + updated_by_id: 1, + } + end + + def map(resource) + mapped = from_mapping(resource) + attributes = defaults(resource).merge(mapped) + attributes.deep_symbolize_keys + end + + def from_mapping(resource) + return resource if !mapping + + ExternalSync.map( + mapping: mapping, + source: resource + ) + end + + def mapping + Setting.get(mapping_config) + end + + def mapping_config + self.class.name.to_s.sub('Import::', '').gsub('::', '_').underscore + '_mapping' + end + + def post_create(_args) + end + + def post_update(_args) + end + end +end diff --git a/lib/import/model_resource.rb b/lib/import/model_resource.rb new file mode 100644 index 000000000..3c3c23398 --- /dev/null +++ b/lib/import/model_resource.rb @@ -0,0 +1,18 @@ +module Import + class ModelResource < Import::BaseResource + + def import_class + model_name.constantize + end + + def model_name + @model_name ||= self.class.name.split('::').last + end + + private + + def post_create(_args) + reset_primary_key_sequence(model_name.underscore.pluralize) + end + end +end diff --git a/spec/import/base_resource_spec.rb b/spec/import/base_resource_spec.rb new file mode 100644 index 000000000..13a79d4aa --- /dev/null +++ b/spec/import/base_resource_spec.rb @@ -0,0 +1,10 @@ +require 'rails_helper' + +RSpec.describe Import::BaseResource do + + it "needs an implementation of the 'import_class' method" do + expect { + described_class.new(attributes_for(:group)) + }.to raise_error(RuntimeError) + end +end diff --git a/spec/import/model_resource_spec.rb b/spec/import/model_resource_spec.rb new file mode 100644 index 000000000..005ba864c --- /dev/null +++ b/spec/import/model_resource_spec.rb @@ -0,0 +1,35 @@ +require 'rails_helper' + +RSpec.describe Import::ModelResource do + + before do + module Import + module Test + class Group < Import::ModelResource + end + end + end + end + + it 'creates model Objects by class name' do + + group_data = attributes_for(:group) + + expect { + Import::Test::Group.new(group_data) + }.to change { Group.count }.by(1) + end + + it 'updates model Objects by class name' do + + group = create(:group) + + update_attributes = group.serializable_hash + update_attributes[:note] = 'Updated' + + expect { + Import::Test::Group.new(update_attributes) + group.reload + }.to change { group.note } + end +end