app_rail-airtable 0.3.5 → 0.4.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/CHANGELOG.md +9 -0
- data/Gemfile.lock +16 -31
- 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 +14 -3
- data/lib/app_rail/airtable/generator.rb +17 -2
- 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,62 +1,47 @@
|
|
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
|
|
11
13
|
GEM
|
12
14
|
remote: https://rubygems.org/
|
13
15
|
specs:
|
14
|
-
activesupport (7.0.
|
16
|
+
activesupport (7.0.2.2)
|
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.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.8.11)
|
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
|
@@ -28,7 +29,7 @@ module AppRail
|
|
28
29
|
|
29
30
|
def find_by_email_and_password(email, password)
|
30
31
|
user = all(filter: "{Email} = \"#{email}\"").first
|
31
|
-
user
|
32
|
+
user&.valid_password?(password) ? user : nil
|
32
33
|
end
|
33
34
|
|
34
35
|
def find_by_access_token(access_token)
|
@@ -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
|
@@ -13,7 +13,7 @@ module AppRail
|
|
13
13
|
argument :output_directory
|
14
14
|
argument :api_key
|
15
15
|
argument :base_id
|
16
|
-
argument :schema
|
16
|
+
argument :schema, required: false
|
17
17
|
|
18
18
|
def self.source_root
|
19
19
|
File.join(File.dirname(__FILE__), '..', '..', '..')
|
@@ -41,7 +41,7 @@ module AppRail
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def tables
|
44
|
-
@tables ||= JSON.parse(schema)['tables']
|
44
|
+
@tables ||= schema ? JSON.parse(schema)['tables'] : []
|
45
45
|
end
|
46
46
|
|
47
47
|
def find_table(table_name)
|
@@ -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-
|
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: []
|