jsonapi-resources 0.9.0 → 0.10.6

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.
Files changed (44) hide show
  1. checksums.yaml +5 -5
  2. data/LICENSE.txt +1 -1
  3. data/README.md +34 -11
  4. data/lib/bug_report_templates/rails_5_latest.rb +125 -0
  5. data/lib/bug_report_templates/rails_5_master.rb +140 -0
  6. data/lib/jsonapi/active_relation/adapters/join_left_active_record_adapter.rb +27 -0
  7. data/lib/jsonapi/active_relation/join_manager.rb +303 -0
  8. data/lib/jsonapi/active_relation_resource.rb +884 -0
  9. data/lib/jsonapi/acts_as_resource_controller.rb +122 -105
  10. data/lib/jsonapi/basic_resource.rb +1162 -0
  11. data/lib/jsonapi/cached_response_fragment.rb +127 -0
  12. data/lib/jsonapi/compiled_json.rb +11 -1
  13. data/lib/jsonapi/configuration.rb +71 -8
  14. data/lib/jsonapi/error.rb +27 -0
  15. data/lib/jsonapi/error_codes.rb +2 -0
  16. data/lib/jsonapi/exceptions.rb +80 -50
  17. data/lib/jsonapi/formatter.rb +3 -3
  18. data/lib/jsonapi/include_directives.rb +18 -65
  19. data/lib/jsonapi/link_builder.rb +74 -80
  20. data/lib/jsonapi/operation.rb +16 -5
  21. data/lib/jsonapi/operation_result.rb +74 -16
  22. data/lib/jsonapi/path.rb +43 -0
  23. data/lib/jsonapi/path_segment.rb +76 -0
  24. data/lib/jsonapi/processor.rb +239 -111
  25. data/lib/jsonapi/relationship.rb +153 -15
  26. data/lib/jsonapi/request_parser.rb +430 -367
  27. data/lib/jsonapi/resource.rb +3 -1253
  28. data/lib/jsonapi/resource_controller_metal.rb +5 -2
  29. data/lib/jsonapi/resource_fragment.rb +47 -0
  30. data/lib/jsonapi/resource_id_tree.rb +112 -0
  31. data/lib/jsonapi/resource_identity.rb +42 -0
  32. data/lib/jsonapi/resource_serializer.rb +143 -285
  33. data/lib/jsonapi/resource_set.rb +176 -0
  34. data/lib/jsonapi/resources/railtie.rb +9 -0
  35. data/lib/jsonapi/resources/version.rb +1 -1
  36. data/lib/jsonapi/response_document.rb +105 -83
  37. data/lib/jsonapi/routing_ext.rb +48 -26
  38. data/lib/jsonapi-resources.rb +20 -4
  39. data/lib/tasks/check_upgrade.rake +52 -0
  40. metadata +50 -20
  41. data/lib/jsonapi/cached_resource_fragment.rb +0 -127
  42. data/lib/jsonapi/operation_dispatcher.rb +0 -88
  43. data/lib/jsonapi/operation_results.rb +0 -35
  44. data/lib/jsonapi/relationship_builder.rb +0 -167
@@ -0,0 +1,52 @@
1
+ require 'rake'
2
+ require 'jsonapi-resources'
3
+
4
+ namespace :jsonapi do
5
+ namespace :resources do
6
+ desc 'Checks application for orphaned overrides'
7
+ task :check_upgrade => :environment do
8
+ Rails.application.eager_load!
9
+
10
+ resource_klasses = ObjectSpace.each_object(Class).select { |klass| klass < JSONAPI::Resource}
11
+
12
+ puts "Checking #{resource_klasses.count} resources"
13
+
14
+ issues_found = 0
15
+
16
+ klasses_with_deprecated = resource_klasses.select { |klass| klass.methods.include?(:find_records) }
17
+ unless klasses_with_deprecated.empty?
18
+ puts " Found the following resources the still implement `find_records`:"
19
+ klasses_with_deprecated.each { |klass| puts " #{klass}"}
20
+ puts " The `find_records` method is no longer called by JR. Please review and ensure your functionality is ported over."
21
+
22
+ issues_found = issues_found + klasses_with_deprecated.length
23
+ end
24
+
25
+ klasses_with_deprecated = resource_klasses.select { |klass| klass.methods.include?(:records_for) }
26
+ unless klasses_with_deprecated.empty?
27
+ puts " Found the following resources the still implement `records_for`:"
28
+ klasses_with_deprecated.each { |klass| puts " #{klass}"}
29
+ puts " The `records_for` method is no longer called by JR. Please review and ensure your functionality is ported over."
30
+
31
+ issues_found = issues_found + klasses_with_deprecated.length
32
+ end
33
+
34
+ klasses_with_deprecated = resource_klasses.select { |klass| klass.methods.include?(:apply_includes) }
35
+ unless klasses_with_deprecated.empty?
36
+ puts " Found the following resources the still implement `apply_includes`:"
37
+ klasses_with_deprecated.each { |klass| puts " #{klass}"}
38
+ puts " The `apply_includes` method is no longer called by JR. Please review and ensure your functionality is ported over."
39
+
40
+ issues_found = issues_found + klasses_with_deprecated.length
41
+ end
42
+
43
+ if issues_found > 0
44
+ puts "Finished inspection. #{issues_found} issues found that may impact upgrading. Please address these issues. "
45
+ else
46
+ puts "Finished inspection with no issues found. Note this is only a cursory check for method overrides that will no \n" \
47
+ "longer be called by JSONAPI::Resources. This check in no way assures your code will continue to function as \n" \
48
+ "it did before the upgrade. Please do adequate testing before using in production."
49
+ end
50
+ end
51
+ end
52
+ end
metadata CHANGED
@@ -1,30 +1,30 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonapi-resources
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Gebhardt
8
8
  - Larry Gebhardt
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-02-14 00:00:00.000000000 Z
12
+ date: 2022-02-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - "~>"
18
+ - - ">="
19
19
  - !ruby/object:Gem::Version
20
- version: '1.5'
20
+ version: '1.17'
21
21
  type: :development
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - "~>"
25
+ - - ">="
26
26
  - !ruby/object:Gem::Version
27
- version: '1.5'
27
+ version: '1.17'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: rake
30
30
  requirement: !ruby/object:Gem::Requirement
@@ -43,16 +43,22 @@ dependencies:
43
43
  name: minitest
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - ">="
46
+ - - "~>"
47
47
  - !ruby/object:Gem::Version
48
- version: '0'
48
+ version: '5.10'
49
+ - - "!="
50
+ - !ruby/object:Gem::Version
51
+ version: 5.10.2
49
52
  type: :development
50
53
  prerelease: false
51
54
  version_requirements: !ruby/object:Gem::Requirement
52
55
  requirements:
53
- - - ">="
56
+ - - "~>"
54
57
  - !ruby/object:Gem::Version
55
- version: '0'
58
+ version: '5.10'
59
+ - - "!="
60
+ - !ruby/object:Gem::Version
61
+ version: 5.10.2
56
62
  - !ruby/object:Gem::Dependency
57
63
  name: minitest-spec-rails
58
64
  requirement: !ruby/object:Gem::Requirement
@@ -109,6 +115,20 @@ dependencies:
109
115
  - - ">="
110
116
  - !ruby/object:Gem::Version
111
117
  version: '0'
118
+ - !ruby/object:Gem::Dependency
119
+ name: database_cleaner
120
+ requirement: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ type: :development
126
+ prerelease: false
127
+ version_requirements: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
112
132
  - !ruby/object:Gem::Dependency
113
133
  name: activerecord
114
134
  requirement: !ruby/object:Gem::Requirement
@@ -162,14 +182,20 @@ extra_rdoc_files: []
162
182
  files:
163
183
  - LICENSE.txt
164
184
  - README.md
185
+ - lib/bug_report_templates/rails_5_latest.rb
186
+ - lib/bug_report_templates/rails_5_master.rb
165
187
  - lib/generators/jsonapi/USAGE
166
188
  - lib/generators/jsonapi/controller_generator.rb
167
189
  - lib/generators/jsonapi/resource_generator.rb
168
190
  - lib/generators/jsonapi/templates/jsonapi_controller.rb
169
191
  - lib/generators/jsonapi/templates/jsonapi_resource.rb
170
192
  - lib/jsonapi-resources.rb
193
+ - lib/jsonapi/active_relation/adapters/join_left_active_record_adapter.rb
194
+ - lib/jsonapi/active_relation/join_manager.rb
195
+ - lib/jsonapi/active_relation_resource.rb
171
196
  - lib/jsonapi/acts_as_resource_controller.rb
172
- - lib/jsonapi/cached_resource_fragment.rb
197
+ - lib/jsonapi/basic_resource.rb
198
+ - lib/jsonapi/cached_response_fragment.rb
173
199
  - lib/jsonapi/callbacks.rb
174
200
  - lib/jsonapi/compiled_json.rb
175
201
  - lib/jsonapi/configuration.rb
@@ -182,26 +208,31 @@ files:
182
208
  - lib/jsonapi/mime_types.rb
183
209
  - lib/jsonapi/naive_cache.rb
184
210
  - lib/jsonapi/operation.rb
185
- - lib/jsonapi/operation_dispatcher.rb
186
211
  - lib/jsonapi/operation_result.rb
187
- - lib/jsonapi/operation_results.rb
188
212
  - lib/jsonapi/paginator.rb
213
+ - lib/jsonapi/path.rb
214
+ - lib/jsonapi/path_segment.rb
189
215
  - lib/jsonapi/processor.rb
190
216
  - lib/jsonapi/relationship.rb
191
- - lib/jsonapi/relationship_builder.rb
192
217
  - lib/jsonapi/request_parser.rb
193
218
  - lib/jsonapi/resource.rb
194
219
  - lib/jsonapi/resource_controller.rb
195
220
  - lib/jsonapi/resource_controller_metal.rb
221
+ - lib/jsonapi/resource_fragment.rb
222
+ - lib/jsonapi/resource_id_tree.rb
223
+ - lib/jsonapi/resource_identity.rb
196
224
  - lib/jsonapi/resource_serializer.rb
225
+ - lib/jsonapi/resource_set.rb
226
+ - lib/jsonapi/resources/railtie.rb
197
227
  - lib/jsonapi/resources/version.rb
198
228
  - lib/jsonapi/response_document.rb
199
229
  - lib/jsonapi/routing_ext.rb
230
+ - lib/tasks/check_upgrade.rake
200
231
  homepage: https://github.com/cerebris/jsonapi-resources
201
232
  licenses:
202
233
  - MIT
203
234
  metadata: {}
204
- post_install_message:
235
+ post_install_message:
205
236
  rdoc_options: []
206
237
  require_paths:
207
238
  - lib
@@ -209,16 +240,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
209
240
  requirements:
210
241
  - - ">="
211
242
  - !ruby/object:Gem::Version
212
- version: '2.1'
243
+ version: '2.3'
213
244
  required_rubygems_version: !ruby/object:Gem::Requirement
214
245
  requirements:
215
246
  - - ">="
216
247
  - !ruby/object:Gem::Version
217
248
  version: '0'
218
249
  requirements: []
219
- rubyforge_project:
220
- rubygems_version: 2.5.1
221
- signing_key:
250
+ rubygems_version: 3.1.6
251
+ signing_key:
222
252
  specification_version: 4
223
253
  summary: Easily support JSON API in Rails.
224
254
  test_files: []
@@ -1,127 +0,0 @@
1
- module JSONAPI
2
- class CachedResourceFragment
3
- def self.fetch_fragments(resource_klass, serializer, context, cache_ids)
4
- serializer_config_key = serializer.config_key(resource_klass).gsub("/", "_")
5
- context_json = resource_klass.attribute_caching_context(context).to_json
6
- context_b64 = JSONAPI.configuration.resource_cache_digest_function.call(context_json)
7
- context_key = "ATTR-CTX-#{context_b64.gsub("/", "_")}"
8
-
9
- results = self.lookup(resource_klass, serializer_config_key, context, context_key, cache_ids)
10
-
11
- miss_ids = results.select{|k,v| v.nil? }.keys
12
- unless miss_ids.empty?
13
- find_filters = {resource_klass._primary_key => miss_ids.uniq}
14
- find_options = {context: context}
15
- resource_klass.find(find_filters, find_options).each do |resource|
16
- (id, cr) = write(resource_klass, resource, serializer, serializer_config_key, context, context_key)
17
- results[id] = cr
18
- end
19
- end
20
-
21
- if JSONAPI.configuration.resource_cache_usage_report_function
22
- JSONAPI.configuration.resource_cache_usage_report_function.call(
23
- resource_klass.name,
24
- cache_ids.size - miss_ids.size,
25
- miss_ids.size
26
- )
27
- end
28
-
29
- return results
30
- end
31
-
32
- attr_reader :resource_klass, :id, :type, :context, :fetchable_fields, :relationships,
33
- :links_json, :attributes_json, :meta_json,
34
- :preloaded_fragments
35
-
36
- def initialize(resource_klass, id, type, context, fetchable_fields, relationships,
37
- links_json, attributes_json, meta_json)
38
- @resource_klass = resource_klass
39
- @id = id
40
- @type = type
41
- @context = context
42
- @fetchable_fields = Set.new(fetchable_fields)
43
-
44
- # Relationships left uncompiled because we'll often want to insert included ids on retrieval
45
- @relationships = relationships
46
-
47
- @links_json = CompiledJson.of(links_json)
48
- @attributes_json = CompiledJson.of(attributes_json)
49
- @meta_json = CompiledJson.of(meta_json)
50
-
51
- # A hash of hashes
52
- @preloaded_fragments ||= Hash.new
53
- end
54
-
55
- def to_cache_value
56
- {
57
- id: id,
58
- type: type,
59
- fetchable: fetchable_fields,
60
- rels: relationships,
61
- links: links_json.try(:to_s),
62
- attrs: attributes_json.try(:to_s),
63
- meta: meta_json.try(:to_s)
64
- }
65
- end
66
-
67
- def to_real_resource
68
- rs = Resource.resource_for(self.type).find_by_keys([self.id], {context: self.context})
69
- return rs.try(:first)
70
- end
71
-
72
- private
73
-
74
- def self.lookup(resource_klass, serializer_config_key, context, context_key, cache_ids)
75
- type = resource_klass._type
76
-
77
- keys = cache_ids.map do |(id, cache_key)|
78
- [type, id, cache_key, serializer_config_key, context_key]
79
- end
80
-
81
- hits = JSONAPI.configuration.resource_cache.read_multi(*keys).reject{|_,v| v.nil? }
82
- return keys.each_with_object({}) do |key, hash|
83
- (_, id, _, _) = key
84
- if hits.has_key?(key)
85
- hash[id] = self.from_cache_value(resource_klass, context, hits[key])
86
- else
87
- hash[id] = nil
88
- end
89
- end
90
- end
91
-
92
- def self.from_cache_value(resource_klass, context, h)
93
- new(
94
- resource_klass,
95
- h.fetch(:id),
96
- h.fetch(:type),
97
- context,
98
- h.fetch(:fetchable),
99
- h.fetch(:rels, nil),
100
- h.fetch(:links, nil),
101
- h.fetch(:attrs, nil),
102
- h.fetch(:meta, nil)
103
- )
104
- end
105
-
106
- def self.write(resource_klass, resource, serializer, serializer_config_key, context, context_key)
107
- (id, cache_key) = resource.cache_id
108
- json = serializer.object_hash(resource) # No inclusions passed to object_hash
109
- cr = self.new(
110
- resource_klass,
111
- json['id'],
112
- json['type'],
113
- context,
114
- resource.fetchable_fields,
115
- json['relationships'],
116
- json['links'],
117
- json['attributes'],
118
- json['meta']
119
- )
120
-
121
- key = [resource_klass._type, id, cache_key, serializer_config_key, context_key]
122
- JSONAPI.configuration.resource_cache.write(key, cr.to_cache_value)
123
- return [id, cr]
124
- end
125
-
126
- end
127
- end
@@ -1,88 +0,0 @@
1
- module JSONAPI
2
- class OperationDispatcher
3
-
4
- def initialize(transaction: lambda { |&block| block.yield },
5
- rollback: lambda { },
6
- server_error_callbacks: [])
7
-
8
- @transaction = transaction
9
- @rollback = rollback
10
- @server_error_callbacks = server_error_callbacks
11
- end
12
-
13
- def process(operations)
14
- results = JSONAPI::OperationResults.new
15
-
16
- # Use transactions if more than one operation and if one of the operations can be transactional
17
- # Even if transactional transactions won't be used unless the derived OperationsProcessor supports them.
18
- transactional = false
19
-
20
- operations.each do |operation|
21
- transactional |= operation.transactional?
22
- end if JSONAPI.configuration.allow_transactions
23
-
24
- transaction(transactional) do
25
- # Links and meta data global to the set of operations
26
- operations_meta = {}
27
- operations_links = {}
28
- operations.each do |operation|
29
- results.add_result(process_operation(operation))
30
- rollback(transactional) if results.has_errors?
31
- end
32
- results.meta = operations_meta
33
- results.links = operations_links
34
- end
35
- results
36
- end
37
-
38
- private
39
-
40
- def transaction(transactional)
41
- if transactional
42
- @transaction.call do
43
- yield
44
- end
45
- else
46
- yield
47
- end
48
- end
49
-
50
- def rollback(transactional)
51
- if transactional
52
- @rollback.call
53
- end
54
- end
55
-
56
- def process_operation(operation)
57
- with_default_handling do
58
- operation.process
59
- end
60
- end
61
-
62
- def with_default_handling(&block)
63
- block.yield
64
- rescue => e
65
- if JSONAPI.configuration.exception_class_whitelisted?(e)
66
- raise e
67
- else
68
- @server_error_callbacks.each { |callback|
69
- safe_run_callback(callback, e)
70
- }
71
-
72
- internal_server_error = JSONAPI::Exceptions::InternalServerError.new(e)
73
- Rails.logger.error { "Internal Server Error: #{e.message} #{e.backtrace.join("\n")}" }
74
- return JSONAPI::ErrorsOperationResult.new(internal_server_error.errors[0].code, internal_server_error.errors)
75
- end
76
- end
77
-
78
- def safe_run_callback(callback, error)
79
- begin
80
- callback.call(error)
81
- rescue => e
82
- Rails.logger.error { "Error in error handling callback: #{e.message} #{e.backtrace.join("\n")}" }
83
- internal_server_error = JSONAPI::Exceptions::InternalServerError.new(e)
84
- return JSONAPI::ErrorsOperationResult.new(internal_server_error.errors[0].code, internal_server_error.errors)
85
- end
86
- end
87
- end
88
- end
@@ -1,35 +0,0 @@
1
- module JSONAPI
2
- class OperationResults
3
- attr_accessor :results
4
- attr_accessor :meta
5
- attr_accessor :links
6
-
7
- def initialize
8
- @results = []
9
- @has_errors = false
10
- @meta = {}
11
- @links = {}
12
- end
13
-
14
- def add_result(result)
15
- @has_errors = true if result.is_a?(JSONAPI::ErrorsOperationResult)
16
- @results.push(result)
17
- end
18
-
19
- def has_errors?
20
- @has_errors
21
- end
22
-
23
- def all_errors
24
- errors = []
25
- if @has_errors
26
- @results.each do |result|
27
- if result.is_a?(JSONAPI::ErrorsOperationResult)
28
- errors.concat(result.errors)
29
- end
30
- end
31
- end
32
- errors
33
- end
34
- end
35
- end
@@ -1,167 +0,0 @@
1
- module JSONAPI
2
- class RelationshipBuilder
3
- attr_reader :model_class, :options, :relationship_class
4
- delegate :register_relationship, to: :@resource_class
5
-
6
- def initialize(relationship_class, model_class, options)
7
- @relationship_class = relationship_class
8
- @model_class = model_class
9
- @resource_class = options[:parent_resource]
10
- @options = options
11
- end
12
-
13
- def define_relationship_methods(relationship_name)
14
- # Initialize from an ActiveRecord model's properties
15
- if model_class && model_class.ancestors.collect{|ancestor| ancestor.name}.include?('ActiveRecord::Base')
16
- model_association = model_class.reflect_on_association(relationship_name)
17
- if model_association
18
- options[:class_name] ||= model_association.class_name
19
- end
20
- end
21
-
22
- relationship = register_relationship(
23
- relationship_name,
24
- relationship_class.new(relationship_name, options)
25
- )
26
-
27
- foreign_key = define_foreign_key_setter(relationship.foreign_key)
28
-
29
- case relationship
30
- when JSONAPI::Relationship::ToOne
31
- associated = define_resource_relationship_accessor(:one, relationship_name)
32
- args = [relationship, foreign_key, associated, relationship_name]
33
-
34
- relationship.belongs_to? ? build_belongs_to(*args) : build_has_one(*args)
35
- when JSONAPI::Relationship::ToMany
36
- associated = define_resource_relationship_accessor(:many, relationship_name)
37
-
38
- build_to_many(relationship, foreign_key, associated, relationship_name)
39
- end
40
- end
41
-
42
- def define_foreign_key_setter(foreign_key)
43
- define_on_resource "#{foreign_key}=" do |value|
44
- @model.method("#{foreign_key}=").call(value)
45
- end
46
- foreign_key
47
- end
48
-
49
- def define_resource_relationship_accessor(type, relationship_name)
50
- associated_records_method_name = {
51
- one: "record_for_#{relationship_name}",
52
- many: "records_for_#{relationship_name}"
53
- }
54
- .fetch(type)
55
-
56
- define_on_resource associated_records_method_name do |options = {}|
57
- relationship = self.class._relationships[relationship_name]
58
- relation_name = relationship.relation_name(context: @context)
59
- records = records_for(relation_name)
60
-
61
- resource_klass = relationship.resource_klass
62
-
63
- filters = options.fetch(:filters, {})
64
- unless filters.nil? || filters.empty?
65
- records = resource_klass.apply_filters(records, filters, options)
66
- end
67
-
68
- sort_criteria = options.fetch(:sort_criteria, {})
69
- unless sort_criteria.nil? || sort_criteria.empty?
70
- order_options = relationship.resource_klass.construct_order_options(sort_criteria)
71
- records = resource_klass.apply_sort(records, order_options, @context)
72
- end
73
-
74
- paginator = options[:paginator]
75
- if paginator
76
- records = resource_klass.apply_pagination(records, paginator, order_options)
77
- end
78
-
79
- records
80
- end
81
-
82
- associated_records_method_name
83
- end
84
-
85
- def build_belongs_to(relationship, foreign_key, associated_records_method_name, relationship_name)
86
- # Calls method matching foreign key name on model instance
87
- define_on_resource foreign_key do
88
- @model.method(foreign_key).call
89
- end
90
-
91
- # Returns instantiated related resource object or nil
92
- define_on_resource relationship_name do |options = {}|
93
- relationship = self.class._relationships[relationship_name]
94
-
95
- if relationship.polymorphic?
96
- associated_model = public_send(associated_records_method_name)
97
- resource_klass = self.class.resource_for_model(associated_model) if associated_model
98
- return resource_klass.new(associated_model, @context) if resource_klass
99
- else
100
- resource_klass = relationship.resource_klass
101
- if resource_klass
102
- associated_model = public_send(associated_records_method_name)
103
- return associated_model ? resource_klass.new(associated_model, @context) : nil
104
- end
105
- end
106
- end
107
- end
108
-
109
- def build_has_one(relationship, foreign_key, associated_records_method_name, relationship_name)
110
- # Returns primary key name of related resource class
111
- define_on_resource foreign_key do
112
- relationship = self.class._relationships[relationship_name]
113
-
114
- record = public_send(associated_records_method_name)
115
- return nil if record.nil?
116
- record.public_send(relationship.resource_klass._primary_key)
117
- end
118
-
119
- # Returns instantiated related resource object or nil
120
- define_on_resource relationship_name do |options = {}|
121
- relationship = self.class._relationships[relationship_name]
122
-
123
- if relationship.polymorphic?
124
- associated_model = public_send(associated_records_method_name)
125
- resource_klass = self.class.resource_for_model(associated_model) if associated_model
126
- return resource_klass.new(associated_model, @context) if resource_klass && associated_model
127
- else
128
- resource_klass = relationship.resource_klass
129
- if resource_klass
130
- associated_model = public_send(associated_records_method_name)
131
- return associated_model ? resource_klass.new(associated_model, @context) : nil
132
- end
133
- end
134
- end
135
- end
136
-
137
- def build_to_many(relationship, foreign_key, associated_records_method_name, relationship_name)
138
- # Returns array of primary keys of related resource classes
139
- define_on_resource foreign_key do
140
- records = public_send(associated_records_method_name)
141
- return records.collect do |record|
142
- record.public_send(relationship.resource_klass._primary_key)
143
- end
144
- end
145
-
146
- # Returns array of instantiated related resource objects
147
- define_on_resource relationship_name do |options = {}|
148
- relationship = self.class._relationships[relationship_name]
149
-
150
- resource_klass = relationship.resource_klass
151
- records = public_send(associated_records_method_name, options)
152
-
153
- return records.collect do |record|
154
- if relationship.polymorphic?
155
- resource_klass = self.class.resource_for_model(record)
156
- end
157
- resource_klass.new(record, @context)
158
- end
159
- end
160
- end
161
-
162
- def define_on_resource(method_name, &block)
163
- return if @resource_class.method_defined?(method_name)
164
- @resource_class.inject_method_definition(method_name, block)
165
- end
166
- end
167
- end