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
@@ -1,8 +1,13 @@
1
1
  module JSONAPI
2
2
  class Relationship
3
3
  attr_reader :acts_as_set, :foreign_key, :options, :name,
4
- :class_name, :polymorphic, :always_include_linkage_data,
5
- :parent_resource, :eager_load_on_include
4
+ :class_name, :polymorphic, :always_include_optional_linkage_data,
5
+ :parent_resource, :eager_load_on_include, :custom_methods,
6
+ :inverse_relationship, :allow_include, :use_related_resource_records_for_joins
7
+
8
+ attr_writer :allow_include
9
+
10
+ attr_accessor :_routed, :_warned_missing_route
6
11
 
7
12
  def initialize(name, options = {})
8
13
  @name = name.to_s
@@ -12,22 +17,75 @@ module JSONAPI
12
17
  @parent_resource = options[:parent_resource]
13
18
  @relation_name = options.fetch(:relation_name, @name)
14
19
  @polymorphic = options.fetch(:polymorphic, false) == true
15
- @always_include_linkage_data = options.fetch(:always_include_linkage_data, false) == true
16
- @eager_load_on_include = options.fetch(:eager_load_on_include, true) == true
20
+ @polymorphic_types = options[:polymorphic_types]
21
+ if options[:polymorphic_relations]
22
+ ActiveSupport::Deprecation.warn('Use polymorphic_types instead of polymorphic_relations')
23
+ @polymorphic_types ||= options[:polymorphic_relations]
24
+ end
25
+
26
+ use_related_resource_records_for_joins_default = if options[:relation_name]
27
+ false
28
+ else
29
+ JSONAPI.configuration.use_related_resource_records_for_joins
30
+ end
31
+
32
+ @use_related_resource_records_for_joins = options.fetch(:use_related_resource_records_for_joins,
33
+ use_related_resource_records_for_joins_default) == true
34
+
35
+ @always_include_optional_linkage_data = options.fetch(:always_include_optional_linkage_data, false) == true
36
+ @eager_load_on_include = options.fetch(:eager_load_on_include, false) == true
37
+ @allow_include = options[:allow_include]
38
+ @class_name = nil
39
+ @inverse_relationship = nil
40
+
41
+ @_routed = false
42
+ @_warned_missing_route = false
43
+
44
+ exclude_links(options.fetch(:exclude_links, JSONAPI.configuration.default_exclude_links))
45
+
46
+ # Custom methods are reserved for future use
47
+ @custom_methods = options.fetch(:custom_methods, {})
17
48
  end
18
49
 
19
50
  alias_method :polymorphic?, :polymorphic
51
+ alias_method :parent_resource_klass, :parent_resource
20
52
 
21
53
  def primary_key
54
+ # :nocov:
22
55
  @primary_key ||= resource_klass._primary_key
56
+ # :nocov:
23
57
  end
24
58
 
25
59
  def resource_klass
26
- @resource_klass ||= @parent_resource.resource_for(@class_name)
60
+ @resource_klass ||= @parent_resource.resource_klass_for(@class_name)
27
61
  end
28
62
 
29
63
  def table_name
64
+ # :nocov:
30
65
  @table_name ||= resource_klass._table_name
66
+ # :nocov:
67
+ end
68
+
69
+ def self.polymorphic_types(name)
70
+ @poly_hash ||= {}.tap do |hash|
71
+ ObjectSpace.each_object do |klass|
72
+ next unless Module === klass
73
+ if ActiveRecord::Base > klass
74
+ klass.reflect_on_all_associations(:has_many).select{|r| r.options[:as] }.each do |reflection|
75
+ (hash[reflection.options[:as]] ||= []) << klass.name.underscore
76
+ end
77
+ end
78
+ end
79
+ end
80
+ @poly_hash[name.to_sym]
81
+ end
82
+
83
+ def resource_types
84
+ if polymorphic? && belongs_to?
85
+ @polymorphic_types ||= self.class.polymorphic_types(@relation_name).collect {|t| t.pluralize}
86
+ else
87
+ [resource_klass._type.to_s.pluralize]
88
+ end
31
89
  end
32
90
 
33
91
  def type
@@ -47,17 +105,35 @@ module JSONAPI
47
105
  end
48
106
  end
49
107
 
50
- def type_for_source(source)
51
- if polymorphic?
52
- resource = source.public_send(name)
53
- resource.class._type if resource
54
- else
55
- type
108
+ def belongs_to?
109
+ # :nocov:
110
+ false
111
+ # :nocov:
112
+ end
113
+
114
+ def readonly?
115
+ @options[:readonly]
116
+ end
117
+
118
+ def exclude_links(exclude)
119
+ case exclude
120
+ when :default, "default"
121
+ @_exclude_links = [:self, :related]
122
+ when :none, "none"
123
+ @_exclude_links = []
124
+ when Array
125
+ @_exclude_links = exclude.collect {|link| link.to_sym}
126
+ else
127
+ fail "Invalid exclude_links"
56
128
  end
57
129
  end
58
130
 
59
- def belongs_to?
60
- false
131
+ def _exclude_links
132
+ @_exclude_links ||= []
133
+ end
134
+
135
+ def exclude_link?(link)
136
+ _exclude_links.include?(link.to_sym)
61
137
  end
62
138
 
63
139
  class ToOne < Relationship
@@ -68,27 +144,89 @@ module JSONAPI
68
144
  @class_name = options.fetch(:class_name, name.to_s.camelize)
69
145
  @foreign_key ||= "#{name}_id".to_sym
70
146
  @foreign_key_on = options.fetch(:foreign_key_on, :self)
147
+ if parent_resource
148
+ @inverse_relationship = options.fetch(:inverse_relationship, parent_resource._type)
149
+ end
150
+ end
151
+
152
+ def to_s
153
+ # :nocov: useful for debugging
154
+ "#{parent_resource}.#{name}(#{belongs_to? ? 'BelongsToOne' : 'ToOne'})"
155
+ # :nocov:
71
156
  end
72
157
 
73
158
  def belongs_to?
159
+ # :nocov:
74
160
  foreign_key_on == :self
161
+ # :nocov:
75
162
  end
76
163
 
77
164
  def polymorphic_type
78
165
  "#{name}_type" if polymorphic?
79
166
  end
167
+
168
+ def include_optional_linkage_data?
169
+ @always_include_optional_linkage_data || JSONAPI::configuration.always_include_to_one_linkage_data
170
+ end
171
+
172
+ def allow_include?(context = nil)
173
+ strategy = if @allow_include.nil?
174
+ JSONAPI.configuration.default_allow_include_to_one
175
+ else
176
+ @allow_include
177
+ end
178
+
179
+ if !!strategy == strategy #check for boolean
180
+ return strategy
181
+ elsif strategy.is_a?(Symbol) || strategy.is_a?(String)
182
+ parent_resource.send(strategy, context)
183
+ else
184
+ strategy.call(context)
185
+ end
186
+ end
80
187
  end
81
188
 
82
189
  class ToMany < Relationship
83
- attr_reader :reflect, :inverse_relationship
190
+ attr_reader :reflect
84
191
 
85
192
  def initialize(name, options = {})
86
193
  super
87
194
  @class_name = options.fetch(:class_name, name.to_s.camelize.singularize)
88
195
  @foreign_key ||= "#{name.to_s.singularize}_ids".to_sym
89
196
  @reflect = options.fetch(:reflect, true) == true
90
- @inverse_relationship = options.fetch(:inverse_relationship, parent_resource._type.to_s.singularize.to_sym) if parent_resource
197
+ if parent_resource
198
+ @inverse_relationship = options.fetch(:inverse_relationship, parent_resource._type.to_s.singularize.to_sym)
199
+ end
200
+ end
201
+
202
+ def to_s
203
+ # :nocov: useful for debugging
204
+ "#{parent_resource}.#{name}(ToMany)"
205
+ # :nocov:
206
+ end
207
+
208
+ def include_optional_linkage_data?
209
+ # :nocov:
210
+ @always_include_optional_linkage_data || JSONAPI::configuration.always_include_to_many_linkage_data
211
+ # :nocov:
91
212
  end
213
+
214
+ def allow_include?(context = nil)
215
+ strategy = if @allow_include.nil?
216
+ JSONAPI.configuration.default_allow_include_to_many
217
+ else
218
+ @allow_include
219
+ end
220
+
221
+ if !!strategy == strategy #check for boolean
222
+ return strategy
223
+ elsif strategy.is_a?(Symbol) || strategy.is_a?(String)
224
+ parent_resource.send(strategy, context)
225
+ else
226
+ strategy.call(context)
227
+ end
228
+ end
229
+
92
230
  end
93
231
  end
94
232
  end