zero-rails-adapter 0.3.0 → 0.3.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 +150 -0
- data/README.md +46 -9
- data/app/controllers/zero_rails_adapter/mutations_controller.rb +5 -1
- data/lib/generators/zero_rails_adapter/install/templates/initializer.rb +3 -5
- data/lib/generators/zero_rails_adapter/mutator/templates/mutator.rb +4 -1
- data/lib/zero_rails_adapter/configuration.rb +5 -3
- data/lib/zero_rails_adapter/mutator.rb +3 -1
- data/lib/zero_rails_adapter/processor.rb +35 -7
- data/lib/zero_rails_adapter/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ab52c7684cc6471e482808ce5bcdb64b7aa63ccbf8c9ae736feb535683198204
|
|
4
|
+
data.tar.gz: f69fa8c3101e9f8fff279af69103f5980a323dc856a70dd6b436f8bb92a9b37c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a8a68b2c6bc50703669edd95cf46e9b74c0a01c6b4414723a78b07c4158d8b37ef884ae4972e0c0bf5ae684f897c2416f4d2e1b1b8beb1a2d1fd967faa8a36f0
|
|
7
|
+
data.tar.gz: 8690225768276ff9ca61478486674f90b91f3b873ed190d95dc0bb7da5aea2f3a96d32f3c74ef24cc2d21fe54e731f03b136549638d3491dff3a354d1b7fc1d6
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `zero-rails-adapter` are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
|
+
Because the project is still below 1.0, minor releases may contain breaking
|
|
7
|
+
changes; those changes are called out explicitly below.
|
|
8
|
+
|
|
9
|
+
## [Unreleased]
|
|
10
|
+
|
|
11
|
+
## [0.3.1] - 2026-07-29
|
|
12
|
+
|
|
13
|
+
### Security
|
|
14
|
+
|
|
15
|
+
- Changed request verification, authentication, and global mutation
|
|
16
|
+
authorization defaults to fail closed. Applications must now configure every
|
|
17
|
+
gate explicitly.
|
|
18
|
+
- Custom mutators without an `authorize_with` callback are rejected instead of
|
|
19
|
+
executing implicitly. The mutator generator scaffolds an explicit
|
|
20
|
+
deny-by-default callback.
|
|
21
|
+
- Generated initializers now require `ZERO_MUTATE_API_KEY` with `ENV.fetch`
|
|
22
|
+
instead of silently disabling request verification when the variable is
|
|
23
|
+
absent.
|
|
24
|
+
- Internal and database `PushFailed` responses no longer expose raw exception
|
|
25
|
+
messages. Full errors remain available to the configured server logger.
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- Persist only explicit application and validation failures before advancing
|
|
30
|
+
LMID. Database failures and unexpected Ruby exceptions now roll back the
|
|
31
|
+
mutation completely and return a retry-safe `PushFailed`, allowing the same
|
|
32
|
+
mutation ID to succeed after the underlying problem is fixed.
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- Expanded the Zero 1.8 integration contract to use PostgreSQL UUID primary
|
|
37
|
+
keys and foreign keys and to cover request verification, authentication,
|
|
38
|
+
global and mutator authorization, sanitized internal failures, unchanged
|
|
39
|
+
LMID state, and successful same-ID replay.
|
|
40
|
+
- Updated the contract's direct `ws` dependency from 8.18.3 to 8.21.1.
|
|
41
|
+
|
|
42
|
+
### Upgrade notes
|
|
43
|
+
|
|
44
|
+
Configure `request_verifier`, `authenticator`, and `authorizer` explicitly
|
|
45
|
+
before accepting mutation traffic. Add `authorize_with` to every custom
|
|
46
|
+
mutator, including mutators that intentionally rely only on the global
|
|
47
|
+
authorizer. Regenerate the initializer if the application still conditionally
|
|
48
|
+
configures `ZERO_MUTATE_API_KEY`.
|
|
49
|
+
|
|
50
|
+
## [0.3.0] - 2026-07-29
|
|
51
|
+
|
|
52
|
+
### Breaking changes
|
|
53
|
+
|
|
54
|
+
- Changed model and column exposure from permissive to fail-closed. The adapter
|
|
55
|
+
no longer discovers and publishes every Active Record model by default.
|
|
56
|
+
Applications must define `published_schema` with both the models and columns
|
|
57
|
+
that Zero may replicate.
|
|
58
|
+
- Split the former `model_provider` responsibility into `published_schema` for
|
|
59
|
+
replicated data and `crud_model_provider` for generic writes.
|
|
60
|
+
- Made generic CRUD fully opt-in. `crud_model_provider` now defaults to an empty
|
|
61
|
+
list and `crud_authorizer` denies every operation by default. Publishing a
|
|
62
|
+
model does not make it writable.
|
|
63
|
+
- Changed integer-backed Active Record enum generation from a string
|
|
64
|
+
enumeration to `number()`. String-backed Active Record enums generate
|
|
65
|
+
`string()`, while only PostgreSQL native enums generate Zero enumerations.
|
|
66
|
+
|
|
67
|
+
### Upgrade notes
|
|
68
|
+
|
|
69
|
+
Before upgrading an application from 0.2.0:
|
|
70
|
+
|
|
71
|
+
1. Replace `model_provider` with an explicit `published_schema` table-and-column
|
|
72
|
+
allowlist.
|
|
73
|
+
2. If generic CRUD is required, configure both `crud_model_provider` and
|
|
74
|
+
`crud_authorizer`. Keep them closed and use custom mutators for domain
|
|
75
|
+
operations that enforce application invariants.
|
|
76
|
+
3. Regenerate `schema.ts` and `mutators.ts`.
|
|
77
|
+
4. Generate and review the column-limited PostgreSQL publication SQL, apply it
|
|
78
|
+
through the application's normal database process, and point zero-cache at
|
|
79
|
+
that publication.
|
|
80
|
+
5. Confirm that timestamp consumers treat Zero values as Unix epoch
|
|
81
|
+
milliseconds and update any code that assumed string-valued Rails enums.
|
|
82
|
+
|
|
83
|
+
See the [README](README.md#explicit-publication-schema) for configuration
|
|
84
|
+
examples.
|
|
85
|
+
|
|
86
|
+
### Added
|
|
87
|
+
|
|
88
|
+
- Added a table-and-column publication schema with validation for primary keys,
|
|
89
|
+
sensitive credentials, framework-internal tables, unknown columns, and
|
|
90
|
+
unsupported PostgreSQL types.
|
|
91
|
+
- Added a generator for reviewable, column-limited PostgreSQL publication SQL.
|
|
92
|
+
- Added `zero_key` for stable synchronization identifiers that differ from the
|
|
93
|
+
Active Record primary key, including composite keys. Separate keys must be
|
|
94
|
+
published and backed by exact unique, non-null database indexes.
|
|
95
|
+
- Added explicit one-hop and two-hop relationship definitions for delegated,
|
|
96
|
+
polymorphic, through, custom-key, and other associations Rails cannot safely
|
|
97
|
+
infer.
|
|
98
|
+
- Added an exact Zero 1.8 integration contract using PostgreSQL logical
|
|
99
|
+
replication, zero-cache, a Rails custom-mutator endpoint, and a real Zero
|
|
100
|
+
client.
|
|
101
|
+
- Added coverage for replication queries, LMID advancement, duplicate
|
|
102
|
+
mutations, failed-mutation skipping, and `_zero_cleanupResults`.
|
|
103
|
+
|
|
104
|
+
### Changed
|
|
105
|
+
|
|
106
|
+
- Generic update and destroy now locate records through the configured Zero
|
|
107
|
+
key. Generic updates cannot change either the Zero key or the Active Record
|
|
108
|
+
primary key.
|
|
109
|
+
- TypeScript generation now uses `published_schema` for tables and columns and
|
|
110
|
+
generates CRUD mutators only for models returned by `crud_model_provider`.
|
|
111
|
+
- Timestamps are explicitly documented and generated as Unix epoch
|
|
112
|
+
milliseconds on the Zero side.
|
|
113
|
+
- Manual relationships override inferred relationships with the same source
|
|
114
|
+
and name.
|
|
115
|
+
|
|
116
|
+
### Security
|
|
117
|
+
|
|
118
|
+
- Added default rejection for known credential columns such as password hashes
|
|
119
|
+
and token digests, authentication tables, Active Storage internals, and
|
|
120
|
+
Action Mailbox internals.
|
|
121
|
+
- Publication validation rejects unsupported PostgreSQL types, including
|
|
122
|
+
`citext`; applications must exclude those columns or publish a supported safe
|
|
123
|
+
mirror column.
|
|
124
|
+
- Prevented schema generation and PostgreSQL publication generation from
|
|
125
|
+
silently exposing newly discovered Active Record models or columns.
|
|
126
|
+
|
|
127
|
+
## [0.2.0] - 2026-07-28
|
|
128
|
+
|
|
129
|
+
### Added
|
|
130
|
+
|
|
131
|
+
- Initial public release.
|
|
132
|
+
- Added a mountable Rails Engine with Zero mutation endpoints.
|
|
133
|
+
- Added generic Active Record create, update, and destroy operations using
|
|
134
|
+
validations, callbacks, associations, database constraints, and Rails
|
|
135
|
+
transactions.
|
|
136
|
+
- Added explicit custom mutators through a Ruby DSL, base class, registry, and
|
|
137
|
+
Rails generator.
|
|
138
|
+
- Added configurable request verification, authentication, authorization,
|
|
139
|
+
model resolution, writable-attribute policies, and transaction storage.
|
|
140
|
+
- Added atomic Zero LMID tracking, mutation ordering, duplicate detection,
|
|
141
|
+
structured application errors, failed-mutation skipping, and cleanup-result
|
|
142
|
+
handling.
|
|
143
|
+
- Added TypeScript schema and mutator generation from Active Record models.
|
|
144
|
+
- Added Active Support mutation notifications and Rails/PostgreSQL test
|
|
145
|
+
coverage.
|
|
146
|
+
|
|
147
|
+
[Unreleased]: https://github.com/mechiland/zero_rails_adapter/compare/v0.3.1...HEAD
|
|
148
|
+
[0.3.1]: https://github.com/mechiland/zero_rails_adapter/compare/v0.3.0...v0.3.1
|
|
149
|
+
[0.3.0]: https://github.com/mechiland/zero_rails_adapter/releases/tag/v0.3.0
|
|
150
|
+
[0.2.0]: https://rubygems.org/gems/zero-rails-adapter/versions/0.2.0
|
data/README.md
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
`zero-rails-adapter` is a mountable Rails Engine that maps Rocicorp Zero custom
|
|
4
4
|
mutations directly to existing Active Record models.
|
|
5
5
|
|
|
6
|
+
See the [changelog](CHANGELOG.md) for release notes and upgrade instructions.
|
|
7
|
+
|
|
6
8
|
The default CRUD path does not require a Ruby Mutator class for every model:
|
|
7
9
|
|
|
8
10
|
| Zero mutation | Rails call |
|
|
@@ -48,6 +50,10 @@ bundle install
|
|
|
48
50
|
bin/rails generate zero_rails_adapter:install
|
|
49
51
|
```
|
|
50
52
|
|
|
53
|
+
The generated initializer reads `ZERO_MUTATE_API_KEY` with `ENV.fetch`, so a
|
|
54
|
+
missing key fails during application boot instead of disabling request
|
|
55
|
+
verification.
|
|
56
|
+
|
|
51
57
|
Mount the Engine:
|
|
52
58
|
|
|
53
59
|
```ruby
|
|
@@ -283,6 +289,17 @@ and writable-attribute interfaces below.
|
|
|
283
289
|
The generated initializer supports `ZERO_MUTATE_API_KEY` and verifies
|
|
284
290
|
zero-cache's `X-Api-Key` header using a constant-time comparison.
|
|
285
291
|
|
|
292
|
+
All mutation security gates fail closed by default:
|
|
293
|
+
|
|
294
|
+
- `request_verifier` returns `false`.
|
|
295
|
+
- `authenticator` raises `UnauthorizedError`.
|
|
296
|
+
- The global `authorizer` returns `false`.
|
|
297
|
+
- The generic CRUD `crud_authorizer` returns `false`.
|
|
298
|
+
|
|
299
|
+
Applications must configure each gate they use explicitly. An application that
|
|
300
|
+
intentionally permits anonymous identities must still install an authenticator
|
|
301
|
+
that returns `ZeroRailsAdapter::Identity.new`.
|
|
302
|
+
|
|
286
303
|
The authentication interface receives the Rails request. It can integrate with
|
|
287
304
|
Devise/Warden, any JWT library, a session, or an application-specific
|
|
288
305
|
authentication system:
|
|
@@ -307,6 +324,10 @@ authorizer then receives the model class as `target` for create, or the loaded
|
|
|
307
324
|
record for update and destroy:
|
|
308
325
|
|
|
309
326
|
```ruby
|
|
327
|
+
config.authorizer = lambda do |context, mutation|
|
|
328
|
+
MutationPolicy.allowed?(context.current_user, mutation.name)
|
|
329
|
+
end
|
|
330
|
+
|
|
310
331
|
config.crud_authorizer = lambda do |context, action, target, attributes|
|
|
311
332
|
MutationPolicy.new(
|
|
312
333
|
context.current_user,
|
|
@@ -370,6 +391,10 @@ available:
|
|
|
370
391
|
ZeroRailsAdapter.define_mutator "projects.archive" do
|
|
371
392
|
attribute :id, :string
|
|
372
393
|
|
|
394
|
+
authorize_with do |context|
|
|
395
|
+
context.current_user.present?
|
|
396
|
+
end
|
|
397
|
+
|
|
373
398
|
perform do
|
|
374
399
|
Project.find(id).archive!(actor: context.current_user)
|
|
375
400
|
end
|
|
@@ -377,7 +402,9 @@ end
|
|
|
377
402
|
```
|
|
378
403
|
|
|
379
404
|
Mutators use Active Model attributes and validations and share a transaction
|
|
380
|
-
with application writes and LMID tracking.
|
|
405
|
+
with application writes and LMID tracking. A custom mutator without an
|
|
406
|
+
`authorize_with` callback is rejected. To rely intentionally on the global
|
|
407
|
+
authorizer alone, the mutator must still declare `authorize_with { true }`.
|
|
381
408
|
|
|
382
409
|
## Mutation Ordering and Transaction Semantics
|
|
383
410
|
|
|
@@ -389,11 +416,19 @@ For each `(schema, clientGroupID, clientID)`, the adapter:
|
|
|
389
416
|
4. Executes the authorized Active Record operation inside a transaction.
|
|
390
417
|
5. Updates the LMID atomically.
|
|
391
418
|
|
|
392
|
-
When
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
419
|
+
When an explicit `ApplicationError`, argument validation error, or supported
|
|
420
|
+
Active Model/Active Record validation or lifecycle error occurs, the first
|
|
421
|
+
transaction rolls back. A second transaction advances the LMID and stores a
|
|
422
|
+
structured `app` result so that a bad mutation is not retried forever and later
|
|
423
|
+
mutations can continue.
|
|
424
|
+
|
|
425
|
+
Database failures and unexpected Ruby exceptions do not advance LMID or store
|
|
426
|
+
a mutation result. They return a retry-safe `PushFailed`, so the same mutation
|
|
427
|
+
ID can be retried after the underlying problem is fixed. Public database and
|
|
428
|
+
internal failure messages are fixed and sanitized; the configured server
|
|
429
|
+
logger receives the original exception and backtrace. If persisting an
|
|
430
|
+
application failure also fails, the adapter likewise returns `PushFailed`
|
|
431
|
+
without advancing LMID.
|
|
397
432
|
|
|
398
433
|
Each mutation owns an independent transaction. A later failure in the same
|
|
399
434
|
HTTP batch does not roll back earlier committed mutations.
|
|
@@ -446,9 +481,11 @@ bundle exec rake contract
|
|
|
446
481
|
|
|
447
482
|
That task compiles the generated TypeScript, starts PostgreSQL with logical
|
|
448
483
|
replication, starts the real zero-cache and Rails mutation endpoint, then uses
|
|
449
|
-
a Zero client to mutate and query replicated rows. The generated fixture
|
|
450
|
-
includes a separate Zero key and a two-hop
|
|
451
|
-
|
|
484
|
+
a Zero client to mutate and query replicated rows. The generated fixture uses
|
|
485
|
+
UUID primary and foreign keys and includes a separate Zero key and a two-hop
|
|
486
|
+
relationship. The task also verifies request verification, authentication,
|
|
487
|
+
global and mutator authorization, sanitized retry-safe failures, same-ID
|
|
488
|
+
replay, LMID advancement, duplicate-mutation handling, failure skipping, and
|
|
452
489
|
`_zero_cleanupResults`. The contract runs as its own CI job.
|
|
453
490
|
|
|
454
491
|
See [`examples/nextjs`](examples/nextjs) for a Next.js integration fixture.
|
|
@@ -27,7 +27,11 @@ module ZeroRailsAdapter
|
|
|
27
27
|
ZeroRailsAdapter.configuration.logger&.error(
|
|
28
28
|
"ZeroRailsAdapter request failed: #{error.class}: #{error.message}"
|
|
29
29
|
)
|
|
30
|
-
render json: push_failed(
|
|
30
|
+
render json: push_failed(
|
|
31
|
+
"internal",
|
|
32
|
+
Processor::INTERNAL_ERROR_MESSAGE,
|
|
33
|
+
[]
|
|
34
|
+
), status: :internal_server_error
|
|
31
35
|
end
|
|
32
36
|
|
|
33
37
|
private
|
|
@@ -6,11 +6,9 @@ ZeroRailsAdapter.configure do |config|
|
|
|
6
6
|
|
|
7
7
|
# Verify that calls came from your zero-cache instance.
|
|
8
8
|
# Configure zero-cache with ZERO_MUTATE_API_KEY using the same value.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
)
|
|
13
|
-
end
|
|
9
|
+
config.request_verifier = ZeroRailsAdapter::RequestVerifiers::ApiKey.new(
|
|
10
|
+
key: ENV.fetch("ZERO_MUTATE_API_KEY")
|
|
11
|
+
)
|
|
14
12
|
|
|
15
13
|
# Return an Identity from any authentication system (Devise, JWT, cookies, etc.).
|
|
16
14
|
# config.authenticator = lambda do |request|
|
|
@@ -7,8 +7,11 @@ class <%= class_name %> < ZeroRailsAdapter::Mutator
|
|
|
7
7
|
# attribute :title, :string
|
|
8
8
|
# validates :title, presence: true
|
|
9
9
|
|
|
10
|
+
authorize_with do |_context|
|
|
11
|
+
false
|
|
12
|
+
end
|
|
13
|
+
|
|
10
14
|
def perform
|
|
11
|
-
# Use context.current_user, context.user_id, and context.claims for authorization.
|
|
12
15
|
raise NotImplementedError
|
|
13
16
|
end
|
|
14
17
|
end
|
|
@@ -9,9 +9,11 @@ module ZeroRailsAdapter
|
|
|
9
9
|
:relationship_provider
|
|
10
10
|
|
|
11
11
|
def initialize
|
|
12
|
-
@authenticator =
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
@authenticator = lambda do |_request|
|
|
13
|
+
raise UnauthorizedError, "Authentication is not configured"
|
|
14
|
+
end
|
|
15
|
+
@request_verifier = ->(_request) { false }
|
|
16
|
+
@authorizer = ->(_context, _mutation) { false }
|
|
15
17
|
@crud_authorizer = ->(_context, _action, _target, _attributes) { false }
|
|
16
18
|
@logger = defined?(Rails) ? Rails.logger : nil
|
|
17
19
|
@transaction_class = ActiveRecord::Base
|
|
@@ -61,7 +61,9 @@ module ZeroRailsAdapter
|
|
|
61
61
|
|
|
62
62
|
def authorize!
|
|
63
63
|
callback = self.class.authorization_callback
|
|
64
|
-
|
|
64
|
+
unless callback
|
|
65
|
+
raise ForbiddenError, "Mutator authorization is not configured"
|
|
66
|
+
end
|
|
65
67
|
return true if instance_exec(context, &callback)
|
|
66
68
|
|
|
67
69
|
raise ForbiddenError, "Mutation is not authorized"
|
|
@@ -3,6 +3,16 @@
|
|
|
3
3
|
module ZeroRailsAdapter
|
|
4
4
|
class Processor
|
|
5
5
|
CLEANUP_MUTATION_NAME = "_zero_cleanupResults"
|
|
6
|
+
DATABASE_ERROR_MESSAGE = "Database error"
|
|
7
|
+
INTERNAL_ERROR_MESSAGE = "Internal server error"
|
|
8
|
+
PERSISTABLE_MUTATION_ERRORS = [
|
|
9
|
+
ActiveModel::UnknownAttributeError,
|
|
10
|
+
ActiveModel::ValidationError,
|
|
11
|
+
ActiveRecord::RecordInvalid,
|
|
12
|
+
ActiveRecord::RecordNotDestroyed,
|
|
13
|
+
ActiveRecord::RecordNotFound,
|
|
14
|
+
ActiveRecord::RecordNotSaved
|
|
15
|
+
].freeze
|
|
6
16
|
|
|
7
17
|
attr_reader :request, :context, :storage
|
|
8
18
|
|
|
@@ -47,16 +57,20 @@ module ZeroRailsAdapter
|
|
|
47
57
|
mutation_ids: request.mutation_ids.drop(processed_count)
|
|
48
58
|
)
|
|
49
59
|
rescue ActiveRecord::ActiveRecordError => error
|
|
60
|
+
mutation_ids = request.mutation_ids.drop(processed_count)
|
|
61
|
+
log_push_failure(error, reason: "database", mutation_ids:)
|
|
50
62
|
push_failed(
|
|
51
63
|
reason: "database",
|
|
52
|
-
message:
|
|
53
|
-
mutation_ids:
|
|
64
|
+
message: DATABASE_ERROR_MESSAGE,
|
|
65
|
+
mutation_ids:
|
|
54
66
|
)
|
|
55
67
|
rescue StandardError => error
|
|
68
|
+
mutation_ids = request.mutation_ids.drop(processed_count)
|
|
69
|
+
log_push_failure(error, reason: "internal", mutation_ids:)
|
|
56
70
|
push_failed(
|
|
57
71
|
reason: "internal",
|
|
58
|
-
message:
|
|
59
|
-
mutation_ids:
|
|
72
|
+
message: INTERNAL_ERROR_MESSAGE,
|
|
73
|
+
mutation_ids:
|
|
60
74
|
)
|
|
61
75
|
end
|
|
62
76
|
|
|
@@ -84,7 +98,7 @@ module ZeroRailsAdapter
|
|
|
84
98
|
already_processed_response(mutation, error)
|
|
85
99
|
rescue OutOfOrderMutationError
|
|
86
100
|
raise
|
|
87
|
-
rescue
|
|
101
|
+
rescue ApplicationError, *PERSISTABLE_MUTATION_ERRORS => error
|
|
88
102
|
application_error = normalize_application_error(error)
|
|
89
103
|
begin
|
|
90
104
|
persist_failure(mutation, application_error)
|
|
@@ -138,8 +152,10 @@ module ZeroRailsAdapter
|
|
|
138
152
|
def normalize_application_error(error)
|
|
139
153
|
return error if error.is_a?(ApplicationError)
|
|
140
154
|
|
|
141
|
-
|
|
142
|
-
|
|
155
|
+
model = error.record if error.respond_to?(:record)
|
|
156
|
+
model ||= error.model if error.respond_to?(:model)
|
|
157
|
+
if model.respond_to?(:errors)
|
|
158
|
+
return ApplicationError.new(error.message, details: model.errors.to_hash)
|
|
143
159
|
end
|
|
144
160
|
|
|
145
161
|
ApplicationError.new(error.message)
|
|
@@ -174,5 +190,17 @@ module ZeroRailsAdapter
|
|
|
174
190
|
"mutationIDs" => mutation_ids
|
|
175
191
|
}
|
|
176
192
|
end
|
|
193
|
+
|
|
194
|
+
def log_push_failure(error, reason:, mutation_ids:)
|
|
195
|
+
ZeroRailsAdapter.configuration.logger&.error(
|
|
196
|
+
"ZeroRailsAdapter push failed: " \
|
|
197
|
+
"reason=#{reason} request_id=#{request.request_id.inspect} " \
|
|
198
|
+
"mutation_ids=#{mutation_ids.inspect} " \
|
|
199
|
+
"#{error.class}: #{error.message}\n" \
|
|
200
|
+
"#{Array(error.backtrace).join("\n")}"
|
|
201
|
+
)
|
|
202
|
+
rescue StandardError
|
|
203
|
+
nil
|
|
204
|
+
end
|
|
177
205
|
end
|
|
178
206
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: zero-rails-adapter
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Zero Rails Adapter contributors
|
|
@@ -35,6 +35,7 @@ executables: []
|
|
|
35
35
|
extensions: []
|
|
36
36
|
extra_rdoc_files: []
|
|
37
37
|
files:
|
|
38
|
+
- CHANGELOG.md
|
|
38
39
|
- LICENSE.txt
|
|
39
40
|
- README.md
|
|
40
41
|
- app/controllers/zero_rails_adapter/mutations_controller.rb
|
|
@@ -87,7 +88,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
87
88
|
- !ruby/object:Gem::Version
|
|
88
89
|
version: '0'
|
|
89
90
|
requirements: []
|
|
90
|
-
rubygems_version: 4.0.
|
|
91
|
+
rubygems_version: 4.0.16
|
|
91
92
|
specification_version: 4
|
|
92
93
|
summary: A Rails 8 Active Record adapter for Rocicorp Zero
|
|
93
94
|
test_files: []
|