app_rail-airtable 0.3.6 → 0.4.1
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 +4 -4
- data/CHANGELOG.md +9 -0
- data/Gemfile +7 -5
- data/Gemfile.lock +19 -33
- data/README.md +39 -5
- data/Rakefile +5 -3
- data/app_rail-airtable.gemspec +22 -18
- data/bin/ara_generator +4 -2
- data/bin/console +4 -3
- data/examples/schemas/daily_logs.json +86 -0
- data/examples/schemas/locations.json +85 -0
- data/examples/schemas/users.json +51 -0
- data/lib/app_rail/airtable/application_record.rb +24 -21
- data/lib/app_rail/airtable/authenticatable.rb +31 -18
- data/lib/app_rail/airtable/authentication_helpers.rb +10 -7
- data/lib/app_rail/airtable/generator.rb +17 -2
- data/lib/app_rail/airtable/sinatra.rb +37 -25
- data/lib/app_rail/airtable/string_ext.rb +4 -2
- data/lib/app_rail/airtable/version.rb +3 -1
- data/lib/app_rail/airtable.rb +9 -7
- data/templates/project/Gemfile +2 -1
- data/templates/project/config.ru +2 -0
- data/templates/project/lib/server.rb.tt +6 -0
- data/templates/project/spec/server_spec.rb.tt +34 -0
- data/templates/project/spec/spec_helper.rb +56 -56
- metadata +40 -9
- data/templates/project/Gemfile.lock +0 -96
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 635c1b4e200ee31f032f974ca3da84df53b766825c10ac3d4c867ac5b1533c2b
|
|
4
|
+
data.tar.gz: 5949f7165d856d5bfab33fb42cf157b859346651c5b927aa548b098841a5f5a5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 352a2c5566fa8b24966d8ce524a6d9b8fc0ebc91b3559b79d0bff16fd9c5436a9bbe6a0893084f15c4fbdd071382da25b455e7b915a271a5a45fcf8c11f9f5c6
|
|
7
|
+
data.tar.gz: 2febff28b74cf2b538b6d8767fc308946d48f7e75bff35991d8e30e4ac29a6794e21d75d37e213ef51a3d9dcf791a078c4890ec62fd931904d7199f74fd54d69
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# 0.4.0
|
|
2
|
+
|
|
3
|
+
### Breaking changes
|
|
4
|
+
* `AppRail::Airtable::Sinatra` `.resources` and `.authenticable_resources` `only` argument defaults to `[:index, :show, :create, :update]` instead of `[:index, :show, :create]`
|
|
5
|
+
|
|
6
|
+
### New features
|
|
7
|
+
* Add `Authenticatable#initialize` method to initialize an Airrecord record without persisting it to airtable
|
|
8
|
+
* Add `update` route (`PUT`), which points to the corresponding model method `self.update_as_json`
|
|
9
|
+
|
data/Gemfile
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
source 'https://rubygems.org'
|
|
2
4
|
|
|
3
5
|
# Specify your gem's dependencies in app_rail-airtable.gemspec
|
|
4
6
|
gemspec
|
|
5
7
|
|
|
6
|
-
gem
|
|
7
|
-
gem
|
|
8
|
-
gem
|
|
9
|
-
gem
|
|
8
|
+
gem 'byebug'
|
|
9
|
+
gem 'rake', '~> 12.0'
|
|
10
|
+
gem 'rspec', '~> 3.0'
|
|
11
|
+
gem 'thor'
|
data/Gemfile.lock
CHANGED
|
@@ -1,62 +1,48 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
app_rail-airtable (0.
|
|
4
|
+
app_rail-airtable (0.4.1)
|
|
5
5
|
activesupport
|
|
6
6
|
airrecord
|
|
7
7
|
bcrypt
|
|
8
|
+
faraday (~> 2.2)
|
|
9
|
+
faraday-net_http_persistent (~> 2.0)
|
|
8
10
|
sinatra
|
|
9
11
|
thor
|
|
10
12
|
|
|
11
13
|
GEM
|
|
12
14
|
remote: https://rubygems.org/
|
|
13
15
|
specs:
|
|
14
|
-
activesupport (7.0.2.
|
|
16
|
+
activesupport (7.0.2.3)
|
|
15
17
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
16
18
|
i18n (>= 1.6, < 2)
|
|
17
19
|
minitest (>= 5.1)
|
|
18
20
|
tzinfo (~> 2.0)
|
|
19
|
-
airrecord (1.0.
|
|
20
|
-
faraday (>= 0.10, <
|
|
21
|
+
airrecord (1.0.9)
|
|
22
|
+
faraday (>= 0.10, < 3.0)
|
|
23
|
+
faraday-net_http_persistent
|
|
21
24
|
net-http-persistent
|
|
22
|
-
bcrypt (3.1.
|
|
25
|
+
bcrypt (3.1.17)
|
|
23
26
|
byebug (11.1.3)
|
|
24
|
-
concurrent-ruby (1.1.
|
|
27
|
+
concurrent-ruby (1.1.10)
|
|
25
28
|
connection_pool (2.2.5)
|
|
26
29
|
diff-lcs (1.4.4)
|
|
27
|
-
faraday (
|
|
28
|
-
faraday-
|
|
29
|
-
faraday-em_synchrony (~> 1.0)
|
|
30
|
-
faraday-excon (~> 1.1)
|
|
31
|
-
faraday-httpclient (~> 1.0)
|
|
32
|
-
faraday-multipart (~> 1.0)
|
|
33
|
-
faraday-net_http (~> 1.0)
|
|
34
|
-
faraday-net_http_persistent (~> 1.0)
|
|
35
|
-
faraday-patron (~> 1.0)
|
|
36
|
-
faraday-rack (~> 1.0)
|
|
37
|
-
faraday-retry (~> 1.0)
|
|
30
|
+
faraday (2.2.0)
|
|
31
|
+
faraday-net_http (~> 2.0)
|
|
38
32
|
ruby2_keywords (>= 0.0.4)
|
|
39
|
-
faraday-
|
|
40
|
-
faraday-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
multipart-post (>= 1.2, < 3)
|
|
45
|
-
faraday-net_http (1.0.1)
|
|
46
|
-
faraday-net_http_persistent (1.2.0)
|
|
47
|
-
faraday-patron (1.0.0)
|
|
48
|
-
faraday-rack (1.0.0)
|
|
49
|
-
faraday-retry (1.0.3)
|
|
50
|
-
i18n (1.9.1)
|
|
33
|
+
faraday-net_http (2.0.2)
|
|
34
|
+
faraday-net_http_persistent (2.0.1)
|
|
35
|
+
faraday-net_http
|
|
36
|
+
net-http-persistent (~> 4.0)
|
|
37
|
+
i18n (1.10.0)
|
|
51
38
|
concurrent-ruby (~> 1.0)
|
|
52
39
|
minitest (5.15.0)
|
|
53
|
-
multipart-post (2.1.1)
|
|
54
40
|
mustermann (1.1.1)
|
|
55
41
|
ruby2_keywords (~> 0.0.1)
|
|
56
42
|
net-http-persistent (4.0.1)
|
|
57
43
|
connection_pool (~> 2.2)
|
|
58
44
|
rack (2.2.3)
|
|
59
|
-
rack-protection (2.
|
|
45
|
+
rack-protection (2.2.0)
|
|
60
46
|
rack
|
|
61
47
|
rack-test (1.1.0)
|
|
62
48
|
rack (>= 1.0, < 3)
|
|
@@ -75,10 +61,10 @@ GEM
|
|
|
75
61
|
rspec-support (~> 3.10.0)
|
|
76
62
|
rspec-support (3.10.2)
|
|
77
63
|
ruby2_keywords (0.0.5)
|
|
78
|
-
sinatra (2.
|
|
64
|
+
sinatra (2.2.0)
|
|
79
65
|
mustermann (~> 1.0)
|
|
80
66
|
rack (~> 2.2)
|
|
81
|
-
rack-protection (= 2.
|
|
67
|
+
rack-protection (= 2.2.0)
|
|
82
68
|
tilt (~> 2.0)
|
|
83
69
|
thor (1.1.0)
|
|
84
70
|
tilt (2.0.10)
|
data/README.md
CHANGED
|
@@ -2,10 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
App Rail Airtable is a micro-framework based on Sinatra and [Airrecord](https://github.com/sirupsen/airrecord) which faciliates use of Airtable as a backend for App Rail Apps. You can deploy a template repo to Heroku for fast start.
|
|
4
4
|
|
|
5
|
-
## Quick Start
|
|
6
|
-
|
|
7
|
-
Visit [App Rail Airtable Template](https://github.com/FutureWorkshops/AppRailAirtableTemplate) and follow instructions.
|
|
8
|
-
|
|
9
5
|
## Installation
|
|
10
6
|
|
|
11
7
|
Add this line to your application's Gemfile:
|
|
@@ -16,7 +12,7 @@ gem 'app_rail-airtable'
|
|
|
16
12
|
|
|
17
13
|
## Usage
|
|
18
14
|
|
|
19
|
-
App Rail Airtable has two important concepts, models and servers.
|
|
15
|
+
App Rail Airtable has two important concepts, models and servers.
|
|
20
16
|
|
|
21
17
|
### Models
|
|
22
18
|
App Rail Airtable makes the following assumptions
|
|
@@ -32,6 +28,7 @@ To provide support for routes, models can implement
|
|
|
32
28
|
* ar_list_item (index)
|
|
33
29
|
* ar_stack (show)
|
|
34
30
|
* self.create_as_json (create)
|
|
31
|
+
* self.update_as_json (update)
|
|
35
32
|
|
|
36
33
|
In order to support authentication you should create a class (normally `User`) and inherit from `AppRail::Airtable::AuthenticationRecord`. Your table needs `Email`, `Password Hash` and `Access Token` columns.
|
|
37
34
|
|
|
@@ -45,10 +42,47 @@ Creates routes that map to a table. It delegates from the route to a model metho
|
|
|
45
42
|
* `index` to `ar_list_item`
|
|
46
43
|
* `show` to `ar_stack`
|
|
47
44
|
* `create` to `self.create_as_json`
|
|
45
|
+
* `update` to `self.update_as_json`
|
|
48
46
|
|
|
49
47
|
**authenticable_resources(name, , only:)**
|
|
50
48
|
Acts as `resources` but also takes a block of routes. Those nested routes will all call the `authenticate!` helper method before running. The `authenticate!` helper will call a lookup helper `find_authenticatable_resource(access_token:)` with the bearer token found in the `HTTP_AUTHORIZATION` header, which should be used to look up the correct object or return nil if none is found (resulting in a 401 response).
|
|
51
49
|
|
|
50
|
+
### Generator
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
bin/ara_generator <output_directory> <airtable_api_key> <airtable_base_id> [<json_schema>]
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
#### Example
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
bin/ara_generator ./test key1234567890 appwertyuiop '{"tables": [{"name": "DailyLogs", "fields": [{"name": "Date", "type": "date"}, {"name": "Score", "type": "integer"}], "associations": [{"name": "User", "type": "belongs_to", "model": "User"}], "ar_class_methods": [{"name": "ar_list_item", "properties": [{"type": "text", "value": "date"}, {"type": "detail_text", "value": "score"}]}], "ar_instance_methods": [{"name": "ar_stack_item", "properties": [{"type": "text", "label": "Date", "value": "date"}, {"type": "button", "label": "Score", "value": "score", "modalWorkflow": "", "style": "primary", "onSuccess": "forward", "sfSymbolName": ""}]}]}, {"name": "Users", "fields": [{"name": "Email", "type": "string"}, {"name": "Password Hash", "type": "string"}, {"name": "Access Token", "type": "string"}], "associations": [{"name": "DailyLogs", "type": "has_many", "model": "DailyLog"}], "authenticatable": "True"}]}'
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
You can find more examples of schemas in [/examples/schemas](/examples/schemas)
|
|
63
|
+
|
|
64
|
+
## Debugging
|
|
65
|
+
|
|
66
|
+
### Listing Existing Routes
|
|
67
|
+
To get a complete list of the available routes in your Sinatra application, run the following code snippet:
|
|
68
|
+
```ruby
|
|
69
|
+
Server.routes.map do |method, routes|
|
|
70
|
+
routes.map { |r| r.first.to_s }.map do |route|
|
|
71
|
+
"#{method.rjust(7, ' ')} #{route}"
|
|
72
|
+
end
|
|
73
|
+
end.flatten.sort.each do |route|
|
|
74
|
+
puts route
|
|
75
|
+
end
|
|
76
|
+
```
|
|
77
|
+
Output:
|
|
78
|
+
```
|
|
79
|
+
GET /mock_items
|
|
80
|
+
GET /mock_items/:id
|
|
81
|
+
PUT /mock_items/:id
|
|
82
|
+
HEAD /mock_items
|
|
83
|
+
HEAD /mock_items/:id
|
|
84
|
+
POST /mock_items
|
|
85
|
+
```
|
|
52
86
|
## License
|
|
53
87
|
|
|
54
88
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
CHANGED
data/app_rail-airtable.gemspec
CHANGED
|
@@ -1,35 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require_relative 'lib/app_rail/airtable/version'
|
|
2
4
|
|
|
3
5
|
Gem::Specification.new do |spec|
|
|
4
|
-
spec.name =
|
|
6
|
+
spec.name = 'app_rail-airtable'
|
|
5
7
|
spec.version = AppRail::Airtable::VERSION
|
|
6
|
-
spec.authors = [
|
|
7
|
-
spec.email = [
|
|
8
|
+
spec.authors = ['Matt Brooke-Smith']
|
|
9
|
+
spec.email = ['matt@futureworkshops.com']
|
|
8
10
|
|
|
9
|
-
spec.summary =
|
|
10
|
-
spec.homepage =
|
|
11
|
-
spec.license =
|
|
12
|
-
spec.required_ruby_version = Gem::Requirement.new(
|
|
11
|
+
spec.summary = 'Gem to help building App Rail servers using Airtable as a backend'
|
|
12
|
+
spec.homepage = 'https://github.com/FutureWorkshops/app_rail-airtable'
|
|
13
|
+
spec.license = 'MIT'
|
|
14
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
|
|
13
15
|
|
|
14
|
-
spec.metadata[
|
|
15
|
-
spec.metadata[
|
|
16
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
|
17
|
+
spec.metadata['source_code_uri'] = 'https://github.com/FutureWorkshops/app_rail-airtable'
|
|
16
18
|
|
|
17
19
|
# Specify which files should be added to the gem when it is released.
|
|
18
20
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
19
|
-
spec.files
|
|
21
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
20
22
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
21
23
|
end
|
|
22
|
-
|
|
24
|
+
|
|
23
25
|
spec.bindir = 'bin'
|
|
24
26
|
spec.executables << 'ara_generator'
|
|
25
|
-
|
|
26
|
-
spec.require_paths = [
|
|
27
|
+
|
|
28
|
+
spec.require_paths = ['lib']
|
|
27
29
|
spec.add_dependency 'activesupport'
|
|
28
|
-
spec.add_dependency 'sinatra'
|
|
29
30
|
spec.add_dependency 'airrecord'
|
|
30
|
-
spec.add_dependency 'thor'
|
|
31
31
|
spec.add_dependency 'bcrypt'
|
|
32
|
-
|
|
33
|
-
spec.
|
|
32
|
+
spec.add_dependency 'faraday', '~> 2.2'
|
|
33
|
+
spec.add_dependency 'faraday-net_http_persistent', '~> 2.0' # workaround to make Faraday work after upgrading to 2.2.0
|
|
34
|
+
spec.add_dependency 'sinatra'
|
|
35
|
+
spec.add_dependency 'thor'
|
|
36
|
+
|
|
34
37
|
spec.add_development_dependency 'rack-test'
|
|
35
|
-
|
|
38
|
+
spec.add_development_dependency 'rspec'
|
|
39
|
+
end
|
data/bin/ara_generator
CHANGED
data/bin/console
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
4
|
+
require 'bundler/setup'
|
|
5
|
+
require 'app_rail/airtable'
|
|
5
6
|
|
|
6
7
|
# You can add fixtures and/or initialization code here to make experimenting
|
|
7
8
|
# with your gem easier. You can also use a different console, if you like.
|
|
@@ -10,5 +11,5 @@ require "app_rail/airtable"
|
|
|
10
11
|
# require "pry"
|
|
11
12
|
# Pry.start
|
|
12
13
|
|
|
13
|
-
require
|
|
14
|
+
require 'irb'
|
|
14
15
|
IRB.start(__FILE__)
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{
|
|
2
|
+
"tables": [
|
|
3
|
+
{
|
|
4
|
+
"name": "DailyLogs",
|
|
5
|
+
"fields": [
|
|
6
|
+
{
|
|
7
|
+
"name": "Date",
|
|
8
|
+
"type": "date"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"name": "Score",
|
|
12
|
+
"type": "integer"
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"associations": [
|
|
16
|
+
{
|
|
17
|
+
"name": "User",
|
|
18
|
+
"type": "belongs_to",
|
|
19
|
+
"model": "User"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"ar_class_methods": [
|
|
23
|
+
{
|
|
24
|
+
"name": "ar_list_item",
|
|
25
|
+
"properties": [
|
|
26
|
+
{
|
|
27
|
+
"type": "text",
|
|
28
|
+
"value": "date"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"type": "detail_text",
|
|
32
|
+
"value": "score"
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
],
|
|
37
|
+
"ar_instance_methods": [
|
|
38
|
+
{
|
|
39
|
+
"name": "ar_stack_item",
|
|
40
|
+
"properties": [
|
|
41
|
+
{
|
|
42
|
+
"type": "text",
|
|
43
|
+
"label": "Date",
|
|
44
|
+
"value": "date"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"type": "button",
|
|
48
|
+
"label": "Score",
|
|
49
|
+
"value": "score",
|
|
50
|
+
"modalWorkflow": "",
|
|
51
|
+
"style": "primary",
|
|
52
|
+
"onSuccess": "forward",
|
|
53
|
+
"sfSymbolName": ""
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
"authenticatable": "True"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"name": "Users",
|
|
62
|
+
"fields": [
|
|
63
|
+
{
|
|
64
|
+
"name": "Email",
|
|
65
|
+
"type": "string"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"name": "Password Hash",
|
|
69
|
+
"type": "string"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"name": "Access Token",
|
|
73
|
+
"type": "string"
|
|
74
|
+
}
|
|
75
|
+
],
|
|
76
|
+
"associations": [
|
|
77
|
+
{
|
|
78
|
+
"name": "DailyLogs",
|
|
79
|
+
"type": "has_many",
|
|
80
|
+
"model": "DailyLog"
|
|
81
|
+
}
|
|
82
|
+
],
|
|
83
|
+
"authenticatable": "True"
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"tables": [
|
|
3
|
+
{
|
|
4
|
+
"name": "DailyLogs",
|
|
5
|
+
"fields": [
|
|
6
|
+
{
|
|
7
|
+
"name": "Date",
|
|
8
|
+
"type": "date"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"name": "Score",
|
|
12
|
+
"type": "integer"
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"associations": [
|
|
16
|
+
{
|
|
17
|
+
"name": "User",
|
|
18
|
+
"type": "belongs_to",
|
|
19
|
+
"model": "User"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"ar_class_methods": [
|
|
23
|
+
{
|
|
24
|
+
"name": "ar_list_item",
|
|
25
|
+
"properties": [
|
|
26
|
+
{
|
|
27
|
+
"type": "text",
|
|
28
|
+
"value": "date"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"type": "detail_text",
|
|
32
|
+
"value": "score"
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
],
|
|
37
|
+
"ar_instance_methods": [
|
|
38
|
+
{
|
|
39
|
+
"name": "ar_stack_item",
|
|
40
|
+
"properties": [
|
|
41
|
+
{
|
|
42
|
+
"type": "text",
|
|
43
|
+
"label": "Date",
|
|
44
|
+
"value": "date"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"type": "button",
|
|
48
|
+
"label": "Score",
|
|
49
|
+
"value": "score",
|
|
50
|
+
"modalWorkflow": "",
|
|
51
|
+
"style": "primary",
|
|
52
|
+
"onSuccess": "forward",
|
|
53
|
+
"sfSymbolName": ""
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"name": "Users",
|
|
61
|
+
"fields": [
|
|
62
|
+
{
|
|
63
|
+
"name": "Email",
|
|
64
|
+
"type": "string"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"name": "Password Hash",
|
|
68
|
+
"type": "string"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"name": "Access Token",
|
|
72
|
+
"type": "string"
|
|
73
|
+
}
|
|
74
|
+
],
|
|
75
|
+
"associations": [
|
|
76
|
+
{
|
|
77
|
+
"name": "DailyLogs",
|
|
78
|
+
"type": "has_many",
|
|
79
|
+
"model": "DailyLog"
|
|
80
|
+
}
|
|
81
|
+
],
|
|
82
|
+
"authenticatable": "True"
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"tables": [
|
|
3
|
+
{
|
|
4
|
+
"name": "Users",
|
|
5
|
+
"fields": [
|
|
6
|
+
{
|
|
7
|
+
"name": "Forename",
|
|
8
|
+
"type": "string"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"name": "Surname",
|
|
12
|
+
"type": "string"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"name": "NHS Number",
|
|
16
|
+
"type": "integer"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"name": "Date of Birth",
|
|
20
|
+
"type": "date"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"name": "Vaccine",
|
|
24
|
+
"type": "string"
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"associations": [
|
|
28
|
+
{
|
|
29
|
+
"name": "Vaccination Appointments",
|
|
30
|
+
"type": "has_many",
|
|
31
|
+
"model": "VaccinationAppointment"
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
"ar_class_methods": [
|
|
35
|
+
{
|
|
36
|
+
"name": "ar_list_item",
|
|
37
|
+
"properties": [
|
|
38
|
+
{
|
|
39
|
+
"type": "text",
|
|
40
|
+
"value": "forename"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"type": "detail_text",
|
|
44
|
+
"value": "surname"
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
}
|
|
@@ -1,64 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'airrecord'
|
|
4
|
+
require 'app_rail-steps'
|
|
2
5
|
require 'active_support/core_ext/string/inflections'
|
|
3
6
|
|
|
4
7
|
module AppRail
|
|
5
8
|
module Airtable
|
|
6
9
|
class ApplicationRecord < Airrecord::Table
|
|
7
10
|
include ActiveSupport::Inflector
|
|
8
|
-
|
|
11
|
+
include AppRail::Steps::Displayable
|
|
12
|
+
|
|
9
13
|
def self.base_key
|
|
10
|
-
ENV.fetch(
|
|
14
|
+
ENV.fetch('AIRTABLE_BASE_ID')
|
|
11
15
|
end
|
|
12
|
-
|
|
16
|
+
|
|
13
17
|
def self.table_name
|
|
14
|
-
|
|
18
|
+
name.pluralize
|
|
15
19
|
end
|
|
16
|
-
|
|
20
|
+
|
|
17
21
|
def self.airtable_attr(*attributes)
|
|
18
22
|
attributes.each do |attribute|
|
|
19
23
|
define_method(attribute.to_s.snake_case) { self[attribute] }
|
|
20
24
|
define_method("#{attribute.to_s.snake_case}=") { |value| self[attribute] = value }
|
|
21
25
|
end
|
|
22
26
|
end
|
|
23
|
-
|
|
27
|
+
|
|
24
28
|
# Step utilities
|
|
25
29
|
def self.ar_list_item(text:, detail_text: nil, image: nil, sf_symbol: nil, material_icon: nil)
|
|
26
30
|
define_method(:ar_list_item_as_json) do
|
|
27
31
|
{
|
|
28
|
-
id:
|
|
29
|
-
text: method_value(text).to_s,
|
|
30
|
-
detailText: method_value(detail_text).to_s,
|
|
31
|
-
imageURL: method_value(image),
|
|
32
|
-
sfSymbolName: method_value(sf_symbol),
|
|
32
|
+
id: id,
|
|
33
|
+
text: method_value(text).to_s,
|
|
34
|
+
detailText: method_value(detail_text).to_s,
|
|
35
|
+
imageURL: method_value(image),
|
|
36
|
+
sfSymbolName: method_value(sf_symbol),
|
|
33
37
|
materialIconName: method_value(material_icon)
|
|
34
38
|
}.compact
|
|
35
39
|
end
|
|
36
40
|
end
|
|
37
|
-
|
|
41
|
+
|
|
38
42
|
def self.ar_stack(text_items:)
|
|
39
43
|
define_method(:ar_stack_as_json) do
|
|
40
|
-
text_items.map{|ti| {type: :text, label: ti, text: self[ti].to_s} }
|
|
44
|
+
text_items.map { |ti| { type: :text, label: ti, text: self[ti].to_s } }
|
|
41
45
|
end
|
|
42
46
|
end
|
|
43
|
-
|
|
47
|
+
|
|
44
48
|
# Customisable behaviour
|
|
45
|
-
|
|
49
|
+
|
|
46
50
|
# Override to provide custom sorting or filtering for index
|
|
47
51
|
def self.index(user:)
|
|
48
52
|
all
|
|
49
53
|
end
|
|
50
|
-
|
|
54
|
+
|
|
51
55
|
private
|
|
52
|
-
|
|
56
|
+
|
|
53
57
|
def method_value(name)
|
|
54
58
|
send(name) if name.present?
|
|
55
59
|
end
|
|
56
|
-
|
|
60
|
+
|
|
57
61
|
# size is either :small, :large or :full
|
|
58
62
|
def image(name, index: 0, size: :full)
|
|
59
|
-
self[name][index][
|
|
63
|
+
self[name][index]['thumbnails'][size.to_s]['url'] if self[name] && self[name].length > index
|
|
60
64
|
end
|
|
61
|
-
|
|
62
65
|
end
|
|
63
66
|
end
|
|
64
|
-
end
|
|
67
|
+
end
|