syncable_models 0.0.11 → 0.0.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +8 -8
  2. data/README.md +1 -1
  3. data/Rakefile +4 -14
  4. data/app/models/syncable_models/sync.rb +22 -0
  5. data/db/migrate/20160225141153_create_syncs.rb +5 -1
  6. data/lib/syncable_models/active_record.rb +20 -7
  7. data/lib/syncable_models/controller.rb +25 -6
  8. data/lib/syncable_models/engine.rb +5 -0
  9. data/lib/syncable_models/importer.rb +54 -23
  10. data/lib/syncable_models/syncable.rb +20 -0
  11. data/lib/syncable_models/version.rb +1 -1
  12. data/lib/syncable_models.rb +1 -0
  13. data/lib/tasks/syncable_models.rake +2 -2
  14. data/spec/controllers/syncable_models/import_api_controller_spec.rb +101 -0
  15. data/{test → spec}/dummy/README.rdoc +0 -0
  16. data/{test → spec}/dummy/Rakefile +0 -0
  17. data/{test → spec}/dummy/app/assets/javascripts/application.js +0 -0
  18. data/{test → spec}/dummy/app/assets/stylesheets/application.css +0 -0
  19. data/{test → spec}/dummy/app/controllers/application_controller.rb +0 -0
  20. data/spec/dummy/app/controllers/import_api_controller.rb +6 -0
  21. data/{test → spec}/dummy/app/helpers/application_helper.rb +0 -0
  22. data/spec/dummy/app/models/project.rb +12 -0
  23. data/spec/dummy/app/models/team.rb +12 -0
  24. data/{test → spec}/dummy/app/views/layouts/application.html.erb +0 -0
  25. data/{test → spec}/dummy/bin/bundle +0 -0
  26. data/{test → spec}/dummy/bin/rails +0 -0
  27. data/{test → spec}/dummy/bin/rake +0 -0
  28. data/{test → spec}/dummy/bin/setup +0 -0
  29. data/{test → spec}/dummy/config/application.rb +7 -1
  30. data/{test → spec}/dummy/config/boot.rb +0 -0
  31. data/{test → spec}/dummy/config/database.yml +0 -0
  32. data/{test → spec}/dummy/config/environment.rb +0 -0
  33. data/{test → spec}/dummy/config/environments/development.rb +0 -0
  34. data/{test → spec}/dummy/config/environments/production.rb +0 -0
  35. data/{test → spec}/dummy/config/environments/test.rb +0 -0
  36. data/{test → spec}/dummy/config/initializers/assets.rb +0 -0
  37. data/{test → spec}/dummy/config/initializers/backtrace_silencers.rb +0 -0
  38. data/{test → spec}/dummy/config/initializers/cookies_serializer.rb +0 -0
  39. data/{test → spec}/dummy/config/initializers/filter_parameter_logging.rb +0 -0
  40. data/{test → spec}/dummy/config/initializers/inflections.rb +0 -0
  41. data/{test → spec}/dummy/config/initializers/mime_types.rb +0 -0
  42. data/{test → spec}/dummy/config/initializers/session_store.rb +0 -0
  43. data/{test → spec}/dummy/config/initializers/wrap_parameters.rb +0 -0
  44. data/{test → spec}/dummy/config/locales/en.yml +0 -0
  45. data/spec/dummy/config/routes.rb +11 -0
  46. data/{test → spec}/dummy/config/secrets.yml +0 -0
  47. data/{test → spec}/dummy/config.ru +0 -0
  48. data/spec/dummy/db/migrate/20160327104327_create_projects.rb +13 -0
  49. data/spec/dummy/db/migrate/20160327111225_create_teams.rb +9 -0
  50. data/spec/dummy/db/migrate/20160327154807_create_syncs.syncable_models.rb +19 -0
  51. data/{test → spec}/dummy/db/schema.rb +23 -2
  52. data/spec/dummy/db/test.sqlite3 +0 -0
  53. data/spec/dummy/log/test.log +819 -0
  54. data/{test → spec}/dummy/public/404.html +0 -0
  55. data/{test → spec}/dummy/public/422.html +0 -0
  56. data/{test → spec}/dummy/public/500.html +0 -0
  57. data/{test → spec}/dummy/public/favicon.ico +0 -0
  58. data/spec/dummy/spec/factories/projects.rb +21 -0
  59. data/spec/dummy/spec/factories/teams.rb +17 -0
  60. data/spec/models/syncable_models/importer/import_spec.rb +104 -0
  61. data/spec/models/syncable_models/sync_spec.rb +106 -0
  62. data/spec/rails_helper.rb +19 -0
  63. data/spec/spec_helper.rb +85 -0
  64. data/{test → spec}/syncable_models_test.rb +0 -0
  65. metadata +106 -80
  66. data/test/dummy/config/routes.rb +0 -4
  67. data/test/dummy/db/test.sqlite3 +0 -0
  68. data/test/dummy/log/test.log +0 -22
  69. data/test/test_helper.rb +0 -21
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- OWEzMmMwODJhOWE0MDNmM2QwMWU3MjA5ZTg5YTU4YTQ5NTkzMjg2NA==
4
+ NmFjMzY5ODRkYmFmOGMwNzdiNWQ4YWFlOTNmZjQ0ZmJmYjg1YTk3MA==
5
5
  data.tar.gz: !binary |-
6
- MDg3OWFmZTVhYTVmNzM1MDI4NmJkYjY5NGI3NjJlZWNkNzA2YjRlYw==
6
+ Mzk4OTVkM2EwNTFiYzI1M2ExYTgwMzMwMjgwOTcwZDFhMmE3MjZmMA==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MjJjOTIxNTVlNzllMDdmYjllNzNiZTA5YzA3ZjE0ZDBlZTkzY2IzOGFkMzM4
10
- MWUwNjdhY2MxYzA1ZTdhMGJjNzY2NmQzM2JlYzZlYmE0OTUwODNhNmQzNjY0
11
- NWE2MGVlOTEyNzVmYzkyOWRhNGE5NWViMjU2YjExZDMwYTIxODM=
9
+ MWQ4ODJiN2UyYjZkY2IzYTEzOWIwZjJkNmEwZTcwYzMxODk1NjQ4NzMzNGEx
10
+ NmYzM2M1MzMwM2IxNmEwMDJjMGE1ZjNhOGMwZDVhMDRlYzkyNDEyOWQ2MWIx
11
+ ZjQwOTgzNTJhMjU1MDU5YjI4MjNkZGY3YjQwNTBkNDY5MGFjZmQ=
12
12
  data.tar.gz: !binary |-
13
- MzE5MDRhNjIzOTI4NDU5YjZlMTBkZDliNWZjZWYxNzM0ZmU3NThhOTQ5YjJl
14
- Yjc3Zjk2ZjAwZjM3ZDZmYzE2YmZkMzMxMDJjNGE0ZTQ4YWYxM2I5ZTUzYmIz
15
- YjYwYWNjNWZlYjJkNjMwM2MxNzUxMjE0OTA5M2JkNzZjZTlhOTU=
13
+ Y2I2OGNkNzNlMDExMTEyNGRkYWRlNzVmNjVkOTVmMGIwMDkxYjZiNzdiM2Mx
14
+ YzI5ZWU1MzQ1ZDUzMzQ3OThjMmE1NDkyY2Y1MjgwYzY5NzdiZjAyMTg5Y2Q1
15
+ MjRmYWJlYWRmN2FmOGM5Mjg2YzllODRhZjliNDU0Yjg0ZTk3MmY=
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # SyncableModels [![Build Status](https://travis-ci.org/flant/syncable_models.svg?branch=master)](https://travis-ci.org/flant/syncable_model)
1
+ # SyncableModels [![Build Status](https://travis-ci.org/flant/syncable_models.svg?branch=master)](https://travis-ci.org/flant/syncable_models) [![Gem Version](https://badge.fury.io/rb/syncable_models.svg)](https://badge.fury.io/rb/syncable_models)
2
2
 
3
3
  This gem helps you to:
4
4
 
data/Rakefile CHANGED
@@ -4,23 +4,13 @@ rescue LoadError
4
4
  puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
5
  end
6
6
 
7
- require 'rdoc/task'
7
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
8
8
 
9
- APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
10
9
  load 'rails/tasks/engine.rake'
11
-
12
-
13
10
  load 'rails/tasks/statistics.rake'
14
11
 
15
- Bundler::GemHelper.install_tasks
16
-
17
- require 'rake/testtask'
12
+ RSpec::Core::RakeTask.new(:spec)
18
13
 
19
- Rake::TestTask.new(:test) do |t|
20
- t.libs << 'lib'
21
- t.libs << 'test'
22
- t.pattern = 'test/**/*_test.rb'
23
- t.verbose = false
24
- end
14
+ task :default => :spec
25
15
 
26
- task default: :test
16
+ Bundler::GemHelper.install_tasks
@@ -7,5 +7,27 @@ module SyncableModels
7
7
  validates :subject, :subject_type, :destination, presence: true
8
8
 
9
9
  scope :by_destination, ->(*d) { where(destination: d) }
10
+ scope :for_destroying, ->{ where(subject_destroyed: true) }
11
+
12
+ before_save do
13
+ self.subject_external_id = subject.syncable_models_external_id
14
+ end
15
+
16
+ def subject
17
+ super || begin
18
+ subject_klass = subject_type.constantize
19
+ subject_klass.where(subject_klass.syncable_models_id_key => subject_external_id).first
20
+ end
21
+ end
22
+
23
+ def sync_destruction!
24
+ if subject
25
+ self.subject = subject
26
+ self.subject_destroyed = false
27
+ save!
28
+ else
29
+ destroy
30
+ end
31
+ end
10
32
  end
11
33
  end
@@ -3,12 +3,16 @@ class CreateSyncs < ActiveRecord::Migration
3
3
  create_table :syncs do |t|
4
4
  t.integer :subject_id
5
5
  t.string :subject_type
6
- t.string :destination
6
+ t.string :destination, null: false
7
+
8
+ t.string :subject_external_id, null: false
9
+ t.boolean :subject_destroyed, null: false, default: false
7
10
 
8
11
  t.timestamps
9
12
  end
10
13
 
11
14
  add_index :syncs, [:subject_id, :subject_type, :destination]
12
15
  add_index :syncs, :destination
16
+ add_index :syncs, [:subject_external_id, :subject_destroyed]
13
17
  end
14
18
  end
@@ -2,9 +2,14 @@ module SyncableModels::ActiveRecord
2
2
  extend ActiveSupport::Concern
3
3
 
4
4
  included do
5
- has_many :syncs, as: :subject, inverse_of: :subject, class_name: ::SyncableModels::Sync
5
+ has_many :syncs,
6
+ as: :subject,
7
+ inverse_of: :subject,
8
+ class_name: ::SyncableModels::Sync,
9
+ dependent: :nullify
6
10
 
7
11
  after_update :clear_syncs_on_update
12
+ after_destroy :set_syncs_destroyed
8
13
 
9
14
  scope :synced, ->(d){ joins(:syncs).where(syncs: { destination: d }) }
10
15
  scope :not_synced, ->(d) do
@@ -19,23 +24,31 @@ module SyncableModels::ActiveRecord
19
24
  end
20
25
 
21
26
  def synced?(destination)
22
- self.syncs.where(destination: destination).exists?
27
+ syncs.where(destination: destination).exists?
23
28
  end
24
29
 
25
30
  def sync(destination)
26
- self.syncs.create(destination: destination) unless self.synced?(destination)
31
+ syncs.create(destination: destination) unless synced?(destination)
27
32
  end
28
33
 
29
34
  def clear_syncs(destination = nil)
30
- syncs = destination ? self.syncs.by_destination(destination) : self.syncs
31
- syncs.destroy_all
35
+ (destination ? syncs.by_destination(destination) : syncs).destroy_all
36
+ end
37
+
38
+ def syncable_models_external_id
39
+ self.send(self.class.syncable_models_id_key)
32
40
  end
33
41
 
34
42
  def clear_syncs_on_update
35
- self.clear_syncs
43
+ clear_syncs
44
+ end
45
+
46
+ def set_syncs_destroyed
47
+ SyncableModels::Sync.where(subject_external_id: self.syncable_models_external_id)
48
+ .update_all(subject_destroyed: true)
36
49
  end
37
50
 
38
51
  def to_import_hash
39
- self.attributes
52
+ attributes
40
53
  end
41
54
  end
@@ -4,7 +4,7 @@ module SyncableModels::Controller
4
4
  BATCH_COUNT = 50
5
5
 
6
6
  module ClassMethods
7
- def sync_for(subject, class_name: nil, sync_method: nil, fetch_method: nil)
7
+ def sync_for(subject, id_key: :uuid, class_name: nil, sync_method: nil, fetch_method: nil)
8
8
  klass = class_name || subject.to_s.singularize.camelize
9
9
  klass = klass.constantize unless klass.is_a?(Class)
10
10
 
@@ -13,7 +13,7 @@ module SyncableModels::Controller
13
13
 
14
14
  class_eval """
15
15
  def #{sync_method}
16
- set_synced #{klass.name}
16
+ set_synced #{klass.name}, :#{id_key.to_s}
17
17
  end
18
18
 
19
19
  def #{fetch_method}
@@ -31,16 +31,35 @@ module SyncableModels::Controller
31
31
  def fetch(klass)
32
32
  if params[:destination]
33
33
  count = params[:count].present? ? params[:count].to_i : BATCH_COUNT
34
- result = klass.not_synced(params[:destination]).limit(count).map(&:to_import_hash)
35
- render json: { status: 200, objects: result }
34
+
35
+ for_sync = klass.not_synced(params[:destination]).limit(count).map(&:to_import_hash)
36
+ count = count - for_sync.count
37
+ for_destroy = SyncableModels::Sync
38
+ .by_destination(params[:destination])
39
+ .for_destroying
40
+ .limit(count)
41
+ .map(&:subject_external_id)
42
+
43
+ render json: { status: 200, for_sync: for_sync, for_destroy: for_destroy }
36
44
  else
37
45
  render_argument_error
38
46
  end
39
47
  end
40
48
 
41
- def set_synced(klass, id_key = :uuid)
49
+ def set_synced(klass, id_key)
42
50
  if params[:ids] && params[:destination]
43
- klass.where(id_key => params[:ids]).sync(params[:destination])
51
+ ids = params[:ids]
52
+
53
+ destruction_syncs = SyncableModels::Sync
54
+ .by_destination(params[:destination])
55
+ .for_destroying
56
+ .where(subject_external_id: ids)
57
+
58
+ destruction_sync_ids = destruction_syncs.pluck(:subject_external_id).map(&:to_s)
59
+ destruction_syncs.each{ |s| s.sync_destruction! }
60
+ ids -= destruction_sync_ids
61
+
62
+ klass.where(id_key => ids).sync(params[:destination])
44
63
  render json: { status: 200 }
45
64
  else
46
65
  render_argument_error
@@ -1,5 +1,10 @@
1
1
  module SyncableModels
2
2
  class Engine < ::Rails::Engine
3
3
  isolate_namespace SyncableModels
4
+
5
+ config.generators do |g|
6
+ g.test_framework :rspec
7
+ g.fixture_replacement :factory_girl, :dir => 'spec/factories'
8
+ end
4
9
  end
5
10
  end
@@ -36,45 +36,76 @@ module SyncableModels
36
36
  end
37
37
 
38
38
  def import(model_names=[])
39
+ model_names = [model_names] unless model_names.is_a?(Array)
40
+ model_names.map!(&:to_s)
39
41
  selected_models = model_names.any? ?
40
42
  @models.select{ |k, v| k.in? model_names } :
41
43
  @models
42
44
 
43
45
  selected_models.each do |model_name, params|
44
46
  puts "[SyncableModels::Importer] Importing #{model_name.underscore.pluralize}..."
45
- next if model_names.any? && !model_name.in?(model_names)
46
47
 
47
- fetch_url = self.api_url + params[:fetch_path]
48
- sync_url = self.api_url + params[:sync_path]
48
+ next if model_names.any? && !model_name.in?(model_names)
49
49
 
50
- conn = Faraday.new(url: fetch_url)
51
- response = conn.get '', params_with_api_key(destination: destination)
50
+ response = fetch_request(params)
52
51
 
53
52
  if response.success?
54
53
  response = JSON.parse(response.body)
55
-
56
54
  if response["status"].to_i == 401
57
55
  puts "[SyncableModels::Importer] Wrong api key!"
58
56
  end
59
57
 
60
- if response['objects'] && response['objects'].count > 0
61
- klass = model_name.constantize
62
- synced_ids = []
63
-
64
- response['objects'].each do |o|
65
- id = o[params[:id_key].to_s]
66
- result = klass.from_import_hash(o)
67
- puts "[SyncableModels::Importer] Importing #{model_name} (id=#{id}): #{ result ? 'OK' : 'FAIL' }"
68
- synced_ids << id if result
69
- end
70
-
71
- if synced_ids.any?
72
- conn = Faraday.new(url: sync_url)
73
- response = conn.get '', params_with_api_key(destination: self.destination, ids: synced_ids)
74
- end
75
- end
58
+ synced_ids = []
59
+
60
+ synced_ids += sync_update model_name, params, response['for_sync']
61
+ synced_ids += sync_destroy model_name, response['for_destroy']
62
+
63
+ sync_request(params, synced_ids) if synced_ids.any?
64
+ end
65
+ end
66
+ end
67
+
68
+ def fetch_request(params)
69
+ conn = Faraday.new(url: api_url + params[:fetch_path])
70
+ conn.get '', params_with_api_key(destination: destination)
71
+ end
72
+
73
+ def sync_request(params, ids)
74
+ conn = Faraday.new(url: api_url + params[:sync_path])
75
+ conn.get '', params_with_api_key(destination: destination, ids: ids)
76
+ end
77
+
78
+ def sync_update(model_name, params, objects)
79
+ synced_ids = []
80
+
81
+ if objects
82
+ klass = model_name.constantize
83
+
84
+ objects.each do |o|
85
+ id = o[params[:id_key].to_s]
86
+ result = klass.from_import_hash(o)
87
+ puts "[SyncableModels::Importer] Importing #{model_name} (external_id=#{id}): #{ result ? 'OK' : 'FAIL' }"
88
+ synced_ids << id if result
89
+ end
90
+ end
91
+
92
+ synced_ids
93
+ end
94
+
95
+ def sync_destroy(model_name, ids)
96
+ synced_ids = []
97
+
98
+ if ids
99
+ klass = model_name.constantize
100
+
101
+ ids.each do |id|
102
+ result = klass.where(external_id: id).first.try(:destroy)
103
+ puts "[SyncableModels::Importer] Destroying #{model_name} (external_id=#{id}): #{ result ? 'OK' : 'FAIL' }"
104
+ synced_ids << id if result
76
105
  end
77
106
  end
107
+
108
+ synced_ids
78
109
  end
79
110
  end
80
111
 
@@ -96,7 +127,7 @@ module SyncableModels
96
127
  end
97
128
 
98
129
  def self.import_all
99
- @@imports.each &:import
130
+ @@imports.each(&:import)
100
131
  end
101
132
  end
102
133
  end
@@ -0,0 +1,20 @@
1
+ require 'active_support'
2
+
3
+ module SyncableModels
4
+ module Syncable
5
+ def syncable(options = {})
6
+ options.assert_valid_keys(
7
+ :id_key
8
+ )
9
+
10
+ class_attribute :syncable_models_id_key
11
+ self.syncable_models_id_key = options[:id_key] || :uuid
12
+
13
+ include SyncableModels::ActiveRecord
14
+ end
15
+ end
16
+ end
17
+
18
+ ActiveSupport.on_load :active_record do
19
+ ActiveRecord::Base.send :extend, SyncableModels::Syncable
20
+ end
@@ -1,3 +1,3 @@
1
1
  module SyncableModels
2
- VERSION = "0.0.11"
2
+ VERSION = "0.0.12"
3
3
  end
@@ -1,4 +1,5 @@
1
1
  require "syncable_models/engine"
2
+ require "syncable_models/syncable"
2
3
  require "syncable_models/active_record"
3
4
  require "syncable_models/controller"
4
5
  require "syncable_models/importer"
@@ -1,8 +1,8 @@
1
- # desc "Explaining what the task does"
1
+ require 'rake'
2
2
 
3
3
  def prepare_models(models)
4
4
  return unless models
5
- models.split(',').map(&:camelize)
5
+ models.gsub(/\s*/, '').split(',').map(&:camelize)
6
6
  end
7
7
 
8
8
  namespace :syncable_models do
@@ -0,0 +1,101 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe ImportApiController, type: :controller do
4
+ let(:json) { JSON.parse(response.body) }
5
+ let(:for_sync) { json['for_sync'] }
6
+ let(:for_destroy) { json['for_destroy'] }
7
+
8
+ describe '#fetch method' do
9
+ before do
10
+ @teams = [create(:first_team),
11
+ create(:second_team),
12
+ create(:third_team),
13
+ create(:fourth_team)]
14
+ end
15
+
16
+ it 'fetches objects if all unsynced' do
17
+ get :teams, destination: :test
18
+ expect(for_sync.count).to eq(4)
19
+ end
20
+
21
+ it 'fetches only unisynced objects' do
22
+ @teams.last.sync(:test)
23
+ get :teams, destination: :test
24
+ expect(for_sync.count).to eq(3)
25
+ end
26
+
27
+ describe 'fetching mixed response' do
28
+ before do
29
+ @teams.last(2).each{ |t| t.sync(:test) }
30
+ @teams.last(2).each(&:destroy)
31
+ end
32
+
33
+ it 'fetches destroyed syncs' do
34
+ get :teams, destination: :test
35
+ expect(for_destroy.count).to eq(2)
36
+ end
37
+
38
+ it 'response still has undestroyed syncs' do
39
+ get :teams, destination: :test
40
+ expect(for_sync.count).to eq(2)
41
+ end
42
+
43
+ describe 'when using limit' do
44
+ it 'returns correct amount of for_sync objects' do
45
+ get :teams, destination: :test, count: 3
46
+ expect(for_sync.count).to eq(2)
47
+ end
48
+
49
+ it 'returns correct amount of for_destroy objects' do
50
+ get :teams, destination: :test, count: 3
51
+ expect(for_destroy.count).to eq(1)
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ describe '#sync method' do
58
+ it 'syncs objects' do
59
+ teams = [create(:first_team), create(:second_team), create(:third_team)]
60
+ get :sync_teams, destination: :test, ids: teams.first(2).map(&:id)
61
+ expect(Team.synced(:test)).to eq(teams.first(2))
62
+ end
63
+
64
+ describe 'when objects destroyed' do
65
+ describe 'and they are non-permanent' do
66
+ before do
67
+ @teams = [create(:first_team), create(:second_team), create(:third_team)]
68
+ @teams.each{ |o| o.sync(:test) }
69
+ @teams.first(2).each(&:destroy)
70
+ get :sync_teams, destination: :test, ids: @teams.first(2).map(&:id)
71
+ end
72
+
73
+ it 'destroys their syncs' do
74
+ expect(SyncableModels::Sync.count).to eq(1)
75
+ end
76
+
77
+ it 'keeps the remaining syncs' do
78
+ expect(SyncableModels::Sync.first.subject).to eq(@teams.last)
79
+ end
80
+ end
81
+
82
+ describe 'and they are permanent' do
83
+ before do
84
+ @projects = [create(:first_project), create(:second_project), create(:third_project)]
85
+ @projects.each{ |o| o.sync(:test) }
86
+ @projects.first(2).each(&:destroy)
87
+ get :sync_projects, destination: :test, ids: @projects.first(2).map(&:uuid)
88
+ @projects.each(&:reload)
89
+ end
90
+
91
+ it 'doesn\'t destroy their syncs' do
92
+ expect(SyncableModels::Sync.count).to eq(3)
93
+ end
94
+
95
+ it 'makes syncs of destroyed object with correct subject_destroyed attribute' do
96
+ expect(@projects.first(2).map(&:syncs).flatten.compact.map(&:subject_destroyed)).to eq([false, false])
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
File without changes
File without changes
@@ -0,0 +1,6 @@
1
+ class ImportApiController < ActionController::Base
2
+ include SyncableModels::Controller
3
+
4
+ sync_for :projects
5
+ sync_for :teams, id_key: :id
6
+ end
@@ -0,0 +1,12 @@
1
+ class Project < ActiveRecord::Base
2
+ syncable
3
+
4
+ validates :name, :uuid, presence: true
5
+
6
+ def self.from_import_hash(hash)
7
+ object = Project.where(external_id: hash['uuid']).first || Project.new(uuid: SecureRandom.uuid, external_id: hash['uuid'])
8
+ object.name = hash['name']
9
+ object.external_id = hash['uuid']
10
+ object.save
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ class Team < ActiveRecord::Base
2
+ syncable id_key: :id
3
+
4
+ validates :name, presence: true
5
+
6
+ def self.from_import_hash(hash)
7
+ object = Team.where(external_id: hash['id']).first || Team.new
8
+ object.name = hash['name']
9
+ object.external_id = hash['id']
10
+ object.save
11
+ end
12
+ end
File without changes
File without changes
File without changes
File without changes
@@ -1,6 +1,12 @@
1
1
  require File.expand_path('../boot', __FILE__)
2
2
 
3
- require 'rails/all'
3
+ # Pick the frameworks you want:
4
+ require "active_record/railtie"
5
+ require "action_controller/railtie"
6
+ require "action_mailer/railtie"
7
+ require "action_view/railtie"
8
+ require "sprockets/railtie"
9
+ # require "rails/test_unit/railtie"
4
10
 
5
11
  Bundler.require(*Rails.groups)
6
12
  require "syncable_models"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,11 @@
1
+ Rails.application.routes.draw do
2
+
3
+ namespace 'import_api' do
4
+ get 'projects'
5
+ get 'sync_projects'
6
+ get 'teams'
7
+ get 'sync_teams'
8
+ end
9
+
10
+ mount SyncableModels::Engine => "/syncable_models"
11
+ end
File without changes
File without changes
@@ -0,0 +1,13 @@
1
+ class CreateProjects < ActiveRecord::Migration
2
+ def change
3
+ create_table :projects do |t|
4
+ t.string :name, null: false
5
+ t.string :uuid, null: false
6
+ t.datetime :deleted_at, null: true
7
+ t.string :external_id
8
+ t.timestamps null: false
9
+ end
10
+
11
+ add_index :projects, :uuid, unique: true, length: 36
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ class CreateTeams < ActiveRecord::Migration
2
+ def change
3
+ create_table :teams do |t|
4
+ t.string :name, null:false
5
+ t.string :external_id
6
+ t.timestamps null: false
7
+ end
8
+ end
9
+ end