airtable_sync 1.0.0
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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +175 -0
- data/Rakefile +18 -0
- data/app/jobs/airtable_sync/create_record_job.rb +21 -0
- data/app/jobs/airtable_sync/destroy_record_job.rb +12 -0
- data/app/jobs/airtable_sync/initial_sync_job.rb +24 -0
- data/app/jobs/airtable_sync/update_record_job.rb +18 -0
- data/app/models/concerns/airtable_sync/callbacks.rb +41 -0
- data/app/models/concerns/airtable_sync/record_sync.rb +40 -0
- data/app/services/airtable_sync/api.rb +32 -0
- data/lib/airtable_sync/configuration.rb +25 -0
- data/lib/airtable_sync/engine.rb +6 -0
- data/lib/airtable_sync/railtie.rb +6 -0
- data/lib/airtable_sync/version.rb +5 -0
- data/lib/airtable_sync.rb +15 -0
- data/lib/generators/airtable_sync/connection_generator.rb +36 -0
- data/lib/generators/airtable_sync/install_generator.rb +13 -0
- data/lib/generators/airtable_sync/templates/airtable_sync.rb +7 -0
- data/lib/generators/airtable_sync/templates/migration.rb.erb +6 -0
- data/lib/tasks/airtable_sync.rake +8 -0
- metadata +108 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8591433d500307558e933d3861df761d6da9434a51628ae0a961410cfc85d552
|
4
|
+
data.tar.gz: ce375ba7fbc498b4e46cc93cb25c824c1e216ee9dd0e46ddd7f15396b2bbbf54
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 73d23e7524abcbcad6b7bbc5a428cd06135fb3344f5ddaf9299b9392bef7f6d93fc1066985b6d57abcf955b08d466f4a765e59ffad16ca7fe04a5a5fa0509f7e
|
7
|
+
data.tar.gz: 408e6f38899dac41d6638da0dba2d1007f94a1b10bb5c7df4fc99f33c77ebdc1d94f0578bf03f5e2b651b5f4ba94d7020b52715f8a3ee0cd05037e6f29f22be0
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2023 Viktor
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
[](https://github.com/vfonic/airtable_sync/actions)
|
2
|
+
|
3
|
+
# AirtableSync
|
4
|
+
|
5
|
+
Keep your Ruby on Rails records in sync with AirTable.
|
6
|
+
|
7
|
+
Currently only one way Rails => AirTable synchronization.
|
8
|
+
|
9
|
+
For the latest changes, see the [CHANGELOG.md](CHANGELOG.md).
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Add this line to your application's Gemfile:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
gem 'airtable_sync'
|
17
|
+
```
|
18
|
+
|
19
|
+
And then execute:
|
20
|
+
|
21
|
+
```bash
|
22
|
+
$ bundle
|
23
|
+
```
|
24
|
+
|
25
|
+
Then run the install generator:
|
26
|
+
|
27
|
+
```bash
|
28
|
+
bundle exec rails generate airtable_sync:install
|
29
|
+
```
|
30
|
+
|
31
|
+
## Usage
|
32
|
+
|
33
|
+
1. Generate AirTable API key
|
34
|
+
https://airtable.com/create/apikey
|
35
|
+
2.
|
36
|
+
|
37
|
+
### Configuration options
|
38
|
+
|
39
|
+
In `config/initializers/airtable_sync.rb` you can specify configuration options:
|
40
|
+
|
41
|
+
1. `api_key`
|
42
|
+
2. `webflow_site_id`
|
43
|
+
3. `skip_airtable_sync` - skip synchronization for different environments.
|
44
|
+
|
45
|
+
Example:
|
46
|
+
|
47
|
+
```rb
|
48
|
+
AirtableSync.configure do |config|
|
49
|
+
config.api_key = ENV.fetch('AIRTABLE_API_KEY')
|
50
|
+
config.skip_airtable_sync = ActiveModel::Type::Boolean.new.cast(ENV.fetch('SKIP_AIRTABLE_SYNC'))
|
51
|
+
end
|
52
|
+
```
|
53
|
+
|
54
|
+
### Add AirtableSync to models
|
55
|
+
|
56
|
+
For each model that you want to sync to AirTable, you need to run the connection generator:
|
57
|
+
|
58
|
+
```bash
|
59
|
+
bundle exec rails generate airtable_sync:connection Article
|
60
|
+
```
|
61
|
+
|
62
|
+
Please note that this _does not_ create the AirTable table. You need to already have it or create it manually.
|
63
|
+
|
64
|
+
### Create AirTable tables
|
65
|
+
|
66
|
+
As mentioned above, you need to create the AirTable tables yourself.
|
67
|
+
|
68
|
+
### Set `airtable_base_id`
|
69
|
+
|
70
|
+
There are couple of ways how you can set the `airtable_base_id` to be used.
|
71
|
+
|
72
|
+
#### Set `airtable_base_id` through configuration
|
73
|
+
|
74
|
+
In `config/initializers/airtable_sync.rb` you can specify `airtable_base_id`:
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
AirtableSync.configure do |config|
|
78
|
+
config.airtable_base_id = ENV.fetch('AIRTABLE_BASE_ID')
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
### Customize fields to synchronize
|
83
|
+
|
84
|
+
By default, AirtableSync calls `#as_airtable_json` on a record to get the fields that it needs to push to AirTable. `#as_airtable_json` simply calls `#as_json` in its default implementation. To change this behavior, you can override `#as_airtable_json` in your model:
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
# app/models/article.rb
|
88
|
+
class Article < ApplicationRecord
|
89
|
+
include AirtableSync::RecordSync
|
90
|
+
|
91
|
+
def as_airtable_json
|
92
|
+
{
|
93
|
+
'Post Title': self.title.capitalize,
|
94
|
+
'Short Description': self.title.parameterize,
|
95
|
+
'Long Description': self.created_at,
|
96
|
+
}
|
97
|
+
end
|
98
|
+
end
|
99
|
+
```
|
100
|
+
|
101
|
+
### Sync a Rails model to different AirTable table
|
102
|
+
|
103
|
+
If AirTable table name does not match the Rails model collection name, you need to specify table name for each `CreateRecordJob`, `DestroyRecordJob`, and `UpdateRecordJob` call. If not specified, model collection name is used as the table name.
|
104
|
+
You also need to replace included `AirtableSync::RecordSync` with custom callbacks that will call appropriate AirtableSync jobs.
|
105
|
+
|
106
|
+
For example:
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
AirtableSync::CreateRecordJob.perform_later(model_name, id, table_name)
|
110
|
+
AirtableSync::UpdateRecordJob.perform_later(model_name, id, table_name)
|
111
|
+
AirtableSync::DestroyRecordJob.perform_later(table_name:, airtable_id:)
|
112
|
+
```
|
113
|
+
|
114
|
+
Where:
|
115
|
+
|
116
|
+
1. `model_name` - Rails model with `airtable_id` column
|
117
|
+
2. `table_name` - AirTable table name (defaults to: `model_name.underscore.pluralize.humanize`)
|
118
|
+
|
119
|
+
For example:
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
AirtableSync::CreateRecordJob.perform_now('articles', 1, 'Stories')
|
123
|
+
```
|
124
|
+
|
125
|
+
Or, if you want to use the default 'articles' table name:
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
AirtableSync::CreateRecordJob.perform_now('articles', 1)
|
129
|
+
```
|
130
|
+
|
131
|
+
### Run the initial sync
|
132
|
+
|
133
|
+
After setting up which models you want to sync to AirTable, you can run the initial sync for each of the models:
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
AirtableSync::InitialSyncJob.perform_later('articles')
|
137
|
+
```
|
138
|
+
|
139
|
+
You can also run this from a Rake task:
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
bundle exec rails "airtable_sync:initial_sync[articles]"
|
143
|
+
```
|
144
|
+
|
145
|
+
Quotes are needed in order for this to work in all shells.
|
146
|
+
|
147
|
+
### Important note
|
148
|
+
|
149
|
+
This gem silently "fails" (does nothing) when `airtable_base_id` or `airtable_id` is `nil`! This is not always desired behavior so be aware of that.
|
150
|
+
|
151
|
+
## Contributing
|
152
|
+
|
153
|
+
PRs welcome!
|
154
|
+
|
155
|
+
To run RuboCop style check and RSpec tests run:
|
156
|
+
|
157
|
+
```sh
|
158
|
+
bundle exec rake
|
159
|
+
```
|
160
|
+
|
161
|
+
To run only RuboCop run:
|
162
|
+
|
163
|
+
```sh
|
164
|
+
bundle exec rails style
|
165
|
+
```
|
166
|
+
|
167
|
+
To run RSpec tests run:
|
168
|
+
|
169
|
+
```sh
|
170
|
+
bundle exec spec
|
171
|
+
```
|
172
|
+
|
173
|
+
## License
|
174
|
+
|
175
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
|
5
|
+
APP_RAKEFILE = File.expand_path('spec/dummy/Rakefile', __dir__)
|
6
|
+
load 'rails/tasks/engine.rake'
|
7
|
+
|
8
|
+
load 'rails/tasks/statistics.rake'
|
9
|
+
|
10
|
+
require 'bundler/gem_tasks'
|
11
|
+
|
12
|
+
require 'stylecheck/rake_tasks' unless Rails.env.production?
|
13
|
+
|
14
|
+
load 'rspec/rails/tasks/rspec.rake'
|
15
|
+
task :default do
|
16
|
+
Rake::Task['style:rubocop:run'].execute
|
17
|
+
Rake::Task['spec'].execute
|
18
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AirtableSync
|
4
|
+
class CreateRecordJob < ApplicationJob
|
5
|
+
# AirTable table name should be in plural form.
|
6
|
+
# 'JobListing'.underscore.pluralize.humanize => "Job listings"
|
7
|
+
# 'job_listing'.underscore.pluralize.humanize => "Job listings"
|
8
|
+
# We can sync Rails model that has different class name than its AirTable table name
|
9
|
+
# model_name => Rails model that has airtable_id column
|
10
|
+
# table_name => AirTable table name
|
11
|
+
# model_name = 'Article'; id = article.id, table_name = 'Posts'
|
12
|
+
def perform(model_name, id, table_name = model_name.underscore.pluralize.humanize)
|
13
|
+
model_class = model_name.underscore.classify.constantize
|
14
|
+
record = model_class.find_by(id:)
|
15
|
+
return if record.blank?
|
16
|
+
return if record.airtable_base_id.blank?
|
17
|
+
|
18
|
+
AirtableSync::Api.new(record.airtable_base_id).create_record(record, table_name)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AirtableSync
|
4
|
+
class DestroyRecordJob < ApplicationJob
|
5
|
+
def perform(table_name:, airtable_base_id:, airtable_id:)
|
6
|
+
return if airtable_base_id.blank?
|
7
|
+
return if airtable_id.blank?
|
8
|
+
|
9
|
+
AirtableSync::Api.new(airtable_base_id).delete_record(table_name, airtable_id)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AirtableSync
|
4
|
+
class InitialSyncJob < ApplicationJob
|
5
|
+
def perform(table_name)
|
6
|
+
model_class = table_name.underscore.classify.constantize
|
7
|
+
model_class.where(airtable_id: nil).find_each do |record|
|
8
|
+
next if record.airtable_base_id.blank?
|
9
|
+
|
10
|
+
client(record.airtable_base_id).create_record(record, table_name)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def client(site_id)
|
17
|
+
if @client&.site_id == site_id
|
18
|
+
@client
|
19
|
+
else
|
20
|
+
@client = AirtableSync::Api.new(site_id)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AirtableSync
|
4
|
+
class UpdateRecordJob < ApplicationJob
|
5
|
+
# AirTable table name should be in plural form.
|
6
|
+
# 'JobListing'.underscore.pluralize.humanize => 'Job listings'
|
7
|
+
# 'job_listing'.underscore.pluralize.humanize => 'Job listings'
|
8
|
+
def perform(model_name, id, table_name = model_name.underscore.pluralize.humanize)
|
9
|
+
model_class = model_name.underscore.classify.constantize
|
10
|
+
record = model_class.find_by(id:)
|
11
|
+
return if record.blank?
|
12
|
+
return if record.airtable_base_id.blank?
|
13
|
+
return AirtableSync::CreateRecordJob.perform_now(model_name, id, table_name) if record.airtable_id.blank?
|
14
|
+
|
15
|
+
AirtableSync::Api.new(record.airtable_base_id).update_record(record, table_name)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Synchronizes any changes to public records to AirTable
|
4
|
+
module AirtableSync
|
5
|
+
module Callbacks
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
attr_accessor :skip_airtable_sync
|
10
|
+
|
11
|
+
after_commit :create_airtable_record, on: :create
|
12
|
+
after_commit :update_airtable_record, on: :update
|
13
|
+
after_commit :destroy_airtable_record, on: :destroy
|
14
|
+
|
15
|
+
def create_airtable_record
|
16
|
+
return if should_skip_sync?
|
17
|
+
|
18
|
+
AirtableSync::CreateRecordJob.perform_later(self.model_name.collection, self.id)
|
19
|
+
end
|
20
|
+
|
21
|
+
def update_airtable_record
|
22
|
+
return if should_skip_sync?
|
23
|
+
|
24
|
+
AirtableSync::UpdateRecordJob.perform_later(self.model_name.collection, self.id)
|
25
|
+
end
|
26
|
+
|
27
|
+
def destroy_airtable_record
|
28
|
+
return if should_skip_sync?
|
29
|
+
|
30
|
+
# Make sure table name is in the plural form
|
31
|
+
table_name = self.model_name.collection.underscore.humanize
|
32
|
+
|
33
|
+
AirtableSync::DestroyRecordJob.perform_later(table_name:, airtable_base_id:, airtable_id:)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def should_skip_sync? = AirtableSync.configuration.skip_airtable_sync || self.skip_airtable_sync || self.airtable_base_id.blank?
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Synchronizes any changes to public records to AirTable
|
4
|
+
module AirtableSync
|
5
|
+
module RecordSync
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
include AirtableSync::Callbacks
|
10
|
+
|
11
|
+
# override this method to get more granular, per site customization
|
12
|
+
# for example, you could have Site model in your codebase:
|
13
|
+
#
|
14
|
+
# class Site < ApplicationRecord
|
15
|
+
# has_many :articles
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# class Article < ApplicationRecord
|
19
|
+
# belongs_to :site
|
20
|
+
#
|
21
|
+
# def airtable_base_id
|
22
|
+
# self.site.airtable_base_id
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
def airtable_base_id = AirtableSync.configuration.airtable_base_id
|
27
|
+
|
28
|
+
# You can customize this to your liking:
|
29
|
+
# def as_airtable_json
|
30
|
+
# {
|
31
|
+
# title: self.title.capitalize,
|
32
|
+
# slug: self.title.parameterize,
|
33
|
+
# published_at: self.created_at,
|
34
|
+
# image: self.image_url
|
35
|
+
# }
|
36
|
+
# end
|
37
|
+
def as_airtable_json = self.as_json
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AirtableSync
|
4
|
+
class Api
|
5
|
+
attr_reader :base_id
|
6
|
+
|
7
|
+
def initialize(base_id)
|
8
|
+
@base_id = base_id
|
9
|
+
end
|
10
|
+
|
11
|
+
def get_all_items(table_name:) = table(table_name).all
|
12
|
+
|
13
|
+
def get_item(table_name, airtable_id) = table(table_name).find(airtable_id)
|
14
|
+
|
15
|
+
def create_record(record, table_name)
|
16
|
+
airtable_record = table(table_name).create(record.as_airtable_json) # rubocop:disable Rails/SaveBang
|
17
|
+
record.update_column(:airtable_id, airtable_record.id) # rubocop:disable Rails/SkipsModelValidations
|
18
|
+
end
|
19
|
+
|
20
|
+
def update_record(record, table_name)
|
21
|
+
airtable_record = table(table_name).find(record.airtable_id)
|
22
|
+
record.as_airtable_json.each { |key, value| airtable_record[key.to_s] = value }
|
23
|
+
airtable_record.save # rubocop:disable Rails/SaveBang
|
24
|
+
end
|
25
|
+
|
26
|
+
def delete_record(table_name, airtable_id) = table(table_name).find(airtable_id).destroy
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def table(table_name) = Airrecord.table(AirtableSync.configuration.api_key, base_id, table_name)
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AirtableSync
|
4
|
+
class << self
|
5
|
+
attr_reader :configuration
|
6
|
+
|
7
|
+
def configure
|
8
|
+
self.configuration ||= Configuration.new
|
9
|
+
|
10
|
+
self.configuration.skip_airtable_sync = !Rails.env.production?
|
11
|
+
|
12
|
+
yield(self.configuration)
|
13
|
+
|
14
|
+
self.configuration.api_key ||= ENV.fetch('AIRTABLE_API_KEY')
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
attr_writer :configuration
|
20
|
+
end
|
21
|
+
|
22
|
+
class Configuration
|
23
|
+
attr_accessor :skip_airtable_sync, :airtable_base_id, :api_key
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'airtable_sync/version'
|
4
|
+
require 'airtable_sync/configuration'
|
5
|
+
require 'airtable_sync/engine'
|
6
|
+
require 'airrecord'
|
7
|
+
|
8
|
+
module AirtableSync
|
9
|
+
end
|
10
|
+
|
11
|
+
module Airrecord
|
12
|
+
class Client
|
13
|
+
def escape(*args) = ERB::Util.url_encode(*args)
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails/generators/active_record'
|
4
|
+
|
5
|
+
module AirtableSync
|
6
|
+
module Generators
|
7
|
+
class ConnectionGenerator < Rails::Generators::NamedBase
|
8
|
+
desc 'Registers ActiveRecord model to sync to AirTable table'
|
9
|
+
|
10
|
+
source_root File.expand_path('templates', __dir__)
|
11
|
+
|
12
|
+
include Rails::Generators::Migration
|
13
|
+
def add_migration
|
14
|
+
migration_template 'migration.rb.erb', "#{migration_path}/add_airtable_id_to_#{table_name}.rb",
|
15
|
+
migration_version:
|
16
|
+
end
|
17
|
+
|
18
|
+
def include_record_sync_in_model_file
|
19
|
+
module_snippet = <<~END_OF_INCLUDE.indent(2)
|
20
|
+
|
21
|
+
include AirtableSync::RecordSync
|
22
|
+
END_OF_INCLUDE
|
23
|
+
|
24
|
+
insert_into_file "app/models/#{name.underscore}.rb", module_snippet, after: / < ApplicationRecord$/
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.next_migration_number(dirname) = ActiveRecord::Generators::Base.next_migration_number(dirname)
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def migration_path = ActiveRecord::Migrator.migrations_paths.first
|
32
|
+
|
33
|
+
def migration_version = "[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AirtableSync
|
4
|
+
module Generators
|
5
|
+
class InstallGenerator < ::Rails::Generators::Base
|
6
|
+
source_root File.expand_path('templates', __dir__)
|
7
|
+
|
8
|
+
def add_config_initializer
|
9
|
+
template 'airtable_sync.rb', 'config/initializers/airtable_sync.rb'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
metadata
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: airtable_sync
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Viktor
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-02-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: airrecord
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rails
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '7.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '7.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: sprockets-rails
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description:
|
56
|
+
email:
|
57
|
+
- viktor.fonic@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- MIT-LICENSE
|
63
|
+
- README.md
|
64
|
+
- Rakefile
|
65
|
+
- app/jobs/airtable_sync/create_record_job.rb
|
66
|
+
- app/jobs/airtable_sync/destroy_record_job.rb
|
67
|
+
- app/jobs/airtable_sync/initial_sync_job.rb
|
68
|
+
- app/jobs/airtable_sync/update_record_job.rb
|
69
|
+
- app/models/concerns/airtable_sync/callbacks.rb
|
70
|
+
- app/models/concerns/airtable_sync/record_sync.rb
|
71
|
+
- app/services/airtable_sync/api.rb
|
72
|
+
- lib/airtable_sync.rb
|
73
|
+
- lib/airtable_sync/configuration.rb
|
74
|
+
- lib/airtable_sync/engine.rb
|
75
|
+
- lib/airtable_sync/railtie.rb
|
76
|
+
- lib/airtable_sync/version.rb
|
77
|
+
- lib/generators/airtable_sync/connection_generator.rb
|
78
|
+
- lib/generators/airtable_sync/install_generator.rb
|
79
|
+
- lib/generators/airtable_sync/templates/airtable_sync.rb
|
80
|
+
- lib/generators/airtable_sync/templates/migration.rb.erb
|
81
|
+
- lib/tasks/airtable_sync.rake
|
82
|
+
homepage: https://github.com/vfonic/airtable_sync
|
83
|
+
licenses:
|
84
|
+
- MIT
|
85
|
+
metadata:
|
86
|
+
homepage_uri: https://github.com/vfonic/airtable_sync
|
87
|
+
source_code_uri: https://github.com/vfonic/airtable_sync
|
88
|
+
rubygems_mfa_required: 'true'
|
89
|
+
post_install_message:
|
90
|
+
rdoc_options: []
|
91
|
+
require_paths:
|
92
|
+
- lib
|
93
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '3.1'
|
98
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
requirements: []
|
104
|
+
rubygems_version: 3.3.26
|
105
|
+
signing_key:
|
106
|
+
specification_version: 4
|
107
|
+
summary: Keep Rails models in sync with AirTable.
|
108
|
+
test_files: []
|