app_rail-airtable 0.1.0 → 0.5.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 +4 -4
- data/.gitignore +8 -0
- data/CHANGELOG.md +13 -0
- data/Gemfile +7 -3
- data/Gemfile.lock +33 -36
- data/README.md +63 -15
- data/Rakefile +5 -3
- data/app_rail-airtable.gemspec +26 -15
- data/bin/ara_generator +8 -0
- 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 +43 -25
- data/lib/app_rail/airtable/authenticatable.rb +78 -0
- data/lib/app_rail/airtable/authentication_helpers.rb +38 -0
- data/lib/app_rail/airtable/generator.rb +75 -0
- data/lib/app_rail/airtable/sinatra.rb +106 -18
- data/lib/app_rail/airtable/string_ext.rb +7 -0
- data/lib/app_rail/airtable/version.rb +3 -1
- data/lib/app_rail/airtable.rb +9 -3
- data/templates/project/.env.tt +2 -0
- data/templates/project/.gitignore +19 -0
- data/templates/project/Gemfile +24 -0
- data/templates/project/app.json +17 -0
- data/templates/project/boot.rb +8 -0
- data/templates/project/config.ru +6 -0
- data/templates/project/lib/server.rb.tt +68 -0
- data/templates/project/spec/server_spec.rb.tt +128 -0
- data/templates/project/spec/spec_helper.rb +114 -0
- metadata +96 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 208213f6a53029eb29b4d98ed9b6d4f9bb7bb0375d3a5de3866615c8701ec3d9
|
4
|
+
data.tar.gz: 5aea3eda06422225f87170aa3b1d8a8a3310123fb151a554b29ad8059db72847
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 975099138a2b7aef7ae085a09d7ace624f6b7eba9c892691807505ec44f8322dbf8b3a474113ecb3053b6d8243264db97531607ec2cfc3b4ad8907c253242dc0
|
7
|
+
data.tar.gz: 2b07588a9c2c375a0b4574a4500921c40f306c45bf153fd530520b7874716f4fbdb3b4cd56ade60c5dba9827b097052833e8827b4b564a83303af47bb4373af7
|
data/.gitignore
CHANGED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# 0.4.6
|
2
|
+
* Add authenticatable_resource POST / DELETE `/<resource>/session` routes for sign in and sign out
|
3
|
+
* Simplify sign in methods & remove Authenticatable#create_session_as_json
|
4
|
+
|
5
|
+
# 0.4.0
|
6
|
+
|
7
|
+
### Breaking changes
|
8
|
+
* `AppRail::Airtable::Sinatra` `.resources` and `.authenticable_resources` `only` argument defaults to `[:index, :show, :create, :update]` instead of `[:index, :show, :create]`
|
9
|
+
|
10
|
+
### New features
|
11
|
+
* Add `Authenticatable#initialize` method to initialize an Airrecord record without persisting it to airtable
|
12
|
+
* Add `update` route (`PUT`), which points to the corresponding model method `self.update_as_json`
|
13
|
+
|
data/Gemfile
CHANGED
@@ -1,7 +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 'byebug'
|
9
|
+
gem 'rake', '~> 12.0'
|
10
|
+
gem 'rspec', '~> 3.0'
|
11
|
+
gem 'thor'
|
data/Gemfile.lock
CHANGED
@@ -1,55 +1,50 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
app_rail-airtable (0.
|
4
|
+
app_rail-airtable (0.5.0)
|
5
5
|
activesupport
|
6
6
|
airrecord
|
7
|
+
app_rail-steps
|
8
|
+
bcrypt
|
9
|
+
faraday (~> 2.2)
|
10
|
+
faraday-net_http_persistent (~> 2.0)
|
7
11
|
sinatra
|
12
|
+
thor
|
8
13
|
|
9
14
|
GEM
|
10
15
|
remote: https://rubygems.org/
|
11
16
|
specs:
|
12
|
-
activesupport (
|
17
|
+
activesupport (7.0.4)
|
13
18
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
14
19
|
i18n (>= 1.6, < 2)
|
15
20
|
minitest (>= 5.1)
|
16
21
|
tzinfo (~> 2.0)
|
17
|
-
|
18
|
-
|
19
|
-
faraday
|
22
|
+
airrecord (1.0.10)
|
23
|
+
faraday (>= 1.0, < 3.0)
|
24
|
+
faraday-net_http_persistent
|
20
25
|
net-http-persistent
|
21
|
-
|
22
|
-
|
26
|
+
app_rail-steps (0.2.17)
|
27
|
+
bcrypt (3.1.18)
|
28
|
+
byebug (11.1.3)
|
29
|
+
concurrent-ruby (1.1.10)
|
30
|
+
connection_pool (2.3.0)
|
23
31
|
diff-lcs (1.4.4)
|
24
|
-
faraday (
|
25
|
-
faraday-
|
26
|
-
faraday-em_synchrony (~> 1.0)
|
27
|
-
faraday-excon (~> 1.1)
|
28
|
-
faraday-httpclient (~> 1.0.1)
|
29
|
-
faraday-net_http (~> 1.0)
|
30
|
-
faraday-net_http_persistent (~> 1.1)
|
31
|
-
faraday-patron (~> 1.0)
|
32
|
-
faraday-rack (~> 1.0)
|
33
|
-
multipart-post (>= 1.2, < 3)
|
32
|
+
faraday (2.6.0)
|
33
|
+
faraday-net_http (>= 2.0, < 3.1)
|
34
34
|
ruby2_keywords (>= 0.0.4)
|
35
|
-
faraday-
|
36
|
-
faraday-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
faraday-net_http_persistent (1.2.0)
|
41
|
-
faraday-patron (1.0.0)
|
42
|
-
faraday-rack (1.0.0)
|
43
|
-
i18n (1.8.10)
|
35
|
+
faraday-net_http (3.0.1)
|
36
|
+
faraday-net_http_persistent (2.1.0)
|
37
|
+
faraday (~> 2.5)
|
38
|
+
net-http-persistent (~> 4.0)
|
39
|
+
i18n (1.12.0)
|
44
40
|
concurrent-ruby (~> 1.0)
|
45
|
-
minitest (5.
|
46
|
-
|
47
|
-
mustermann (1.1.1)
|
41
|
+
minitest (5.16.3)
|
42
|
+
mustermann (2.0.2)
|
48
43
|
ruby2_keywords (~> 0.0.1)
|
49
44
|
net-http-persistent (4.0.1)
|
50
45
|
connection_pool (~> 2.2)
|
51
46
|
rack (2.2.3)
|
52
|
-
rack-protection (2.
|
47
|
+
rack-protection (2.2.2)
|
53
48
|
rack
|
54
49
|
rack-test (1.1.0)
|
55
50
|
rack (>= 1.0, < 3)
|
@@ -68,24 +63,26 @@ GEM
|
|
68
63
|
rspec-support (~> 3.10.0)
|
69
64
|
rspec-support (3.10.2)
|
70
65
|
ruby2_keywords (0.0.5)
|
71
|
-
sinatra (2.
|
72
|
-
mustermann (~>
|
66
|
+
sinatra (2.2.2)
|
67
|
+
mustermann (~> 2.0)
|
73
68
|
rack (~> 2.2)
|
74
|
-
rack-protection (= 2.
|
69
|
+
rack-protection (= 2.2.2)
|
75
70
|
tilt (~> 2.0)
|
76
|
-
|
77
|
-
|
71
|
+
thor (1.1.0)
|
72
|
+
tilt (2.0.11)
|
73
|
+
tzinfo (2.0.5)
|
78
74
|
concurrent-ruby (~> 1.0)
|
79
|
-
zeitwerk (2.4.2)
|
80
75
|
|
81
76
|
PLATFORMS
|
82
77
|
ruby
|
83
78
|
|
84
79
|
DEPENDENCIES
|
85
80
|
app_rail-airtable!
|
81
|
+
byebug
|
86
82
|
rack-test
|
87
83
|
rake (~> 12.0)
|
88
84
|
rspec (~> 3.0)
|
85
|
+
thor
|
89
86
|
|
90
87
|
BUNDLED WITH
|
91
88
|
2.1.4
|
data/README.md
CHANGED
@@ -1,8 +1,6 @@
|
|
1
|
-
#
|
1
|
+
# App Rail Airtable
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
TODO: Delete this and the text above, and describe your gem
|
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.
|
6
4
|
|
7
5
|
## Installation
|
8
6
|
|
@@ -12,29 +10,79 @@ Add this line to your application's Gemfile:
|
|
12
10
|
gem 'app_rail-airtable'
|
13
11
|
```
|
14
12
|
|
15
|
-
|
13
|
+
## Usage
|
16
14
|
|
17
|
-
|
15
|
+
App Rail Airtable has two important concepts, models and servers.
|
18
16
|
|
19
|
-
|
17
|
+
### Models
|
18
|
+
App Rail Airtable makes the following assumptions
|
19
|
+
1. Your App will connect to a single Airtable Base
|
20
|
+
2. Your Airtable Base implements a normalised datamodel
|
21
|
+
3. Your tables in Airtable are plural versions of the models you create in Ruby
|
20
22
|
|
21
|
-
|
23
|
+
**API keys have account scope in Airtable so it is recommended to create a new account for each project so that API keys do not leak data, e.g. bob+<project name>@gmail.com. You can share the project with your main account so you don't need to login to separate accounts for each project.**
|
22
24
|
|
23
|
-
|
25
|
+
You should create a model class for each table you want to use in your App. Model classes should extend `AppRail::Airtable::ApplicationRecord` and define [table name](https://github.com/sirupsen/airrecord#table) and [associations](https://github.com/sirupsen/airrecord#associations)
|
26
|
+
|
27
|
+
To provide support for routes, models can implement
|
28
|
+
* ar_list_item (index)
|
29
|
+
* ar_stack (show)
|
30
|
+
* self.create_as_json (create)
|
31
|
+
* self.update_as_json (update)
|
32
|
+
|
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.
|
34
|
+
|
35
|
+
### Servers
|
36
|
+
You should create a single server which extends `AppRail::Airtable::Sinatra`.
|
37
|
+
|
38
|
+
App Rail Airtable provides two helpers to generate routes
|
39
|
+
|
40
|
+
**resources(name, only:)**
|
41
|
+
Creates routes that map to a table. It delegates from the route to a model method
|
42
|
+
* `index` to `ar_list_item`
|
43
|
+
* `show` to `ar_stack`
|
44
|
+
* `create` to `self.create_as_json`
|
45
|
+
* `update` to `self.update_as_json`
|
24
46
|
|
25
|
-
|
47
|
+
**authenticable_resources(name, , only:)**
|
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).
|
26
49
|
|
27
|
-
|
50
|
+
### Generator
|
28
51
|
|
29
|
-
|
52
|
+
```bash
|
53
|
+
bin/ara_generator <output_directory> <airtable_api_key> <airtable_base_id> [<json_schema>]
|
54
|
+
```
|
30
55
|
|
31
|
-
|
56
|
+
#### Example
|
32
57
|
|
33
|
-
|
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
|
+
```
|
34
61
|
|
35
|
-
|
62
|
+
You can find more examples of schemas in [/examples/schemas](/examples/schemas)
|
36
63
|
|
64
|
+
## Debugging
|
37
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
|
+
```
|
38
86
|
## License
|
39
87
|
|
40
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,29 +1,40 @@
|
|
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
|
+
|
25
|
+
spec.bindir = 'bin'
|
26
|
+
spec.executables << 'ara_generator'
|
27
|
+
|
28
|
+
spec.require_paths = ['lib']
|
23
29
|
spec.add_dependency 'activesupport'
|
24
|
-
spec.add_dependency 'sinatra'
|
25
30
|
spec.add_dependency 'airrecord'
|
26
|
-
|
27
|
-
spec.
|
31
|
+
spec.add_dependency 'app_rail-steps'
|
32
|
+
spec.add_dependency 'bcrypt'
|
33
|
+
spec.add_dependency 'faraday', '~> 2.2'
|
34
|
+
spec.add_dependency 'faraday-net_http_persistent', '~> 2.0' # workaround to make Faraday work after upgrading to 2.2.0
|
35
|
+
spec.add_dependency 'sinatra'
|
36
|
+
spec.add_dependency 'thor'
|
37
|
+
|
28
38
|
spec.add_development_dependency 'rack-test'
|
29
|
-
|
39
|
+
spec.add_development_dependency 'rspec'
|
40
|
+
end
|
data/bin/ara_generator
ADDED
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
|
+
}
|