model_driven_api 3.11.5 → 3.12.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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '0877810a34bb2f213343f3e5f13bfee52b0cec2d8da29431c64466185078d01b'
|
|
4
|
+
data.tar.gz: d52e6f70ae1da5655ab7b5ad605c400c88ed659d84425b91e5a239506d2d9d6a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2a557cb8c023b0e98fc299c3c2334e6720faa58f2383f8f207ad53a5d00f6b66a8b92c9756d467aed8b02a21fc0beb145c5eb92d3fe20ca226de2963fe4ef7ab
|
|
7
|
+
data.tar.gz: eccaf19b8ecdf2c13283c3918ec4be6d1d8c27d4e52b1e37490ddae532720be75a03a11853f882bb14778c141198cb123f2c610a518d3397b351157e7de523b9
|
|
@@ -75,8 +75,7 @@ class Api::V2::ApplicationController < ActionController::API
|
|
|
75
75
|
# TODO: Remove it
|
|
76
76
|
# @record.user_id = current_user.id if @model.column_names.include? "user_id"
|
|
77
77
|
@record = @model.new(@body)
|
|
78
|
-
@record.
|
|
79
|
-
render json: @record.to_json(json_attrs), status: 201
|
|
78
|
+
create_once(@record) { render json: @record.to_json(json_attrs), status: 201 }
|
|
80
79
|
end
|
|
81
80
|
|
|
82
81
|
def update
|
|
@@ -210,6 +209,46 @@ class Api::V2::ApplicationController < ActionController::API
|
|
|
210
209
|
return not_found! if @record.blank?
|
|
211
210
|
end
|
|
212
211
|
|
|
212
|
+
# A model may declare `self.creation_key`: the columns identifying a record its client
|
|
213
|
+
# generated. A create whose key matches an existing record is a repeat of a creation that
|
|
214
|
+
# already happened (a client resending after a lost response), so the caller gets that
|
|
215
|
+
# record back instead of a copy.
|
|
216
|
+
def existing_by_creation_key(record)
|
|
217
|
+
return unless @model.respond_to?(:creation_key)
|
|
218
|
+
|
|
219
|
+
key = @model.creation_key.index_with { |column| record[column] }
|
|
220
|
+
return if key.values.any?(&:nil?)
|
|
221
|
+
|
|
222
|
+
@model.find_by(key)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Saves +record+ and yields to render it, unless its creation key matches an existing
|
|
226
|
+
# record, which is rendered instead (render_existing). Shared by v2 and v3, which differ
|
|
227
|
+
# only in how they render.
|
|
228
|
+
def create_once(record)
|
|
229
|
+
existing = existing_by_creation_key(record)
|
|
230
|
+
return render_existing(existing) if existing
|
|
231
|
+
|
|
232
|
+
# In its own savepoint, so a unique-index violation leaves any enclosing transaction
|
|
233
|
+
# usable for the lookup that follows it.
|
|
234
|
+
@model.transaction(requires_new: true) { record.save! }
|
|
235
|
+
yield
|
|
236
|
+
rescue ActiveRecord::RecordNotUnique
|
|
237
|
+
# A racing request with the same creation key committed between the lookup and the
|
|
238
|
+
# insert: the unique index stopped this one, so hand back what the other created.
|
|
239
|
+
existing = existing_by_creation_key(record)
|
|
240
|
+
raise unless existing
|
|
241
|
+
|
|
242
|
+
render_existing(existing)
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# Only to a caller who could read it anyway (the same check as show): a key is no
|
|
246
|
+
# credential, so guessing someone else's must not hand their record over.
|
|
247
|
+
def render_existing(existing)
|
|
248
|
+
authorize! :show, existing
|
|
249
|
+
render json: existing.to_json(json_attrs), status: 200
|
|
250
|
+
end
|
|
251
|
+
|
|
213
252
|
def json_attrs
|
|
214
253
|
# In order of importance: if you send the configuration via querystring you are ok
|
|
215
254
|
# has precedence over if you have setup the json_attrs in the model concern
|
|
@@ -34,9 +34,10 @@ class Api::V3::ApplicationController < Api::V2::ApplicationController
|
|
|
34
34
|
return render json: result, status: (status_number.presence || 200) if status == true
|
|
35
35
|
|
|
36
36
|
record = @model.new(jsonapi_attributes)
|
|
37
|
-
record
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
create_once(record) do
|
|
38
|
+
serializer = Api::V3::SerializerFactory.serializer_for(@model)
|
|
39
|
+
render json: serializer.new(record, **serializer_opts).serializable_hash, status: :created
|
|
40
|
+
end
|
|
40
41
|
end
|
|
41
42
|
|
|
42
43
|
def update
|
|
@@ -64,6 +65,13 @@ class Api::V3::ApplicationController < Api::V2::ApplicationController
|
|
|
64
65
|
|
|
65
66
|
private
|
|
66
67
|
|
|
68
|
+
# v2's read check, with a JSON:API envelope.
|
|
69
|
+
def render_existing(existing)
|
|
70
|
+
authorize! :show, existing
|
|
71
|
+
serializer = Api::V3::SerializerFactory.serializer_for(@model)
|
|
72
|
+
render json: serializer.new(existing, **serializer_opts).serializable_hash, status: :ok
|
|
73
|
+
end
|
|
74
|
+
|
|
67
75
|
def apply_filters(scope)
|
|
68
76
|
filter_params = params[:filter] || {}
|
|
69
77
|
filter_params.each do |field, value|
|