jsonapi-resources 0.0.6 → 0.0.7
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/README.md +17 -17
- data/lib/jsonapi/formatter.rb +3 -3
- data/lib/jsonapi/operation.rb +16 -16
- data/lib/jsonapi/request.rb +5 -5
- data/lib/jsonapi/resource.rb +57 -51
- data/lib/jsonapi/resource_controller.rb +11 -14
- data/lib/jsonapi/resource_serializer.rb +17 -18
- data/lib/jsonapi/resources/version.rb +1 -1
- data/test/fixtures/active_record.rb +12 -12
- data/test/test_helper.rb +5 -5
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f70ae71e6004b279c357d07b852d3be4eebc03d6
|
4
|
+
data.tar.gz: bc3fc2fae00f4e4d3a5c6d602bc42659181d7a02
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bfb971dee293f36ba1e4a78f6b5db0e9d7a4dbe4be1b38cd66fcb183aefb0935497472e3e1ea72a3ca41be551b96de887dd00c3a323814c8b16b1ad9b03a2e64
|
7
|
+
data.tar.gz: c2c3b13c7c58ee1a7b7a4e1c029477965a927413910944fb9f8837f5faec61af765198a1da618ee493431e12a7eea402b53e8368998f68344eb5eb36b7f1c7d3
|
data/README.md
CHANGED
@@ -63,7 +63,7 @@ end
|
|
63
63
|
|
64
64
|
This resource has 5 attributes: `:id`, `:name_first`, `:name_last`, `:email`, `:twitter`. By default these attributes must exist on the model that is handled by the resource.
|
65
65
|
|
66
|
-
A resource object wraps a Ruby object, usually an ActiveModel record, which is available as the `@
|
66
|
+
A resource object wraps a Ruby object, usually an ActiveModel record, which is available as the `@model` variable. This allows a resource's methods to access the underlying model.
|
67
67
|
|
68
68
|
For example, a computed attribute for `full_name` could be defined as such:
|
69
69
|
|
@@ -75,7 +75,7 @@ class ContactResource < JSONAPI::Resource
|
|
75
75
|
attribute :full_name
|
76
76
|
|
77
77
|
def full_name
|
78
|
-
"#{@
|
78
|
+
"#{@model.name_first}, #{@model.name_last}"
|
79
79
|
end
|
80
80
|
end
|
81
81
|
```
|
@@ -117,7 +117,7 @@ class ContactResource < JSONAPI::Resource
|
|
117
117
|
attributes :id, :name_first, :name_last, :full_name
|
118
118
|
|
119
119
|
def full_name
|
120
|
-
"#{@
|
120
|
+
"#{@model.name_first}, #{@model.name_last}"
|
121
121
|
end
|
122
122
|
|
123
123
|
def self.updateable_fields(context)
|
@@ -458,13 +458,13 @@ JR by default uses some simple rules to format an attribute for serialization. S
|
|
458
458
|
|
459
459
|
If you want to change the way an attribute is serialized you have a couple of ways. The simplest method is to create a getter method on the resource which overrides the attribute and apply the formatting there. For example:
|
460
460
|
|
461
|
-
```
|
461
|
+
```ruby
|
462
462
|
class PersonResource < JSONAPI::Resource
|
463
463
|
attributes :id, :name, :email
|
464
464
|
attribute :last_login_time
|
465
465
|
|
466
466
|
def last_login_time
|
467
|
-
@
|
467
|
+
@model.last_login_time.in_time_zone(@context[:current_user].time_zone).to_s
|
468
468
|
end
|
469
469
|
end
|
470
470
|
```
|
@@ -475,7 +475,7 @@ This is simple to implement for a one off situation, but not for example if you
|
|
475
475
|
|
476
476
|
To overcome the above limitations JR uses Value Formatters. Value Formatters allow you to control the way values are handled for an attribute. The `format` can be set per attribute as it is declared in the resource. For example:
|
477
477
|
|
478
|
-
```
|
478
|
+
```ruby
|
479
479
|
class PersonResource < JSONAPI::Resource
|
480
480
|
attributes :id, :name, :email
|
481
481
|
attribute :last_login_time, format: :date_with_timezone
|
@@ -484,15 +484,15 @@ end
|
|
484
484
|
|
485
485
|
A Value formatter has a `format` and an `unformat` method. Here's the base ValueFormatter and DefaultValueFormatter for reference:
|
486
486
|
|
487
|
-
```
|
487
|
+
```ruby
|
488
488
|
module JSONAPI
|
489
489
|
class ValueFormatter < Formatter
|
490
490
|
class << self
|
491
|
-
def format(raw_value,
|
491
|
+
def format(raw_value, context)
|
492
492
|
super(raw_value)
|
493
493
|
end
|
494
494
|
|
495
|
-
def unformat(value,
|
495
|
+
def unformat(value, context)
|
496
496
|
super(value)
|
497
497
|
end
|
498
498
|
...
|
@@ -502,7 +502,7 @@ end
|
|
502
502
|
|
503
503
|
class DefaultValueFormatter < JSONAPI::ValueFormatter
|
504
504
|
class << self
|
505
|
-
def format(raw_value,
|
505
|
+
def format(raw_value, context)
|
506
506
|
case raw_value
|
507
507
|
when String, Integer
|
508
508
|
return raw_value
|
@@ -516,15 +516,15 @@ end
|
|
516
516
|
|
517
517
|
You can also create your own Value Formatter. Value Formatters must be named with the `format` name followed by `ValueFormatter`, i.e. `DateWithTimezoneValueFormatter` and derive from `JSONAPI::ValueFormatter`. It is recommended that you create a directory for your formatters, called `formatters`.
|
518
518
|
|
519
|
-
The `format` method is called by the ResourceSerializer as is serializing a resource. The format method takes the `raw_value`,
|
519
|
+
The `format` method is called by the ResourceSerializer as is serializing a resource. The format method takes the `raw_value`, and `context` parameters. `raw_value` is the value as read from the model, and `context` is the context of the current user/request. From this you can base the formatted version of the attribute current context.
|
520
520
|
|
521
|
-
The `unformat` method is called when processing the request. Each incoming attribute (except `links`) are run through the `unformat` method. The `unformat` method takes the `value`,
|
521
|
+
The `unformat` method is called when processing the request. Each incoming attribute (except `links`) are run through the `unformat` method. The `unformat` method takes the `value`, and `context` parameters. `value` is the value as it comes in on the request, and `context` is the context of the current user/request. This allows you process the incoming value to alter its state before it is stored in the model. By default no processing is applied.
|
522
522
|
|
523
523
|
###### Use a Different Default Value Formatter
|
524
524
|
|
525
525
|
Another way to handle formatting is to set a different default value formatter. This will affect all attributes that do notw have a `format` set. You can do this by overriding the `default_attribute_options` method for a resource (or a base resource for a system wide change).
|
526
526
|
|
527
|
-
```
|
527
|
+
```ruby
|
528
528
|
def default_attribute_options
|
529
529
|
{format: :my_default}
|
530
530
|
end
|
@@ -532,15 +532,15 @@ Another way to handle formatting is to set a different default value formatter.
|
|
532
532
|
|
533
533
|
and
|
534
534
|
|
535
|
-
```
|
535
|
+
```ruby
|
536
536
|
class MyDefaultValueFormatter < JSONAPI::ValueFormatter
|
537
537
|
class << self
|
538
|
-
def format(raw_value,
|
538
|
+
def format(raw_value, context)
|
539
539
|
case raw_value
|
540
540
|
when String, Integer
|
541
541
|
return raw_value
|
542
542
|
when DateTime
|
543
|
-
return raw_value.in_time_zone(
|
543
|
+
return raw_value.in_time_zone(context[:current_user].time_zone).to_s
|
544
544
|
else
|
545
545
|
return raw_value.to_s
|
546
546
|
end
|
@@ -566,7 +566,7 @@ end
|
|
566
566
|
|
567
567
|
This will cause the serializer to use the CamelizedKeyFormatter. Besides UnderscoredKeyFormatter and CamelizedKeyFormatter JR defines the DasherizedKeyFormatter. You can also create your own KeyFormatter, for example:
|
568
568
|
|
569
|
-
```
|
569
|
+
```ruby
|
570
570
|
class UpperCamelizedKeyFormatter < JSONAPI::KeyFormatter
|
571
571
|
class << self
|
572
572
|
def format(key)
|
data/lib/jsonapi/formatter.rb
CHANGED
@@ -37,11 +37,11 @@ module JSONAPI
|
|
37
37
|
|
38
38
|
class ValueFormatter < Formatter
|
39
39
|
class << self
|
40
|
-
def format(raw_value,
|
40
|
+
def format(raw_value, context)
|
41
41
|
super(raw_value)
|
42
42
|
end
|
43
43
|
|
44
|
-
def unformat(value,
|
44
|
+
def unformat(value, context)
|
45
45
|
super(value)
|
46
46
|
end
|
47
47
|
|
@@ -82,7 +82,7 @@ end
|
|
82
82
|
|
83
83
|
class DefaultValueFormatter < JSONAPI::ValueFormatter
|
84
84
|
class << self
|
85
|
-
def format(raw_value,
|
85
|
+
def format(raw_value, context)
|
86
86
|
case raw_value
|
87
87
|
when String, Integer
|
88
88
|
return raw_value
|
data/lib/jsonapi/operation.rb
CHANGED
@@ -20,9 +20,9 @@ module JSONAPI
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def apply(context)
|
23
|
-
resource = @resource_klass.
|
24
|
-
resource.replace_fields(@values
|
25
|
-
resource.save
|
23
|
+
resource = @resource_klass.create(context)
|
24
|
+
resource.replace_fields(@values)
|
25
|
+
resource.save
|
26
26
|
|
27
27
|
return JSONAPI::OperationResult.new(:created, resource)
|
28
28
|
|
@@ -40,7 +40,7 @@ module JSONAPI
|
|
40
40
|
|
41
41
|
def apply(context)
|
42
42
|
resource = @resource_klass.find_by_key(@resource_id, context)
|
43
|
-
resource.remove
|
43
|
+
resource.remove
|
44
44
|
|
45
45
|
return JSONAPI::OperationResult.new(:no_content)
|
46
46
|
|
@@ -63,8 +63,8 @@ module JSONAPI
|
|
63
63
|
|
64
64
|
def apply(context)
|
65
65
|
resource = @resource_klass.find_by_key(@resource_id, context)
|
66
|
-
resource.replace_fields(values
|
67
|
-
resource.save
|
66
|
+
resource.replace_fields(values)
|
67
|
+
resource.save
|
68
68
|
|
69
69
|
return JSONAPI::OperationResult.new(:ok, resource)
|
70
70
|
end
|
@@ -82,8 +82,8 @@ module JSONAPI
|
|
82
82
|
|
83
83
|
def apply(context)
|
84
84
|
resource = @resource_klass.find_by_key(@resource_id, context)
|
85
|
-
resource.create_has_one_link(@association_type, @key_value
|
86
|
-
resource.save
|
85
|
+
resource.create_has_one_link(@association_type, @key_value)
|
86
|
+
resource.save
|
87
87
|
|
88
88
|
return JSONAPI::OperationResult.new(:no_content)
|
89
89
|
end
|
@@ -101,8 +101,8 @@ module JSONAPI
|
|
101
101
|
|
102
102
|
def apply(context)
|
103
103
|
resource = @resource_klass.find_by_key(@resource_id, context)
|
104
|
-
resource.replace_has_one_link(@association_type, @key_value
|
105
|
-
resource.save
|
104
|
+
resource.replace_has_one_link(@association_type, @key_value)
|
105
|
+
resource.save
|
106
106
|
|
107
107
|
return JSONAPI::OperationResult.new(:no_content)
|
108
108
|
end
|
@@ -121,7 +121,7 @@ module JSONAPI
|
|
121
121
|
def apply(context)
|
122
122
|
resource = @resource_klass.find_by_key(@resource_id, context)
|
123
123
|
@key_values.each do |value|
|
124
|
-
resource.create_has_many_link(@association_type, value
|
124
|
+
resource.create_has_many_link(@association_type, value)
|
125
125
|
end
|
126
126
|
|
127
127
|
return JSONAPI::OperationResult.new(:no_content)
|
@@ -140,8 +140,8 @@ module JSONAPI
|
|
140
140
|
|
141
141
|
def apply(context)
|
142
142
|
resource = @resource_klass.find_by_key(@resource_id, context)
|
143
|
-
resource.replace_has_many_links(@association_type, @key_values
|
144
|
-
resource.save
|
143
|
+
resource.replace_has_many_links(@association_type, @key_values)
|
144
|
+
resource.save
|
145
145
|
|
146
146
|
return JSONAPI::OperationResult.new(:no_content)
|
147
147
|
end
|
@@ -159,7 +159,7 @@ module JSONAPI
|
|
159
159
|
|
160
160
|
def apply(context)
|
161
161
|
resource = @resource_klass.find_by_key(@resource_id, context)
|
162
|
-
resource.remove_has_many_link(@association_type, @associated_key
|
162
|
+
resource.remove_has_many_link(@association_type, @associated_key)
|
163
163
|
|
164
164
|
return JSONAPI::OperationResult.new(:no_content)
|
165
165
|
|
@@ -179,8 +179,8 @@ module JSONAPI
|
|
179
179
|
|
180
180
|
def apply(context)
|
181
181
|
resource = @resource_klass.find_by_key(@resource_id, context)
|
182
|
-
resource.remove_has_one_link(@association_type
|
183
|
-
resource.save
|
182
|
+
resource.remove_has_one_link(@association_type)
|
183
|
+
resource.save
|
184
184
|
|
185
185
|
return JSONAPI::OperationResult.new(:no_content)
|
186
186
|
end
|
data/lib/jsonapi/request.rb
CHANGED
@@ -182,15 +182,15 @@ module JSONAPI
|
|
182
182
|
association = @resource_klass._association(param)
|
183
183
|
|
184
184
|
if association.is_a?(JSONAPI::Association::HasOne)
|
185
|
-
checked_has_one_associations[param] = @resource_klass.resource_for(association.type).verify_key(value, context)
|
185
|
+
checked_has_one_associations[param] = @resource_klass.resource_for(association.type).verify_key(value, @context)
|
186
186
|
elsif association.is_a?(JSONAPI::Association::HasMany)
|
187
187
|
keys = []
|
188
188
|
if value.is_a?(Array)
|
189
189
|
value.each do |val|
|
190
|
-
keys.push(@resource_klass.resource_for(association.type).verify_key(val, context))
|
190
|
+
keys.push(@resource_klass.resource_for(association.type).verify_key(val, @context))
|
191
191
|
end
|
192
192
|
else
|
193
|
-
keys.push(@resource_klass.resource_for(association.type).verify_key(value, context))
|
193
|
+
keys.push(@resource_klass.resource_for(association.type).verify_key(value, @context))
|
194
194
|
end
|
195
195
|
checked_has_many_associations[param] = keys
|
196
196
|
else
|
@@ -207,7 +207,7 @@ module JSONAPI
|
|
207
207
|
|
208
208
|
def unformat_value(attribute, value)
|
209
209
|
value_formatter = JSONAPI::ValueFormatter.value_formatter_for(@resource_klass._attribute_options(attribute)[:format])
|
210
|
-
value_formatter.unformat(value, @
|
210
|
+
value_formatter.unformat(value, @context)
|
211
211
|
end
|
212
212
|
|
213
213
|
def verify_permitted_params(params, allowed_fields)
|
@@ -368,7 +368,7 @@ module JSONAPI
|
|
368
368
|
def parse_key_array(raw)
|
369
369
|
keys = []
|
370
370
|
raw.split(/,/).collect do |key|
|
371
|
-
keys.push @resource_klass.verify_key(key, context)
|
371
|
+
keys.push @resource_klass.verify_key(key, @context)
|
372
372
|
end
|
373
373
|
return keys
|
374
374
|
end
|
data/lib/jsonapi/resource.rb
CHANGED
@@ -8,89 +8,87 @@ module JSONAPI
|
|
8
8
|
|
9
9
|
@@resource_types = {}
|
10
10
|
|
11
|
-
|
11
|
+
attr :context
|
12
|
+
attr_reader :model
|
12
13
|
|
13
|
-
def initialize(
|
14
|
-
@
|
14
|
+
def initialize(model, context = nil)
|
15
|
+
@model = model
|
16
|
+
@context = context
|
15
17
|
end
|
16
18
|
|
17
|
-
def
|
18
|
-
|
19
|
+
def remove
|
20
|
+
@model.destroy
|
19
21
|
end
|
20
22
|
|
21
|
-
def
|
22
|
-
@object.destroy
|
23
|
-
end
|
24
|
-
|
25
|
-
def create_has_many_link(association_type, association_key_value, context)
|
23
|
+
def create_has_many_link(association_type, association_key_value)
|
26
24
|
association = self.class._associations[association_type]
|
27
|
-
related_resource = self.class.resource_for(association.type).find_by_key(association_key_value, context)
|
25
|
+
related_resource = self.class.resource_for(association.type).find_by_key(association_key_value, @context)
|
28
26
|
|
29
27
|
# ToDo: Add option to skip relations that already exist instead of returning an error?
|
30
|
-
relation = @
|
28
|
+
relation = @model.send(association.type).where(association.primary_key => association_key_value).first
|
31
29
|
if relation.nil?
|
32
|
-
@
|
30
|
+
@model.send(association.type) << related_resource.model
|
33
31
|
else
|
34
32
|
raise JSONAPI::Exceptions::HasManyRelationExists.new(association_key_value)
|
35
33
|
end
|
36
34
|
end
|
37
35
|
|
38
|
-
def replace_has_many_links(association_type, association_key_values
|
36
|
+
def replace_has_many_links(association_type, association_key_values)
|
39
37
|
association = self.class._associations[association_type]
|
40
38
|
|
41
|
-
@
|
39
|
+
@model.send("#{association.key}=", association_key_values)
|
42
40
|
end
|
43
41
|
|
44
|
-
def create_has_one_link(association_type, association_key_value
|
42
|
+
def create_has_one_link(association_type, association_key_value)
|
45
43
|
association = self.class._associations[association_type]
|
46
44
|
|
47
45
|
# ToDo: Add option to skip relations that already exist instead of returning an error?
|
48
|
-
relation = @
|
46
|
+
relation = @model.send("#{association.key}")
|
49
47
|
if relation.nil?
|
50
|
-
@
|
48
|
+
@model.send("#{association.key}=", association_key_value)
|
51
49
|
else
|
52
50
|
raise JSONAPI::Exceptions::HasOneRelationExists.new
|
53
51
|
end
|
54
52
|
end
|
55
53
|
|
56
|
-
def replace_has_one_link(association_type, association_key_value
|
54
|
+
def replace_has_one_link(association_type, association_key_value)
|
57
55
|
association = self.class._associations[association_type]
|
58
56
|
|
59
|
-
@
|
57
|
+
@model.send("#{association.key}=", association_key_value)
|
60
58
|
end
|
61
59
|
|
62
|
-
def remove_has_many_link(association_type, key
|
60
|
+
def remove_has_many_link(association_type, key)
|
63
61
|
association = self.class._associations[association_type]
|
64
62
|
|
65
|
-
@
|
63
|
+
@model.send(association.type).delete(key)
|
66
64
|
end
|
67
65
|
|
68
|
-
def remove_has_one_link(association_type
|
66
|
+
def remove_has_one_link(association_type)
|
69
67
|
association = self.class._associations[association_type]
|
70
68
|
|
71
|
-
@
|
69
|
+
@model.send("#{association.key}=", nil)
|
72
70
|
end
|
73
71
|
|
74
|
-
def replace_fields(field_data
|
72
|
+
def replace_fields(field_data)
|
75
73
|
field_data[:attributes].each do |attribute, value|
|
76
74
|
send "#{attribute}=", value
|
77
75
|
end
|
78
76
|
|
79
77
|
field_data[:has_one].each do |association_type, value|
|
80
78
|
if value.nil?
|
81
|
-
remove_has_one_link(association_type
|
79
|
+
remove_has_one_link(association_type)
|
82
80
|
else
|
83
|
-
replace_has_one_link(association_type, value
|
81
|
+
replace_has_one_link(association_type, value)
|
84
82
|
end
|
85
83
|
end if field_data[:has_one]
|
86
84
|
|
87
85
|
field_data[:has_many].each do |association_type, values|
|
88
|
-
replace_has_many_links(association_type, values
|
86
|
+
replace_has_many_links(association_type, values)
|
89
87
|
end if field_data[:has_many]
|
90
88
|
end
|
91
89
|
|
92
|
-
def save
|
93
|
-
@
|
90
|
+
def save
|
91
|
+
@model.save!
|
94
92
|
rescue ActiveRecord::RecordInvalid => e
|
95
93
|
errors = []
|
96
94
|
e.record.errors.messages.each do |element|
|
@@ -107,7 +105,7 @@ module JSONAPI
|
|
107
105
|
end
|
108
106
|
|
109
107
|
# Override this on a resource instance to override the fetchable keys
|
110
|
-
def fetchable_fields
|
108
|
+
def fetchable_fields
|
111
109
|
self.class.fields
|
112
110
|
end
|
113
111
|
|
@@ -127,6 +125,14 @@ module JSONAPI
|
|
127
125
|
|
128
126
|
attr_accessor :_attributes, :_associations, :_allowed_filters , :_type
|
129
127
|
|
128
|
+
def create(context)
|
129
|
+
self.new(self.create_model, context)
|
130
|
+
end
|
131
|
+
|
132
|
+
def create_model
|
133
|
+
_model_class.new
|
134
|
+
end
|
135
|
+
|
130
136
|
def routing_options(options)
|
131
137
|
@_routing_resource_options = options
|
132
138
|
end
|
@@ -145,11 +151,11 @@ module JSONAPI
|
|
145
151
|
def attribute(attr, options = {})
|
146
152
|
@_attributes[attr] = options
|
147
153
|
define_method attr do
|
148
|
-
@
|
154
|
+
@model.send(attr)
|
149
155
|
end unless method_defined?(attr)
|
150
156
|
|
151
157
|
define_method "#{attr}=" do |value|
|
152
|
-
@
|
158
|
+
@model.send "#{attr}=", value
|
153
159
|
end unless method_defined?("#{attr}=")
|
154
160
|
end
|
155
161
|
|
@@ -182,12 +188,12 @@ module JSONAPI
|
|
182
188
|
end
|
183
189
|
|
184
190
|
# Override in your resource to filter the updateable keys
|
185
|
-
def updateable_fields(context)
|
191
|
+
def updateable_fields(context = nil)
|
186
192
|
_updateable_associations | _attributes.keys
|
187
193
|
end
|
188
194
|
|
189
195
|
# Override in your resource to filter the createable keys
|
190
|
-
def createable_fields(context)
|
196
|
+
def createable_fields(context = nil)
|
191
197
|
_updateable_associations | _attributes.keys
|
192
198
|
end
|
193
199
|
|
@@ -214,19 +220,19 @@ module JSONAPI
|
|
214
220
|
end
|
215
221
|
|
216
222
|
resources = []
|
217
|
-
_model_class.where(where_filters).includes(includes).each do |
|
218
|
-
resources.push self.new(
|
223
|
+
_model_class.where(where_filters).includes(includes).each do |model|
|
224
|
+
resources.push self.new(model, context)
|
219
225
|
end
|
220
226
|
|
221
227
|
return resources
|
222
228
|
end
|
223
229
|
|
224
230
|
def find_by_key(key, context = nil)
|
225
|
-
|
226
|
-
if
|
231
|
+
model = _model_class.where({_key => key}).first
|
232
|
+
if model.nil?
|
227
233
|
raise JSONAPI::Exceptions::RecordNotFound.new(key)
|
228
234
|
end
|
229
|
-
self.new(
|
235
|
+
self.new(model, context)
|
230
236
|
end
|
231
237
|
|
232
238
|
def verify_filters(filters, context = nil)
|
@@ -345,36 +351,36 @@ module JSONAPI
|
|
345
351
|
key = @_associations[attr].key
|
346
352
|
|
347
353
|
define_method key do
|
348
|
-
@
|
354
|
+
@model.method(key).call
|
349
355
|
end unless method_defined?(key)
|
350
356
|
|
351
|
-
define_method "_#{attr}
|
357
|
+
define_method "_#{attr}_resource" do
|
352
358
|
type_name = self.class._associations[attr].type
|
353
359
|
resource_class = self.class.resource_for(type_name)
|
354
360
|
if resource_class
|
355
|
-
|
356
|
-
return resource_class.new(
|
361
|
+
associated_model = @model.send attr
|
362
|
+
return resource_class.new(associated_model, @context)
|
357
363
|
end
|
358
|
-
end
|
364
|
+
end unless method_defined?("_#{attr}_resource")
|
359
365
|
elsif @_associations[attr].is_a?(JSONAPI::Association::HasMany)
|
360
366
|
key = @_associations[attr].key
|
361
367
|
|
362
368
|
define_method key do
|
363
|
-
@
|
369
|
+
@model.method(key).call
|
364
370
|
end unless method_defined?(key)
|
365
371
|
|
366
|
-
define_method "_#{attr}
|
372
|
+
define_method "_#{attr}_resources" do
|
367
373
|
type_name = self.class._associations[attr].type
|
368
374
|
resource_class = self.class.resource_for(type_name)
|
369
375
|
resources = []
|
370
376
|
if resource_class
|
371
|
-
|
372
|
-
|
373
|
-
resources.push resource_class.new(
|
377
|
+
associated_models = @model.send attr
|
378
|
+
associated_models.each do |associated_model|
|
379
|
+
resources.push resource_class.new(associated_model, @context)
|
374
380
|
end
|
375
381
|
end
|
376
382
|
return resources
|
377
|
-
end
|
383
|
+
end unless method_defined?("_#{attr}_resources")
|
378
384
|
end
|
379
385
|
end
|
380
386
|
end
|
@@ -13,24 +13,13 @@ module JSONAPI
|
|
13
13
|
class ResourceController < ActionController::Base
|
14
14
|
include ResourceFor
|
15
15
|
|
16
|
-
before_filter
|
17
|
-
begin
|
18
|
-
@request = JSONAPI::Request.new(params, {
|
19
|
-
context: context,
|
20
|
-
key_formatter: key_formatter
|
21
|
-
})
|
22
|
-
render_errors(@request.errors) unless @request.errors.empty?
|
23
|
-
rescue => e
|
24
|
-
handle_exceptions(e)
|
25
|
-
end
|
26
|
-
}
|
16
|
+
before_filter :setup_request
|
27
17
|
|
28
18
|
def index
|
29
19
|
render json: JSONAPI::ResourceSerializer.new.serialize_to_hash(
|
30
20
|
resource_klass.find(resource_klass.verify_filters(@request.filters, context), context),
|
31
21
|
include: @request.include,
|
32
22
|
fields: @request.fields,
|
33
|
-
context: context,
|
34
23
|
attribute_formatters: attribute_formatters,
|
35
24
|
key_formatter: key_formatter)
|
36
25
|
rescue => e
|
@@ -53,7 +42,6 @@ module JSONAPI
|
|
53
42
|
resources,
|
54
43
|
include: @request.include,
|
55
44
|
fields: @request.fields,
|
56
|
-
context: context,
|
57
45
|
attribute_formatters: attribute_formatters,
|
58
46
|
key_formatter: key_formatter)
|
59
47
|
rescue => e
|
@@ -117,6 +105,16 @@ module JSONAPI
|
|
117
105
|
@resource_klass_name ||= "#{self.class.name.demodulize.sub(/Controller$/, '').singularize}Resource"
|
118
106
|
end
|
119
107
|
|
108
|
+
def setup_request
|
109
|
+
@request = JSONAPI::Request.new(params, {
|
110
|
+
context: context,
|
111
|
+
key_formatter: key_formatter
|
112
|
+
})
|
113
|
+
render_errors(@request.errors) unless @request.errors.empty?
|
114
|
+
rescue => e
|
115
|
+
handle_exceptions(e)
|
116
|
+
end
|
117
|
+
|
120
118
|
def parse_key_array(raw)
|
121
119
|
keys = []
|
122
120
|
raw.split(/,/).collect do |key|
|
@@ -172,7 +170,6 @@ module JSONAPI
|
|
172
170
|
json: JSONAPI::ResourceSerializer.new.serialize_to_hash(resources.length > 1 ? resources : resources[0],
|
173
171
|
include: @request.include,
|
174
172
|
fields: @request.fields,
|
175
|
-
context: context,
|
176
173
|
attribute_formatters: attribute_formatters,
|
177
174
|
key_formatter: key_formatter)
|
178
175
|
else
|
@@ -15,7 +15,7 @@ module JSONAPI
|
|
15
15
|
|
16
16
|
@fields = options.fetch(:fields, {})
|
17
17
|
include = options.fetch(:include, [])
|
18
|
-
|
18
|
+
|
19
19
|
@key_formatter = options.fetch(:key_formatter, JSONAPI.configuration.key_formatter)
|
20
20
|
|
21
21
|
@linked_objects = {}
|
@@ -110,7 +110,7 @@ module JSONAPI
|
|
110
110
|
end
|
111
111
|
end
|
112
112
|
|
113
|
-
# Returns a serialized hash for the source
|
113
|
+
# Returns a serialized hash for the source model, with
|
114
114
|
def object_hash(source, requested_associations)
|
115
115
|
obj_hash = attribute_hash(source)
|
116
116
|
links = links_hash(source, requested_associations)
|
@@ -124,7 +124,7 @@ module JSONAPI
|
|
124
124
|
|
125
125
|
def attribute_hash(source)
|
126
126
|
requested = requested_fields(source.class._type)
|
127
|
-
fields = source.fetchable_fields
|
127
|
+
fields = source.fetchable_fields & source.class._attributes.keys.to_a
|
128
128
|
unless requested.nil?
|
129
129
|
fields = requested & fields
|
130
130
|
end
|
@@ -132,8 +132,7 @@ module JSONAPI
|
|
132
132
|
fields.each_with_object({}) do |name, hash|
|
133
133
|
hash[format_key(name)] = format_value(source.send(name),
|
134
134
|
source.class._attribute_options(name)[:format],
|
135
|
-
source
|
136
|
-
@context)
|
135
|
+
source)
|
137
136
|
end
|
138
137
|
end
|
139
138
|
|
@@ -149,7 +148,7 @@ module JSONAPI
|
|
149
148
|
|
150
149
|
field_set = Set.new(fields)
|
151
150
|
|
152
|
-
included_associations = source.fetchable_fields
|
151
|
+
included_associations = source.fetchable_fields & associations.keys
|
153
152
|
associations.each_with_object({}) do |(name, association), hash|
|
154
153
|
if included_associations.include? name
|
155
154
|
key = association.key
|
@@ -170,25 +169,25 @@ module JSONAPI
|
|
170
169
|
# through the associations.
|
171
170
|
if include_linked_object || include_linked_children
|
172
171
|
if association.is_a?(JSONAPI::Association::HasOne)
|
173
|
-
|
174
|
-
if
|
175
|
-
id =
|
172
|
+
resource = source.send("_#{name}_resource")
|
173
|
+
if resource
|
174
|
+
id = resource.send(association.primary_key)
|
176
175
|
associations_only = already_serialized?(type, id)
|
177
176
|
if include_linked_object && !associations_only
|
178
|
-
add_linked_object(type, id, object_hash(
|
177
|
+
add_linked_object(type, id, object_hash(resource, ia[:include_related]))
|
179
178
|
elsif include_linked_children || associations_only
|
180
|
-
links_hash(
|
179
|
+
links_hash(resource, ia[:include_related])
|
181
180
|
end
|
182
181
|
end
|
183
182
|
elsif association.is_a?(JSONAPI::Association::HasMany)
|
184
|
-
|
185
|
-
|
186
|
-
id =
|
183
|
+
resources = source.send("_#{name}_resources")
|
184
|
+
resources.each do |resource|
|
185
|
+
id = resource.send(association.primary_key)
|
187
186
|
associations_only = already_serialized?(type, id)
|
188
187
|
if include_linked_object && !associations_only
|
189
|
-
add_linked_object(type, id, object_hash(
|
188
|
+
add_linked_object(type, id, object_hash(resource, ia[:include_related]))
|
190
189
|
elsif include_linked_children || associations_only
|
191
|
-
links_hash(
|
190
|
+
links_hash(resource, ia[:include_related])
|
192
191
|
end
|
193
192
|
end
|
194
193
|
end
|
@@ -229,9 +228,9 @@ module JSONAPI
|
|
229
228
|
@key_formatter.format(key)
|
230
229
|
end
|
231
230
|
|
232
|
-
def format_value(value, format, source
|
231
|
+
def format_value(value, format, source)
|
233
232
|
value_formatter = JSONAPI::ValueFormatter.value_formatter_for(format)
|
234
|
-
value_formatter.format(value, source
|
233
|
+
value_formatter.format(value, source)
|
235
234
|
end
|
236
235
|
end
|
237
236
|
end
|
@@ -288,7 +288,7 @@ class PersonResource < JSONAPI::Resource
|
|
288
288
|
|
289
289
|
filter :name
|
290
290
|
|
291
|
-
def self.verify_custom_filter(filter, values, context
|
291
|
+
def self.verify_custom_filter(filter, values, context)
|
292
292
|
case filter
|
293
293
|
when :name
|
294
294
|
values.each do |value|
|
@@ -308,22 +308,22 @@ class AuthorResource < JSONAPI::Resource
|
|
308
308
|
|
309
309
|
filter :name
|
310
310
|
|
311
|
-
def self.find(filters, context
|
311
|
+
def self.find(filters, context)
|
312
312
|
resources = []
|
313
313
|
|
314
314
|
filters.each do |attr, filter|
|
315
|
-
_model_class.where("\"#{attr}\" LIKE \"%#{filter[0]}%\"").each do |
|
316
|
-
resources.push self.new(
|
315
|
+
_model_class.where("\"#{attr}\" LIKE \"%#{filter[0]}%\"").each do |model|
|
316
|
+
resources.push self.new(model, context)
|
317
317
|
end
|
318
318
|
end
|
319
319
|
return resources
|
320
320
|
end
|
321
321
|
|
322
|
-
def fetchable_fields
|
323
|
-
if (@
|
324
|
-
super
|
322
|
+
def fetchable_fields
|
323
|
+
if (@model.id % 2) == 1
|
324
|
+
super - [:email]
|
325
325
|
else
|
326
|
-
super
|
326
|
+
super
|
327
327
|
end
|
328
328
|
end
|
329
329
|
end
|
@@ -358,7 +358,7 @@ class PostResource < JSONAPI::Resource
|
|
358
358
|
has_many :tags, acts_as_set: true
|
359
359
|
has_many :comments, acts_as_set: false
|
360
360
|
def subject
|
361
|
-
@
|
361
|
+
@model.title
|
362
362
|
end
|
363
363
|
|
364
364
|
filters :title, :author, :tags, :comments
|
@@ -392,7 +392,7 @@ class PostResource < JSONAPI::Resource
|
|
392
392
|
|
393
393
|
def self.verify_key(key, context = nil)
|
394
394
|
raise JSONAPI::Exceptions::InvalidFieldValue.new(:id, key) unless is_num?(key)
|
395
|
-
raise JSONAPI::Exceptions::RecordNotFound.new(key) unless find_by_key(key)
|
395
|
+
raise JSONAPI::Exceptions::RecordNotFound.new(key) unless find_by_key(key, context)
|
396
396
|
return key
|
397
397
|
end
|
398
398
|
end
|
@@ -419,13 +419,13 @@ class BreedResource < JSONAPI::Resource
|
|
419
419
|
def self.find(attrs, context = nil)
|
420
420
|
breeds = []
|
421
421
|
$breed_data.breeds.values.each do |breed|
|
422
|
-
breeds.push(BreedResource.new(breed))
|
422
|
+
breeds.push(BreedResource.new(breed, context))
|
423
423
|
end
|
424
424
|
breeds
|
425
425
|
end
|
426
426
|
|
427
427
|
def self.find_by_key(id, context = nil)
|
428
|
-
BreedResource.new($breed_data.breeds[id.to_i])
|
428
|
+
BreedResource.new($breed_data.breeds[id.to_i], context)
|
429
429
|
end
|
430
430
|
end
|
431
431
|
|
data/test/test_helper.rb
CHANGED
@@ -113,7 +113,7 @@ end
|
|
113
113
|
|
114
114
|
class DateWithTimezoneValueFormatter < JSONAPI::ValueFormatter
|
115
115
|
class << self
|
116
|
-
def format(raw_value,
|
116
|
+
def format(raw_value, context)
|
117
117
|
raw_value.in_time_zone('Eastern Time (US & Canada)').to_s
|
118
118
|
end
|
119
119
|
end
|
@@ -121,7 +121,7 @@ end
|
|
121
121
|
|
122
122
|
class DateValueFormatter < JSONAPI::ValueFormatter
|
123
123
|
class << self
|
124
|
-
def format(raw_value,
|
124
|
+
def format(raw_value, context)
|
125
125
|
raw_value.strftime('%m/%d/%Y')
|
126
126
|
end
|
127
127
|
end
|
@@ -129,11 +129,11 @@ end
|
|
129
129
|
|
130
130
|
class TitleValueFormatter < JSONAPI::ValueFormatter
|
131
131
|
class << self
|
132
|
-
def format(raw_value, source
|
133
|
-
super(raw_value, source
|
132
|
+
def format(raw_value, source)
|
133
|
+
super(raw_value, source).titlecase
|
134
134
|
end
|
135
135
|
|
136
|
-
def unformat(value,
|
136
|
+
def unformat(value, context)
|
137
137
|
value.to_s.downcase
|
138
138
|
end
|
139
139
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsonapi-resources
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Gebhardt
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-10-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|