app_rail-airtable 0.3.7 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/Gemfile.lock +15 -30
- data/README.md +39 -5
- data/app_rail-airtable.gemspec +2 -0
- 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/authenticatable.rb +13 -2
- data/lib/app_rail/airtable/generator.rb +15 -0
- data/lib/app_rail/airtable/sinatra.rb +14 -4
- data/lib/app_rail/airtable/version.rb +3 -1
- data/templates/project/Gemfile +1 -1
- data/templates/project/Gemfile.lock +2 -2
- 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 +1 -0
- metadata +39 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5154709a34596c961227e058380aa927b7643df717e67289a6158b43f65b2213
|
4
|
+
data.tar.gz: 39b53b565d80d517aedc654f04b21f7d64189c4b0b62bd30ec1ea53252e9c1bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 68bfcd69273296c2eca597bf4bceb3bfefdd41f153d94a020f96e2604e8dcf7426359ea74e4ddcab6197a7ecf3f319dbefe204af1f9471b31cd83d921afaa87c
|
7
|
+
data.tar.gz: 23ce7443a261f2eb431c42f2904d1b7d31a98c843adb3e601c6d2cc6610a02d15597e4b65bef49dffb4d599df17a07b97bb0550d66b5f4eb122c66141b94a6ab
|
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.lock
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
app_rail-airtable (0.
|
4
|
+
app_rail-airtable (0.4.0)
|
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
|
|
@@ -16,47 +18,30 @@ GEM
|
|
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.8)
|
22
|
+
faraday (>= 0.10, < 3.0)
|
21
23
|
net-http-persistent
|
22
24
|
bcrypt (3.1.16)
|
23
25
|
byebug (11.1.3)
|
24
26
|
concurrent-ruby (1.1.9)
|
25
27
|
connection_pool (2.2.5)
|
26
28
|
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)
|
29
|
+
faraday (2.2.0)
|
30
|
+
faraday-net_http (~> 2.0)
|
38
31
|
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)
|
32
|
+
faraday-net_http (2.0.1)
|
33
|
+
faraday-net_http_persistent (2.0.1)
|
34
|
+
faraday-net_http
|
35
|
+
net-http-persistent (~> 4.0)
|
36
|
+
i18n (1.10.0)
|
51
37
|
concurrent-ruby (~> 1.0)
|
52
38
|
minitest (5.15.0)
|
53
|
-
multipart-post (2.1.1)
|
54
39
|
mustermann (1.1.1)
|
55
40
|
ruby2_keywords (~> 0.0.1)
|
56
41
|
net-http-persistent (4.0.1)
|
57
42
|
connection_pool (~> 2.2)
|
58
43
|
rack (2.2.3)
|
59
|
-
rack-protection (2.
|
44
|
+
rack-protection (2.2.0)
|
60
45
|
rack
|
61
46
|
rack-test (1.1.0)
|
62
47
|
rack (>= 1.0, < 3)
|
@@ -75,10 +60,10 @@ GEM
|
|
75
60
|
rspec-support (~> 3.10.0)
|
76
61
|
rspec-support (3.10.2)
|
77
62
|
ruby2_keywords (0.0.5)
|
78
|
-
sinatra (2.
|
63
|
+
sinatra (2.2.0)
|
79
64
|
mustermann (~> 1.0)
|
80
65
|
rack (~> 2.2)
|
81
|
-
rack-protection (= 2.
|
66
|
+
rack-protection (= 2.2.0)
|
82
67
|
tilt (~> 2.0)
|
83
68
|
thor (1.1.0)
|
84
69
|
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/app_rail-airtable.gemspec
CHANGED
@@ -27,6 +27,8 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.add_dependency 'activesupport'
|
28
28
|
spec.add_dependency 'sinatra'
|
29
29
|
spec.add_dependency 'airrecord'
|
30
|
+
spec.add_dependency 'faraday', '~> 2.2'
|
31
|
+
spec.add_dependency 'faraday-net_http_persistent', '~> 2.0' # workaround to make Faraday work after upgrading to 2.2.0
|
30
32
|
spec.add_dependency 'thor'
|
31
33
|
spec.add_dependency 'bcrypt'
|
32
34
|
|
@@ -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
|
+
}
|
@@ -8,11 +8,12 @@ module AppRail
|
|
8
8
|
|
9
9
|
def self.included(klass)
|
10
10
|
klass.extend(ClassMethods)
|
11
|
+
klass.prepend(InstanceMethods) # prepends `initialize` instance method in order to take precedence over Airrecord::Table#initialize
|
11
12
|
end
|
12
13
|
|
13
14
|
module ClassMethods
|
14
15
|
def create(email:, password:)
|
15
|
-
user =
|
16
|
+
user = new("Email" => email, "Password Hash" => password_hash(password), "Access Token" => next_access_token)
|
16
17
|
user.create
|
17
18
|
user
|
18
19
|
end
|
@@ -43,7 +44,17 @@ module AppRail
|
|
43
44
|
SecureRandom.hex
|
44
45
|
end
|
45
46
|
end
|
46
|
-
|
47
|
+
|
48
|
+
module InstanceMethods
|
49
|
+
def initialize(*args)
|
50
|
+
if (kwargs = args.first) && kwargs.is_a?(Hash) && kwargs.size == 2 && kwargs.key?(:email) && kwargs.key?(:password)
|
51
|
+
super("Email" => kwargs[:email], "Password Hash" => self.class.password_hash(kwargs[:password]), "Access Token" => self.class.next_access_token)
|
52
|
+
else
|
53
|
+
super
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
47
58
|
def valid_password?(password)
|
48
59
|
BCrypt::Password.new(password_hash) == password
|
49
60
|
end
|
@@ -55,6 +55,21 @@ module AppRail
|
|
55
55
|
raise "ERROR! The key \"#{key}\" is not present in the schema definition."
|
56
56
|
end
|
57
57
|
end
|
58
|
+
|
59
|
+
def fields_as_params_examples(fields)
|
60
|
+
fields.each_with_object({}) do |field, hsh|
|
61
|
+
hsh[field['name']] = case field['type']
|
62
|
+
when 'date'
|
63
|
+
'01/01/2022'
|
64
|
+
when 'string', 'text'
|
65
|
+
'MyString'
|
66
|
+
when 'integer'
|
67
|
+
10
|
68
|
+
else
|
69
|
+
'MyString'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
58
73
|
end
|
59
74
|
end
|
60
75
|
end
|
@@ -37,7 +37,7 @@ module AppRail
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
-
def self.authenticatable_resources(name, only: [:index, :show, :create])
|
40
|
+
def self.authenticatable_resources(name, only: [:index, :show, :create, :update])
|
41
41
|
|
42
42
|
# If authentication is used then include the correct helpers
|
43
43
|
# Allowing the routes to use `authenticate!` and `current_user`
|
@@ -51,12 +51,13 @@ module AppRail
|
|
51
51
|
@@authenticated_route = false
|
52
52
|
end
|
53
53
|
|
54
|
-
def self.resources(name, only: [:index, :show, :create])
|
54
|
+
def self.resources(name, only: [:index, :show, :create, :update])
|
55
55
|
only = [only] if only.is_a?(Symbol)
|
56
|
-
|
56
|
+
|
57
57
|
index_route(name, authenticated_route?) if only.include?(:index)
|
58
58
|
show_route(name, authenticated_route?) if only.include?(:show)
|
59
59
|
create_route(name, authenticated_route?) if only.include?(:create)
|
60
|
+
update_route(name, authenticated_route?) if only.include?(:update)
|
60
61
|
end
|
61
62
|
|
62
63
|
def self.index_route(name, authenticated_route)
|
@@ -80,7 +81,16 @@ module AppRail
|
|
80
81
|
[201, as_json.to_json]
|
81
82
|
end
|
82
83
|
end
|
83
|
-
|
84
|
+
|
85
|
+
def self.update_route(name, authenticated_route)
|
86
|
+
put "/#{name.to_s}/:id" do
|
87
|
+
authenticate! if authenticated_route
|
88
|
+
record = name.classify_constantize.find(params['id'])
|
89
|
+
as_json = record.update_as_json(current_user: authenticated_route ? current_user : nil, params: params_and_body_as_json)
|
90
|
+
[200, as_json.to_json]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
84
94
|
def self.authenticated_route?
|
85
95
|
@@authenticated_route
|
86
96
|
end
|
data/templates/project/Gemfile
CHANGED
@@ -10,7 +10,7 @@ GEM
|
|
10
10
|
airrecord (1.0.7)
|
11
11
|
faraday (>= 0.10, < 2.0)
|
12
12
|
net-http-persistent
|
13
|
-
app_rail-airtable (0.
|
13
|
+
app_rail-airtable (0.4.0)
|
14
14
|
activesupport
|
15
15
|
airrecord
|
16
16
|
bcrypt
|
@@ -83,7 +83,7 @@ PLATFORMS
|
|
83
83
|
ruby
|
84
84
|
|
85
85
|
DEPENDENCIES
|
86
|
-
app_rail-airtable (~> 0.
|
86
|
+
app_rail-airtable (~> 0.4.0)
|
87
87
|
byebug
|
88
88
|
dotenv
|
89
89
|
rack-test
|
@@ -25,6 +25,12 @@ class <%= table['name'].singularize %> < AppRail::Airtable::ApplicationRecord
|
|
25
25
|
record = <%= table['name'].singularize %>.create(email: params["payload"]["email"], password: params["payload"]["password"])
|
26
26
|
{ response: { id: record.id }, oauth_session: record.oauth_session}
|
27
27
|
end
|
28
|
+
|
29
|
+
def update_as_json(params:, current_user:)
|
30
|
+
params['payload'].each { |attr, v| public_send("#{attr}=", v) }
|
31
|
+
save
|
32
|
+
{ response: { id: id }, oauth_session: oauth_session }
|
33
|
+
end
|
28
34
|
<% end -%>
|
29
35
|
end
|
30
36
|
|
@@ -69,6 +69,24 @@ RSpec.describe Server do
|
|
69
69
|
it { expect(json_response).to eq [resource_to_json] }
|
70
70
|
end
|
71
71
|
|
72
|
+
describe 'PUT /<%= path_name %>/:id"' do
|
73
|
+
let(:params) { <%= fields_as_params_examples(table['fields']) %> }
|
74
|
+
let(:response) { put "/<%= path_name %>/#{id}", params.to_json, headers }
|
75
|
+
let(:mock_auth_resource) { instance_double(<%= auth_model_name %>) }
|
76
|
+
let(:mock_resource) { instance_double(<%= model_name %>, id: id) }
|
77
|
+
let(:resource_to_json) { { id: id } }
|
78
|
+
let(:headers) { auth_headers.merge('CONTENT_TYPE' => 'application/json') }
|
79
|
+
let(:id) { '1' }
|
80
|
+
|
81
|
+
before do
|
82
|
+
allow(<%= auth_model_name %>).to receive(:find_by_access_token).with(access_token) { mock_auth_resource }
|
83
|
+
allow(<%= model_name %>).to receive(:find).with(id) { mock_resource }
|
84
|
+
allow(mock_resource).to receive(:update_as_json).with(current_user: mock_auth_resource, params: { 'id' => '1' }.merge(params)) { resource_to_json }
|
85
|
+
end
|
86
|
+
|
87
|
+
it { expect(response.status).to eq 200 }
|
88
|
+
it { expect(json_response).to eq resource_to_json }
|
89
|
+
end
|
72
90
|
<% end -%>
|
73
91
|
<% else -%>
|
74
92
|
<% @tables.each do |table| -%>
|
@@ -89,6 +107,22 @@ RSpec.describe Server do
|
|
89
107
|
it { expect(json_response).to eq [resource_to_json] }
|
90
108
|
end
|
91
109
|
|
110
|
+
describe 'PUT /<%= path_name %>/:id"' do
|
111
|
+
let(:params) { <%= fields_as_params_examples(table['fields']) %> }
|
112
|
+
let(:response) { put "/<%= path_name %>/#{id}", params.to_json, headers }
|
113
|
+
let(:mock_resource) { instance_double(<%= model_name %>, id: id) }
|
114
|
+
let(:resource_to_json) { { id: id } }
|
115
|
+
let(:headers) { auth_headers.merge('CONTENT_TYPE' => 'application/json') }
|
116
|
+
let(:id) { '1' }
|
117
|
+
|
118
|
+
before do
|
119
|
+
allow(<%= model_name %>).to receive(:find).with(id) { mock_resource }
|
120
|
+
allow(mock_resource).to receive(:update_as_json).with(current_user: mock_auth_resource, params: { 'id' => '1' }.merge(params)) { resource_to_json }
|
121
|
+
end
|
122
|
+
|
123
|
+
it { expect(response.status).to eq 200 }
|
124
|
+
it { expect(json_response).to eq resource_to_json }
|
125
|
+
end
|
92
126
|
<% end -%>
|
93
127
|
<% end -%>
|
94
128
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: app_rail-airtable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Brooke-Smith
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-02-
|
11
|
+
date: 2022-02-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -52,6 +52,34 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: faraday
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.2'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.2'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: faraday-net_http_persistent
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.0'
|
55
83
|
- !ruby/object:Gem::Dependency
|
56
84
|
name: thor
|
57
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,7 +136,7 @@ dependencies:
|
|
108
136
|
- - ">="
|
109
137
|
- !ruby/object:Gem::Version
|
110
138
|
version: '0'
|
111
|
-
description:
|
139
|
+
description:
|
112
140
|
email:
|
113
141
|
- matt@futureworkshops.com
|
114
142
|
executables:
|
@@ -120,6 +148,7 @@ files:
|
|
120
148
|
- ".gitignore"
|
121
149
|
- ".rspec"
|
122
150
|
- ".travis.yml"
|
151
|
+
- CHANGELOG.md
|
123
152
|
- Gemfile
|
124
153
|
- Gemfile.lock
|
125
154
|
- LICENSE.txt
|
@@ -129,6 +158,9 @@ files:
|
|
129
158
|
- bin/ara_generator
|
130
159
|
- bin/console
|
131
160
|
- bin/setup
|
161
|
+
- examples/schemas/daily_logs.json
|
162
|
+
- examples/schemas/locations.json
|
163
|
+
- examples/schemas/users.json
|
132
164
|
- lib/app_rail/airtable.rb
|
133
165
|
- lib/app_rail/airtable/application_record.rb
|
134
166
|
- lib/app_rail/airtable/authenticatable.rb
|
@@ -152,7 +184,7 @@ licenses:
|
|
152
184
|
metadata:
|
153
185
|
homepage_uri: https://github.com/FutureWorkshops/app_rail-airtable
|
154
186
|
source_code_uri: https://github.com/FutureWorkshops/app_rail-airtable
|
155
|
-
post_install_message:
|
187
|
+
post_install_message:
|
156
188
|
rdoc_options: []
|
157
189
|
require_paths:
|
158
190
|
- lib
|
@@ -167,8 +199,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
167
199
|
- !ruby/object:Gem::Version
|
168
200
|
version: '0'
|
169
201
|
requirements: []
|
170
|
-
rubygems_version: 3.
|
171
|
-
signing_key:
|
202
|
+
rubygems_version: 3.3.6
|
203
|
+
signing_key:
|
172
204
|
specification_version: 4
|
173
205
|
summary: Gem to help building App Rail servers using Airtable as a backend
|
174
206
|
test_files: []
|