jsonapi-resources 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|