syncable_models 0.0.11 → 0.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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