graphiti 1.13.4 → 2.0.0.beta.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.
@@ -7,8 +7,12 @@ class Graphiti::Util::Persistence
7
7
  # @param [Hash] relationships see (Deserializer#relationships)
8
8
  # @param [Model] caller_model The persisted parent object in the request graph
9
9
  # @param [Symbol] foreign_key Attribute assigned by parent object in graph
10
- def initialize(resource, meta, attributes, relationships, caller_model, foreign_key = nil)
10
+ # @param [Model] assigned_model a model already built by #assign, to be
11
+ # assigned onto rather than rebuilt
12
+ # TODO: make foreign_key a keyword once the satellite gems are rolled in
13
+ def initialize(resource, meta, attributes, relationships, caller_model, foreign_key = nil, assigned_model: nil)
11
14
  @resource = resource
15
+ @assigned_model = assigned_model
12
16
  @meta = meta
13
17
  @attributes = attributes
14
18
  @relationships = relationships
@@ -24,6 +28,14 @@ class Graphiti::Util::Persistence
24
28
  end
25
29
  end
26
30
 
31
+ def assign
32
+ attributes = @adapter.persistence_attributes(self, @attributes)
33
+ assigned = @resource.assign(attributes, metadata, @meta[:method], model_instance: @assigned_model)
34
+ @resource.decorate_record(assigned)
35
+
36
+ assigned
37
+ end
38
+
27
39
  # Perform the actual save logic.
28
40
  #
29
41
  # belongs_to must be processed before/separately from has_many -
@@ -46,11 +58,13 @@ class Graphiti::Util::Persistence
46
58
  def run
47
59
  attributes = @adapter.persistence_attributes(self, @attributes)
48
60
 
61
+ payload_attributes = attributes.dup
49
62
  parents = @adapter.process_belongs_to(self, attributes)
63
+ apply_derived_attributes(attributes, payload_attributes)
50
64
  persisted = persist_object(@meta[:method], attributes)
51
65
  @resource.decorate_record(persisted)
52
- assign_temp_id(persisted, @meta[:temp_id])
53
66
 
67
+ assign_temp_id(persisted, @meta[:temp_id])
54
68
  associate_parents(persisted, parents)
55
69
 
56
70
  children = @adapter.process_has_many(self, persisted)
@@ -81,6 +95,19 @@ class Graphiti::Util::Persistence
81
95
 
82
96
  private
83
97
 
98
+ # process_belongs_to persists the parents and writes their primary keys into
99
+ # +attributes+. A model that was already assigned (see ResourceProxy#assign_attributes)
100
+ # predates those keys, so apply just them - the payload attributes are already on it,
101
+ # and re-applying them would clobber any changes made since.
102
+ def apply_derived_attributes(attributes, payload_attributes)
103
+ return unless @assigned_model
104
+
105
+ derived = attributes.reject { |key, value| payload_attributes[key] == value }
106
+ return if derived.empty?
107
+
108
+ @resource.assign_attributes(@assigned_model, derived, metadata)
109
+ end
110
+
84
111
  def add_hook(prc, lifecycle_event)
85
112
  ::Graphiti::Util::TransactionHooksRecorder.add(prc, lifecycle_event)
86
113
  end
@@ -163,10 +190,19 @@ class Graphiti::Util::Persistence
163
190
  }
164
191
  end
165
192
 
193
+ def accepts_assigned_model?(method)
194
+ method.parameters.any? { |type, name| name == :assigned_model && [:key, :keyreq].include?(type) }
195
+ end
196
+
166
197
  def call_resource_method(method_name, attributes, caller_model)
167
198
  method = @resource.method(method_name)
168
199
 
169
- if method.arity == 1
200
+ if @assigned_model && [:create, :update].include?(method_name)
201
+ unless accepts_assigned_model?(method)
202
+ raise Graphiti::Errors::AssignedModelNotSupported.new(@resource.class, method_name)
203
+ end
204
+ method.call(attributes, metadata, assigned_model: @assigned_model)
205
+ elsif method.arity == 1
170
206
  method.call(attributes)
171
207
  else
172
208
  method.call(attributes, metadata)
@@ -1,3 +1,3 @@
1
1
  module Graphiti
2
- VERSION = "1.13.4"
2
+ VERSION = "2.0.0.beta.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphiti
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.13.4
4
+ version: 2.0.0.beta.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lee Richmond
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-08-20 00:00:00.000000000 Z
11
+ date: 2026-07-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jsonapi-serializable
@@ -248,6 +248,7 @@ files:
248
248
  - LICENSE.txt
249
249
  - README.md
250
250
  - Rakefile
251
+ - UPGRADING.md
251
252
  - bin/appraisal
252
253
  - bin/console
253
254
  - bin/rspec
@@ -269,8 +270,6 @@ files:
269
270
  - deprecated_generators/graphiti/templates/update_request_spec.rb.erb
270
271
  - exe/graphiti
271
272
  - gemfiles/.bundle/config
272
- - gemfiles/rails_5_2.gemfile
273
- - gemfiles/rails_5_2_graphiti_rails.gemfile
274
273
  - gemfiles/rails_6.gemfile
275
274
  - gemfiles/rails_6_graphiti_rails.gemfile
276
275
  - gemfiles/rails_7.gemfile
@@ -371,7 +370,14 @@ homepage: https://github.com/graphiti-api/graphiti
371
370
  licenses:
372
371
  - MIT
373
372
  metadata: {}
374
- post_install_message:
373
+ post_install_message: "Graphiti: relationship readable:/writable: guards are now enforced.\n\nSymbols,
374
+ strings, and procs passed to a relationship's readable/writable\nguards were always
375
+ interpreted as true and never actually called before this\nconditional relationship
376
+ change. They are now evaluated per-request, where\nunreadable relationships are
377
+ omitted from responses and includes, and unwritable\nrelationships reject writes.\n\nTo
378
+ list every affected relationship in your app:\n\n bin/rails runner 'puts Graphiti.guarded_relationships'\n\nAudit
379
+ these before deploying. Apps using schema.json will also see affected \nrelationships
380
+ flagged as \"became guarded\" by the schema check.\n"
375
381
  rdoc_options: []
376
382
  require_paths:
377
383
  - lib
@@ -379,12 +385,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
379
385
  requirements:
380
386
  - - ">="
381
387
  - !ruby/object:Gem::Version
382
- version: '2.7'
388
+ version: '3.0'
383
389
  required_rubygems_version: !ruby/object:Gem::Requirement
384
390
  requirements:
385
- - - ">="
391
+ - - ">"
386
392
  - !ruby/object:Gem::Version
387
- version: '0'
393
+ version: 1.3.1
388
394
  requirements: []
389
395
  rubygems_version: 3.3.27
390
396
  signing_key:
@@ -1,18 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "rails", "~> 5.2.0"
6
- gem "rspec-rails"
7
- gem "sqlite3", "~> 1.4.0"
8
- gem "database_cleaner"
9
-
10
- group :test do
11
- gem "pry"
12
- gem "pry-byebug", platform: [:mri]
13
- gem "appraisal"
14
- gem "guard"
15
- gem "guard-rspec"
16
- end
17
-
18
- gemspec path: "../"
@@ -1,19 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "rails", "~> 5.2.0"
6
- gem "rspec-rails"
7
- gem "sqlite3", "~> 1.4.0"
8
- gem "database_cleaner"
9
- gem "graphiti-rails", "~> 0.4.0"
10
-
11
- group :test do
12
- gem "pry"
13
- gem "pry-byebug", platform: [:mri]
14
- gem "appraisal"
15
- gem "guard"
16
- gem "guard-rspec"
17
- end
18
-
19
- gemspec path: "../"