fmrest-spyke 0.16.0 → 0.18.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -10
- data/README.md +52 -6
- data/lib/fmrest/spyke/model/associations.rb +7 -2
- data/lib/fmrest/spyke/model/attributes.rb +7 -1
- data/lib/fmrest/spyke/model/global_fields.rb +1 -3
- data/lib/fmrest/spyke/model/rescuable.rb +27 -0
- data/lib/fmrest/spyke/model/serialization.rb +1 -1
- data/lib/fmrest/spyke/model.rb +2 -0
- data/lib/fmrest/spyke/portal_builder.rb +17 -0
- data/lib/fmrest/spyke/spyke_formatter.rb +19 -5
- metadata +9 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 38cc05be48b9ba5737e7a2c1d89504bab617a2f1d6d7261fde1b5a919aa793e7
|
4
|
+
data.tar.gz: 0b1780c8ce2f7d8d8f4c300909b2bafb7f41e18e2ce648f929be9e2d3569ddbe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 123d5611c9c862605c30643b8034665c67c24fc283d21311f6124baff2271c459bcae0d4834f2480f4aa2e521105a6df58ecb011f46fc4f50a656df4a91108f5
|
7
|
+
data.tar.gz: 91a6d0bdf49792a76b0bf817543a89e7b92bcf0c55eaa128d9bee3219f250e47a14bd064f862383f11f66dac70f1830cc6f1017b56d912f4d8be344e7ac86bed
|
data/CHANGELOG.md
CHANGED
@@ -1,13 +1,29 @@
|
|
1
1
|
## Changelog
|
2
2
|
|
3
|
+
### 0.18.0
|
4
|
+
|
5
|
+
* Better support for portals with mismatching field qualifiers
|
6
|
+
* Defining an attribute on a model that would collide with an existing method
|
7
|
+
now raises an error
|
8
|
+
|
9
|
+
### 0.17.1
|
10
|
+
|
11
|
+
* Fixed crash when `fmid_token` is set but `username` isn't
|
12
|
+
|
13
|
+
### 0.17.0
|
14
|
+
|
15
|
+
* Added support for Claris ID token login
|
16
|
+
* Added ability to use procs in settings
|
17
|
+
* Added `Rescuable` mixin
|
18
|
+
|
3
19
|
### 0.16.0
|
4
20
|
|
5
|
-
*
|
21
|
+
* Added `FmRest.logger=`
|
6
22
|
* Handle serialization of `nil`, `true` and `false` values
|
7
23
|
|
8
24
|
### 0.15.2
|
9
25
|
|
10
|
-
*
|
26
|
+
* Fixed autoloading of `FmRest::Layout`
|
11
27
|
|
12
28
|
### 0.15.0
|
13
29
|
|
@@ -23,13 +39,13 @@
|
|
23
39
|
|
24
40
|
### 0.13.1
|
25
41
|
|
26
|
-
*
|
42
|
+
* Fixed downloading of container field data from FMS19+
|
27
43
|
|
28
44
|
### 0.13.0
|
29
45
|
|
30
46
|
* Split `fmrest` gem into `fmrest-core` and `fmrest-spyke`. `fmrest` becomes a
|
31
47
|
wrapper for the two new gems.
|
32
|
-
*
|
48
|
+
* Fixed bug preventing connection databases with spaces in their names.
|
33
49
|
* Improved portal support with ability to delete portal records, and better
|
34
50
|
refreshing of portal records after saving the parent.
|
35
51
|
* `FmRest::Spyke::Base#__record_id` and `FmRest::Spyke::Base#__mod_id` now
|
@@ -44,7 +60,7 @@
|
|
44
60
|
|
45
61
|
### 0.11.1
|
46
62
|
|
47
|
-
*
|
63
|
+
* Fixed a couple crashes due to missing constants
|
48
64
|
|
49
65
|
### 0.11.0
|
50
66
|
|
@@ -59,7 +75,7 @@
|
|
59
75
|
|
60
76
|
### 0.10.1
|
61
77
|
|
62
|
-
*
|
78
|
+
* Fixed `URI.escape` obsolete warning messages in Ruby 2.7 by replacing it with
|
63
79
|
`URI.encode_www_form_component`
|
64
80
|
([PR#40](https://github.com/beezwax/fmrest-ruby/pull/40))
|
65
81
|
|
@@ -133,20 +149,20 @@
|
|
133
149
|
|
134
150
|
### 0.3.2
|
135
151
|
|
136
|
-
*
|
152
|
+
* Fixed support for ActiveSupport < 5.2
|
137
153
|
([#27](https://github.com/beezwax/fmrest-ruby/issues/27))
|
138
154
|
|
139
155
|
### 0.3.0
|
140
156
|
|
141
|
-
*
|
157
|
+
* Added Moneta token store
|
142
158
|
|
143
159
|
### 0.2.5
|
144
160
|
|
145
|
-
*
|
161
|
+
* Fixed crash in `fetch_container_data` when no proxy options were set
|
146
162
|
|
147
163
|
### 0.2.4
|
148
164
|
|
149
165
|
* Use `String#=~` instead of `String#match?` for Ruby <2.4 compatibility (Fixes
|
150
166
|
[#26](https://github.com/beezwax/fmrest-ruby/issues/26))
|
151
|
-
*
|
167
|
+
* Deprecated `FmRest.config` in favor of `FmRest.default_connection_settings`
|
152
168
|
* Honor Faraday SSL and proxy settings when fetching container files
|
data/README.md
CHANGED
@@ -125,6 +125,10 @@ The minimum required connection settings are `:host`, `:database`, `:username`
|
|
125
125
|
and `:password`, but fmrest-ruby has many other options you can pass when
|
126
126
|
setting up a connection (see [full list](#full-list-of-available-options) below).
|
127
127
|
|
128
|
+
If you're using FileMaker Cloud you may need to pass `:fmid_token` instead
|
129
|
+
of the regular `:username` and `:password`. See the [main document on
|
130
|
+
connecting to FileMaker Cloud](docs/FileMakerCloud.md) for more info.
|
131
|
+
|
128
132
|
`:ssl` and `:proxy` are forwarded to the underlying
|
129
133
|
[Faraday](https://github.com/lostisland/faraday) connection. You can use this
|
130
134
|
to, for instance, disable SSL verification:
|
@@ -149,6 +153,7 @@ Option | Description | Format
|
|
149
153
|
`:username` | A Data API-ready account | String | None
|
150
154
|
`:password` | Your password | String | None
|
151
155
|
`:account_name` | Alias of `:username` | String | None
|
156
|
+
`:fmid_token` | Claris ID token (only needed for FileMaker Cloud) | String | None
|
152
157
|
`:ssl` | SSL options to be forwarded to Faraday | Faraday SSL options | None
|
153
158
|
`:proxy` | Proxy options to be forwarded to Faraday | Faraday proxy options | None
|
154
159
|
`:log` | Log JSON responses to STDOUT | Boolean | `false`
|
@@ -283,10 +288,12 @@ Also, if not set, your model will try to use
|
|
283
288
|
#### Connection settings overlays
|
284
289
|
|
285
290
|
There may be cases where you want to use a different set of connection settings
|
286
|
-
depending on context
|
287
|
-
provided by the user in a web
|
288
|
-
|
289
|
-
|
291
|
+
depending on context, or simply change the connection settings over time. For
|
292
|
+
example, if you want to use username and password provided by the user in a web
|
293
|
+
application, or if you're connecting using an expiring Claris ID token. Since
|
294
|
+
`.fmrest_config` is set at the class level, changing the username/password for
|
295
|
+
the model in one context would also change it in all other contexts, leading to
|
296
|
+
security issues.
|
290
297
|
|
291
298
|
To solve this scenario, fmrest-ruby provides a way of defining thread-local and
|
292
299
|
reversible connection settings overlays through
|
@@ -323,7 +330,7 @@ Requests a Data API session token using the connection settings in
|
|
323
330
|
|
324
331
|
You normally don't need to use this method as fmrest-ruby will automatically
|
325
332
|
request and store session tokens for you (provided that `:autologin` is
|
326
|
-
`true`).
|
333
|
+
`true` in the connection settings, which it is by default).
|
327
334
|
|
328
335
|
### FmRest::Layout.logout
|
329
336
|
|
@@ -452,6 +459,41 @@ field values on the database that model is configured for.
|
|
452
459
|
See the [main document on setting global field values](docs/GlobalFields.md)
|
453
460
|
for details.
|
454
461
|
|
462
|
+
### Rescuable mixin
|
463
|
+
|
464
|
+
Sometimes you may want to handle Data API errors at the model level. For
|
465
|
+
instance, if you're logging in to a file hosted by FileMaker Cloud using a
|
466
|
+
Claris ID token, and you want to be able to renew said token when it fails to
|
467
|
+
log you in. For such cases fmrest-ruby provides an off-by-default mixin called
|
468
|
+
`Rescuable` that provides convenience macros for that. If you've used Ruby on
|
469
|
+
Rails you may be familiar with its syntax from controllers. E.g.
|
470
|
+
|
471
|
+
```ruby
|
472
|
+
class BeeBase < FmRest::Layout
|
473
|
+
include FmRest::Spyke::Model::Rescuable
|
474
|
+
|
475
|
+
rescue_from FmRest::APIError::SystemError, with: :notify_admin_of_system_error
|
476
|
+
|
477
|
+
# Shorthand for rescue_with FmRest::APIError::AccountError, ...
|
478
|
+
rescue_account_error { ClarisIDTokenManager.expire_token }
|
479
|
+
|
480
|
+
def self.notify_admin_of_system_error(e)
|
481
|
+
# Shoot an email to the FM admin...
|
482
|
+
end
|
483
|
+
end
|
484
|
+
```
|
485
|
+
|
486
|
+
Since `Rescuable` uses `ActiveSupport::Rescuable` internally, you may want to
|
487
|
+
check [Rails'
|
488
|
+
documentation](https://api.rubyonrails.org/classes/ActiveSupport/Rescuable/ClassMethods.html)
|
489
|
+
too for details on how it works.
|
490
|
+
|
491
|
+
One caveat of using `rescue_from` is that it always catches exceptions at the
|
492
|
+
class level, so if you pass a method name to `with:` that method has to be a
|
493
|
+
class method. Also note that this will only catch exceptions raised during an
|
494
|
+
API call to the Data API server (in other words, only on actions that perform
|
495
|
+
an HTTP request).
|
496
|
+
|
455
497
|
## Logging
|
456
498
|
|
457
499
|
If using `fmrest-spyke` with Rails then pretty log output will be set up for
|
@@ -501,6 +543,10 @@ class LoggyBee < FmRest::Layout
|
|
501
543
|
end
|
502
544
|
```
|
503
545
|
|
546
|
+
## Gotchas
|
547
|
+
|
548
|
+
Read about unexpected scenarios in the [gotchas doc](docs/Gotchas.md).
|
549
|
+
|
504
550
|
## API implementation completeness table
|
505
551
|
|
506
552
|
FM Data API reference: https://fmhelp.filemaker.com/docs/18/en/dataapi/
|
@@ -510,7 +556,7 @@ FM Data API reference: https://fmhelp.filemaker.com/docs/18/en/dataapi/
|
|
510
556
|
| Log in using HTTP Basic Auth | Yes | Yes |
|
511
557
|
| Log in using OAuth | No | No |
|
512
558
|
| Log in to an external data source | No | No |
|
513
|
-
| Log in using
|
559
|
+
| Log in using Claris ID account | Yes | Yes |
|
514
560
|
| Log out | Yes | Yes |
|
515
561
|
| Get product information | Manual* | No |
|
516
562
|
| Get database names | Manual* | No |
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "fmrest/spyke/portal_builder"
|
3
4
|
require "fmrest/spyke/portal"
|
4
5
|
|
5
6
|
module FmRest
|
@@ -13,6 +14,8 @@ module FmRest
|
|
13
14
|
included do
|
14
15
|
# Keep track of portal options by their FM keys as we could need it
|
15
16
|
# to parse the portalData JSON in SpykeFormatter
|
17
|
+
#
|
18
|
+
# TODO: Replace this with options in PortalBuilder
|
16
19
|
class_attribute :portal_options, instance_accessor: false, instance_predicate: false
|
17
20
|
|
18
21
|
# class_attribute supports a :default option since ActiveSupport 5.2,
|
@@ -40,11 +43,13 @@ module FmRest
|
|
40
43
|
# end
|
41
44
|
#
|
42
45
|
def has_portal(name, options = {})
|
43
|
-
create_association
|
46
|
+
# This is analogous to Spyke's create_association method, but using
|
47
|
+
# our custom builder instead
|
48
|
+
self.associations = associations.merge(name => PortalBuilder.new(self, name, Portal, options))
|
44
49
|
|
45
50
|
# Store options for SpykeFormatter to use if needed
|
46
51
|
portal_key = options[:portal_key] || name
|
47
|
-
self.portal_options = portal_options.merge(portal_key.to_s => options.dup.merge(name: name.to_s)).freeze
|
52
|
+
self.portal_options = portal_options.merge(portal_key.to_s => options.dup.merge(name: name.to_s).freeze).freeze
|
48
53
|
|
49
54
|
define_method "#{name.to_s.singularize}_ids" do
|
50
55
|
association(name).map(&:id)
|
@@ -94,11 +94,17 @@ module FmRest
|
|
94
94
|
end
|
95
95
|
|
96
96
|
def _fmrest_define_attribute(from, to)
|
97
|
+
if existing_method = ((method_defined?(from) || private_method_defined?(from)) && from) ||
|
98
|
+
((method_defined?("#{from}=") || private_method_defined?("#{from}=")) && "#{from}=")
|
99
|
+
|
100
|
+
raise ArgumentError, "You tried to define an attribute named `#{from}' on `#{name}', but this will generate a instance method `#{existing_method}', which is already defined by FmRest::Layout."
|
101
|
+
end
|
102
|
+
|
97
103
|
# We use a setter here instead of injecting the hash key/value pair
|
98
104
|
# directly with #[]= so that we don't change the mapped_attributes
|
99
105
|
# hash on the parent class. The resulting hash is frozen for the
|
100
106
|
# same reason.
|
101
|
-
self.mapped_attributes = mapped_attributes.merge(from => to).freeze
|
107
|
+
self.mapped_attributes = mapped_attributes.merge(from => to.to_s).freeze
|
102
108
|
|
103
109
|
_fmrest_attribute_methods_container.module_eval do
|
104
110
|
define_method(from) do
|
@@ -6,8 +6,6 @@ module FmRest
|
|
6
6
|
module GlobalFields
|
7
7
|
extend ::ActiveSupport::Concern
|
8
8
|
|
9
|
-
FULLY_QUALIFIED_FIELD_NAME_MATCHER = /\A[^:]+::[^:]+\Z/.freeze
|
10
|
-
|
11
9
|
class_methods do
|
12
10
|
def set_globals(values_hash)
|
13
11
|
connection.patch(FmRest::V1.globals_path, {
|
@@ -26,7 +24,7 @@ module FmRest
|
|
26
24
|
next
|
27
25
|
end
|
28
26
|
|
29
|
-
unless
|
27
|
+
unless V1.is_fully_qualified?(k.to_s)
|
30
28
|
raise ArgumentError, "global fields must be given in fully qualified format (table name::field name)"
|
31
29
|
end
|
32
30
|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FmRest
|
4
|
+
module Spyke
|
5
|
+
module Model
|
6
|
+
module Rescuable
|
7
|
+
extend ::ActiveSupport::Concern
|
8
|
+
|
9
|
+
include ::ActiveSupport::Rescuable
|
10
|
+
|
11
|
+
class_methods do
|
12
|
+
def request(*args)
|
13
|
+
begin
|
14
|
+
super
|
15
|
+
rescue => e
|
16
|
+
rescue_with_handler(e) || raise
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def rescue_account_error(with: nil, &block)
|
21
|
+
rescue_from APIError::AccountError, with: with, &block
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -26,7 +26,7 @@ module FmRest
|
|
26
26
|
def serialize_for_portal(portal)
|
27
27
|
params =
|
28
28
|
changed_params.except(:__record_id).transform_keys do |key|
|
29
|
-
"#{portal.attribute_prefix}::#{key}"
|
29
|
+
V1.is_fully_qualified?(key) ? key : "#{portal.attribute_prefix}::#{key}"
|
30
30
|
end
|
31
31
|
|
32
32
|
params[:recordId] = __record_id.to_s if __record_id
|
data/lib/fmrest/spyke/model.rb
CHANGED
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FmRest
|
4
|
+
module Spyke
|
5
|
+
class PortalBuilder < ::Spyke::Associations::Builder
|
6
|
+
attr_reader :options
|
7
|
+
|
8
|
+
def klass
|
9
|
+
begin
|
10
|
+
super
|
11
|
+
rescue NameError => e
|
12
|
+
::FmRest::Layout
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -195,8 +195,8 @@ module FmRest
|
|
195
195
|
out
|
196
196
|
end
|
197
197
|
|
198
|
-
# Extracts `recordId` and strips the `"
|
199
|
-
# portal
|
198
|
+
# Extracts `recordId` and strips the `"tableName::"` field qualifier for
|
199
|
+
# each portal
|
200
200
|
#
|
201
201
|
# Sample `json_portal_data`:
|
202
202
|
#
|
@@ -210,19 +210,33 @@ module FmRest
|
|
210
210
|
# @return [Hash] the portal data in Spyke format
|
211
211
|
def prepare_portal_data(json_portal_data)
|
212
212
|
json_portal_data.each_with_object({}) do |(portal_name, portal_records), out|
|
213
|
+
|
213
214
|
portal_options = @model.portal_options[portal_name.to_s] || {}
|
215
|
+
portal_builder = @model.associations[portal_options[:name].to_sym]
|
216
|
+
portal_class = portal_builder && portal_builder.klass
|
217
|
+
portal_attributes = (portal_class && portal_class.mapped_attributes.values) || []
|
214
218
|
|
215
219
|
out[portal_name] =
|
216
220
|
portal_records.map do |portal_fields|
|
217
221
|
attributes = { __record_id: portal_fields[:recordId] }
|
218
222
|
attributes[:__mod_id] = portal_fields[:modId] if portal_fields[:modId]
|
219
223
|
|
220
|
-
|
221
|
-
|
224
|
+
qualifier = portal_options[:attribute_prefix] || portal_name
|
225
|
+
qualifier_matcher = /\A#{qualifier}::/
|
222
226
|
|
223
227
|
portal_fields.each do |k, v|
|
224
228
|
next if :recordId == k || :modId == k
|
225
|
-
|
229
|
+
|
230
|
+
stripped_field_name = k.to_s.gsub(qualifier_matcher, "")
|
231
|
+
|
232
|
+
# Only use the non-qualified attribute name if it was defined
|
233
|
+
# that way on the portal model, otherwise default to the fully
|
234
|
+
# qualified name
|
235
|
+
if portal_attributes.include?(stripped_field_name)
|
236
|
+
attributes[stripped_field_name.to_sym] = v
|
237
|
+
else
|
238
|
+
attributes[k.to_sym] = v
|
239
|
+
end
|
226
240
|
end
|
227
241
|
|
228
242
|
attributes
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fmrest-spyke
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.18.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pedro Carbajal
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-09-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fmrest-core
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 0.18.0.rc1
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: 0.18.0.rc1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: spyke
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -64,9 +64,11 @@ files:
|
|
64
64
|
- lib/fmrest/spyke/model/http.rb
|
65
65
|
- lib/fmrest/spyke/model/orm.rb
|
66
66
|
- lib/fmrest/spyke/model/record_id.rb
|
67
|
+
- lib/fmrest/spyke/model/rescuable.rb
|
67
68
|
- lib/fmrest/spyke/model/serialization.rb
|
68
69
|
- lib/fmrest/spyke/model/uri.rb
|
69
70
|
- lib/fmrest/spyke/portal.rb
|
71
|
+
- lib/fmrest/spyke/portal_builder.rb
|
70
72
|
- lib/fmrest/spyke/relation.rb
|
71
73
|
- lib/fmrest/spyke/spyke_formatter.rb
|
72
74
|
- lib/fmrest/spyke/validation_error.rb
|
@@ -85,11 +87,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
85
87
|
version: '0'
|
86
88
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
89
|
requirements:
|
88
|
-
- - "
|
90
|
+
- - ">"
|
89
91
|
- !ruby/object:Gem::Version
|
90
|
-
version:
|
92
|
+
version: 1.3.1
|
91
93
|
requirements: []
|
92
|
-
rubygems_version: 3.
|
94
|
+
rubygems_version: 3.2.3
|
93
95
|
signing_key:
|
94
96
|
specification_version: 4
|
95
97
|
summary: FileMaker Data API ORM client library
|