json_api_client 1.0.0.beta5 → 1.0.0.beta6
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/lib/json_api_client/helpers/callbacks.rb +27 -0
- data/lib/json_api_client/helpers/dirty.rb +71 -0
- data/lib/json_api_client/helpers/dynamic_attributes.rb +1 -1
- data/lib/json_api_client/helpers.rb +2 -13
- data/lib/json_api_client/included_data.rb +1 -1
- data/lib/json_api_client/parsers/parser.rb +3 -2
- data/lib/json_api_client/query/requestor.rb +3 -3
- data/lib/json_api_client/relationships/relations.rb +16 -5
- data/lib/json_api_client/resource.rb +393 -20
- data/lib/json_api_client/version.rb +1 -1
- metadata +19 -17
- data/lib/json_api_client/helpers/associable.rb +0 -57
- data/lib/json_api_client/helpers/attributable.rb +0 -55
- data/lib/json_api_client/helpers/custom_endpoints.rb +0 -37
- data/lib/json_api_client/helpers/custom_headers.rb +0 -31
- data/lib/json_api_client/helpers/initializable.rb +0 -28
- data/lib/json_api_client/helpers/linkable.rb +0 -22
- data/lib/json_api_client/helpers/paginatable.rb +0 -14
- data/lib/json_api_client/helpers/parsable.rb +0 -19
- data/lib/json_api_client/helpers/queryable.rb +0 -37
- data/lib/json_api_client/helpers/relatable.rb +0 -39
- data/lib/json_api_client/helpers/requestable.rb +0 -56
- data/lib/json_api_client/helpers/schemable.rb +0 -68
- data/lib/json_api_client/helpers/serializable.rb +0 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c39c70dd7ca6c162a658718790120555ac010083
|
4
|
+
data.tar.gz: 83eaa82464904a5761933f4b2f41576f280a281a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 36612db285d7249f01b5cfbff6594297ed3c838faee90b5d646ad9c51767b6cbd1bc4511063416691f19db92e06fecf54d60aa47c1d0fa23701ca43eaced2b92
|
7
|
+
data.tar.gz: ad590905aa3c8921ccd199525ad367465acfd048e3516da9722f364c39bdcbd0dbf01d5f4c84a12b9e43c3e9e68cebee16eb73c67436c69ac7ea014d7d270e42
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module JsonApiClient
|
2
|
+
module Helpers
|
3
|
+
module Callbacks
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
extend ActiveModel::Callbacks
|
8
|
+
define_model_callbacks :save, :destroy, :create, :update
|
9
|
+
end
|
10
|
+
|
11
|
+
def save
|
12
|
+
run_callbacks :save do
|
13
|
+
run_callbacks (persisted? ? :update : :create) do
|
14
|
+
super
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def destroy
|
20
|
+
run_callbacks :destroy do
|
21
|
+
super
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module JsonApiClient
|
2
|
+
module Helpers
|
3
|
+
module Dirty
|
4
|
+
|
5
|
+
def changed?
|
6
|
+
changed_attributes.present?
|
7
|
+
end
|
8
|
+
|
9
|
+
def changed
|
10
|
+
changed_attributes.keys
|
11
|
+
end
|
12
|
+
|
13
|
+
def changed_attributes
|
14
|
+
@changed_attributes ||= ActiveSupport::HashWithIndifferentAccess.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def clear_changes_information
|
18
|
+
@changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def set_all_attributes_dirty
|
22
|
+
attributes.each do |k, v|
|
23
|
+
set_attribute_was(k, v)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def attribute_will_change!(attr)
|
28
|
+
return if attribute_changed?(attr)
|
29
|
+
set_attribute_was(attr, attributes[attr])
|
30
|
+
end
|
31
|
+
|
32
|
+
def set_attribute_was(attr, value)
|
33
|
+
begin
|
34
|
+
value = value.duplicable? ? value.clone : value
|
35
|
+
changed_attributes[attr] = value
|
36
|
+
rescue TypeError, NoMethodError
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def attribute_was(attr) # :nodoc:
|
41
|
+
attribute_changed?(attr) ? changed_attributes[attr] : attributes[attr]
|
42
|
+
end
|
43
|
+
|
44
|
+
def attribute_changed?(attr)
|
45
|
+
changed.include?(attr.to_s)
|
46
|
+
end
|
47
|
+
|
48
|
+
def attribute_change(attr)
|
49
|
+
[changed_attributes[attr], attributes[attr]] if attribute_changed?(attr)
|
50
|
+
end
|
51
|
+
|
52
|
+
protected
|
53
|
+
|
54
|
+
def method_missing(method, *args, &block)
|
55
|
+
if method.to_s =~ /^(.*)_changed\?$/
|
56
|
+
has_attribute?($1) ? attribute_changed?($1) : nil
|
57
|
+
elsif method.to_s =~ /^(.*)_was$/
|
58
|
+
has_attribute?($1) ? attribute_was($1) : nil
|
59
|
+
else
|
60
|
+
super
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def set_attribute(name, value)
|
65
|
+
attribute_will_change!(name) if value != attributes[name]
|
66
|
+
super
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -1,18 +1,7 @@
|
|
1
1
|
module JsonApiClient
|
2
2
|
module Helpers
|
3
|
-
autoload :
|
4
|
-
autoload :
|
5
|
-
autoload :CustomEndpoints, 'json_api_client/helpers/custom_endpoints'
|
6
|
-
autoload :CustomHeaders, 'json_api_client/helpers/custom_headers'
|
3
|
+
autoload :Callbacks, 'json_api_client/helpers/callbacks'
|
4
|
+
autoload :Dirty, 'json_api_client/helpers/dirty'
|
7
5
|
autoload :DynamicAttributes, 'json_api_client/helpers/dynamic_attributes'
|
8
|
-
autoload :Initializable, 'json_api_client/helpers/initializable'
|
9
|
-
autoload :Linkable, 'json_api_client/helpers/linkable'
|
10
|
-
autoload :Relatable, 'json_api_client/helpers/relatable'
|
11
|
-
autoload :Paginatable, 'json_api_client/helpers/paginatable'
|
12
|
-
autoload :Parsable, 'json_api_client/helpers/parsable'
|
13
|
-
autoload :Queryable, 'json_api_client/helpers/queryable'
|
14
|
-
autoload :Requestable, 'json_api_client/helpers/requestable'
|
15
|
-
autoload :Schemable, 'json_api_client/helpers/schemable'
|
16
|
-
autoload :Serializable, 'json_api_client/helpers/serializable'
|
17
6
|
end
|
18
7
|
end
|
@@ -10,7 +10,7 @@ module JsonApiClient
|
|
10
10
|
h[type] = records.map do |datum|
|
11
11
|
params = klass.parser.parameters_from_resource(datum)
|
12
12
|
resource = klass.load(params)
|
13
|
-
resource.
|
13
|
+
resource.last_result_set = result_set
|
14
14
|
resource
|
15
15
|
end.index_by(&:id)
|
16
16
|
h
|
@@ -3,7 +3,8 @@ module JsonApiClient
|
|
3
3
|
class Parser
|
4
4
|
class << self
|
5
5
|
def parse(klass, response)
|
6
|
-
data = response.body
|
6
|
+
data = response.body.present? ? response.body : {}
|
7
|
+
|
7
8
|
ResultSet.new.tap do |result_set|
|
8
9
|
result_set.record_class = klass
|
9
10
|
result_set.uri = response.env[:url]
|
@@ -66,7 +67,7 @@ module JsonApiClient
|
|
66
67
|
results = [results] unless results.is_a?(Array)
|
67
68
|
resources = results.map do |res|
|
68
69
|
resource = result_set.record_class.load(parameters_from_resource(res))
|
69
|
-
resource.
|
70
|
+
resource.last_result_set = result_set
|
70
71
|
resource
|
71
72
|
end
|
72
73
|
result_set.concat(resources)
|
@@ -10,13 +10,13 @@ module JsonApiClient
|
|
10
10
|
# expects a record
|
11
11
|
def create(record)
|
12
12
|
request(:post, klass.path(record.attributes), {
|
13
|
-
data: record.
|
13
|
+
data: record.as_json_api
|
14
14
|
})
|
15
15
|
end
|
16
16
|
|
17
17
|
def update(record)
|
18
18
|
request(:patch, resource_path(record.attributes), {
|
19
|
-
data: record.
|
19
|
+
data: record.as_json_api
|
20
20
|
})
|
21
21
|
end
|
22
22
|
|
@@ -60,7 +60,7 @@ module JsonApiClient
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def request(type, path, params)
|
63
|
-
klass.parse(connection.run(type, path, params, klass.custom_headers))
|
63
|
+
klass.parser.parse(klass, connection.run(type, path, params, klass.custom_headers))
|
64
64
|
end
|
65
65
|
|
66
66
|
end
|
@@ -2,32 +2,43 @@ module JsonApiClient
|
|
2
2
|
module Relationships
|
3
3
|
class Relations
|
4
4
|
include Helpers::DynamicAttributes
|
5
|
+
include Helpers::Dirty
|
6
|
+
include ActiveModel::Serialization
|
5
7
|
|
6
8
|
def initialize(relations)
|
7
9
|
self.attributes = relations
|
10
|
+
clear_changes_information
|
8
11
|
end
|
9
12
|
|
10
13
|
def present?
|
11
14
|
attributes.present?
|
12
15
|
end
|
13
16
|
|
14
|
-
def
|
15
|
-
Hash[
|
16
|
-
|
17
|
-
|
17
|
+
def as_json_api
|
18
|
+
Hash[attributes_for_serialization.map do |k, v|
|
19
|
+
[k, v.slice("data")] if v.has_key?("data")
|
20
|
+
end.compact]
|
21
|
+
end
|
22
|
+
|
23
|
+
def attributes_for_serialization
|
24
|
+
attributes.slice(*changed)
|
18
25
|
end
|
19
26
|
|
20
27
|
protected
|
21
28
|
|
22
29
|
def set_attribute(name, value)
|
23
|
-
|
30
|
+
value = case value
|
24
31
|
when JsonApiClient::Resource
|
25
32
|
{data: value.as_relation}
|
26
33
|
when Array
|
27
34
|
{data: value.map(&:as_relation)}
|
35
|
+
when NilClass
|
36
|
+
{data: nil}
|
28
37
|
else
|
29
38
|
value
|
30
39
|
end
|
40
|
+
attribute_will_change!(name) if value != attributes[name]
|
41
|
+
attributes[name] = value
|
31
42
|
end
|
32
43
|
|
33
44
|
end
|
@@ -1,40 +1,413 @@
|
|
1
1
|
require 'forwardable'
|
2
2
|
require 'active_support/all'
|
3
|
+
require 'active_model'
|
3
4
|
|
4
5
|
module JsonApiClient
|
5
6
|
class Resource
|
6
|
-
|
7
|
-
|
8
|
-
|
7
|
+
extend ActiveModel::Naming
|
8
|
+
extend ActiveModel::Translation
|
9
|
+
include ActiveModel::Validations
|
10
|
+
include ActiveModel::Conversion
|
11
|
+
include ActiveModel::Serialization
|
12
|
+
|
13
|
+
include Helpers::DynamicAttributes
|
14
|
+
include Helpers::Dirty
|
15
|
+
|
16
|
+
attr_accessor :last_result_set,
|
17
|
+
:links,
|
18
|
+
:relationships
|
19
|
+
class_attribute :site,
|
20
|
+
:primary_key,
|
21
|
+
:parser,
|
22
|
+
:paginator,
|
23
|
+
:connection_class,
|
24
|
+
:connection_object,
|
25
|
+
:connection_options,
|
26
|
+
:query_builder,
|
27
|
+
:linker,
|
28
|
+
:relationship_linker,
|
29
|
+
:read_only_attributes,
|
30
|
+
:requestor_class,
|
31
|
+
:associations,
|
32
|
+
instance_accessor: false
|
33
|
+
self.primary_key = :id
|
34
|
+
self.parser = Parsers::Parser
|
35
|
+
self.paginator = Paginating::Paginator
|
36
|
+
self.connection_class = Connection
|
37
|
+
self.connection_options = {}
|
38
|
+
self.query_builder = Query::Builder
|
39
|
+
self.linker = Linking::Links
|
40
|
+
self.relationship_linker = Relationships::Relations
|
41
|
+
self.read_only_attributes = [:id, :type, :links, :meta, :relationships]
|
42
|
+
self.requestor_class = Query::Requestor
|
43
|
+
self.associations = []
|
44
|
+
|
45
|
+
include Associations::BelongsTo
|
46
|
+
include Associations::HasMany
|
47
|
+
include Associations::HasOne
|
9
48
|
|
10
49
|
class << self
|
11
|
-
|
12
|
-
|
13
|
-
File.join(site, path)
|
14
|
-
end
|
50
|
+
extend Forwardable
|
51
|
+
def_delegators :_new_scope, :where, :order, :includes, :select, :all, :paginate, :page, :first, :find
|
15
52
|
|
53
|
+
# The table name for this resource. i.e. Article -> articles, Person -> people
|
54
|
+
#
|
55
|
+
# @return [String] The table name for this resource
|
16
56
|
def table_name
|
17
57
|
resource_name.pluralize
|
18
58
|
end
|
19
59
|
|
60
|
+
# The name of a single resource. i.e. Article -> article, Person -> person
|
61
|
+
#
|
62
|
+
# @return [String]
|
20
63
|
def resource_name
|
21
64
|
name.demodulize.underscore
|
22
65
|
end
|
66
|
+
|
67
|
+
# Load a resource object from attributes and consider it persisted
|
68
|
+
#
|
69
|
+
# @return [Resource] Persisted resource object
|
70
|
+
def load(params)
|
71
|
+
new(params).tap do |resource|
|
72
|
+
resource.mark_as_persisted!
|
73
|
+
resource.clear_changes_information
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Return/build a connection object
|
78
|
+
#
|
79
|
+
# @return [Connection] The connection to the json api server
|
80
|
+
def connection(rebuild = false, &block)
|
81
|
+
_build_connection(&block)
|
82
|
+
connection_object
|
83
|
+
end
|
84
|
+
|
85
|
+
# Param names that will be considered path params. They will be used
|
86
|
+
# to build the resource path rather than treated as attributes
|
87
|
+
#
|
88
|
+
# @return [Array] Param name symbols of parameters that will be treated as path parameters
|
89
|
+
def prefix_params
|
90
|
+
_belongs_to_associations.map(&:param)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Return the path or path pattern for this resource
|
94
|
+
def path(params = nil)
|
95
|
+
parts = [table_name]
|
96
|
+
if params
|
97
|
+
path_params = params.delete(:path) || params
|
98
|
+
parts.unshift(_prefix_path % path_params.symbolize_keys)
|
99
|
+
else
|
100
|
+
parts.unshift(_prefix_path)
|
101
|
+
end
|
102
|
+
parts.reject!{|part| part == "" }
|
103
|
+
File.join(*parts)
|
104
|
+
rescue KeyError
|
105
|
+
raise ArgumentError, "Not all prefix parameters specified"
|
106
|
+
end
|
107
|
+
|
108
|
+
# Create a new instance of this resource class
|
109
|
+
#
|
110
|
+
# @param attributes [Hash] The attributes to create this resource with
|
111
|
+
# @return [Resource] The instance you tried to create. You will have to check the persisted state or errors on this object to see success/failure.
|
112
|
+
def create(attributes = {})
|
113
|
+
new(attributes).tap do |resource|
|
114
|
+
resource.save
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Within the given block, add these headers to all requests made by
|
119
|
+
# the resource class
|
120
|
+
#
|
121
|
+
# @param headers [Hash] The headers to send along
|
122
|
+
# @param block [Block] The block where headers will be set for
|
123
|
+
def with_headers(headers)
|
124
|
+
self._custom_headers = headers
|
125
|
+
yield
|
126
|
+
ensure
|
127
|
+
self._custom_headers = {}
|
128
|
+
end
|
129
|
+
|
130
|
+
# The current custom headers to send with any request made by this
|
131
|
+
# resource class
|
132
|
+
#
|
133
|
+
# @return [Hash] Headers
|
134
|
+
def custom_headers
|
135
|
+
_header_store.to_h
|
136
|
+
end
|
137
|
+
|
138
|
+
# Returns the requestor for this resource class
|
139
|
+
#
|
140
|
+
# @return [Requestor] The requestor for this resource class
|
141
|
+
def requestor
|
142
|
+
@requestor ||= requestor_class.new(self)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Default attributes that every instance of this resource should be
|
146
|
+
# intialized with. Optionally, override this method in a subclass.
|
147
|
+
#
|
148
|
+
# @return [Hash] Default attributes
|
149
|
+
def default_attributes
|
150
|
+
{type: table_name}
|
151
|
+
end
|
152
|
+
|
153
|
+
# Returns the schema for this resource class
|
154
|
+
#
|
155
|
+
# @return [Schema] The schema for this resource class
|
156
|
+
def schema
|
157
|
+
@schema ||= Schema.new
|
158
|
+
end
|
159
|
+
|
160
|
+
protected
|
161
|
+
|
162
|
+
# Declares a new class/instance method that acts on the collection/member
|
163
|
+
#
|
164
|
+
# @param name [Symbol] the name of the endpoint
|
165
|
+
# @param options [Hash] endpoint options
|
166
|
+
# @option [Symbol] :on One of [:collection or :member] to decide whether it's a collect or member method
|
167
|
+
# @option [Symbol] :request_method The request method (:get, :post, etc)
|
168
|
+
def custom_endpoint(name, options = {})
|
169
|
+
if :collection == options.delete(:on)
|
170
|
+
collection_endpoint(name, options)
|
171
|
+
else
|
172
|
+
member_endpoint(name, options)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# Declares a new class method that acts on the collection
|
177
|
+
#
|
178
|
+
# @param name [Symbol] the name of the endpoint and the method name
|
179
|
+
# @param options [Hash] endpoint options
|
180
|
+
# @option options [Symbol] :request_method The request method (:get, :post, etc)
|
181
|
+
def collection_endpoint(name, options = {})
|
182
|
+
metaclass = class << self
|
183
|
+
self
|
184
|
+
end
|
185
|
+
metaclass.instance_eval do
|
186
|
+
define_method(name) do |*params|
|
187
|
+
request_params = params.first || {}
|
188
|
+
requestor.custom(name, options, request_params)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# Declares a new instance method that acts on the member object
|
194
|
+
#
|
195
|
+
# @param name [Symbol] the name of the endpoint and the method name
|
196
|
+
# @param options [Hash] endpoint options
|
197
|
+
# @option options [Symbol] :request_method The request method (:get, :post, etc)
|
198
|
+
def member_endpoint(name, options = {})
|
199
|
+
define_method name do |*params|
|
200
|
+
request_params = params.first || {}
|
201
|
+
request_params[self.class.primary_key] = attributes.fetch(self.class.primary_key)
|
202
|
+
self.class.requestor.custom(name, options, request_params)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# Declares a new property by name
|
207
|
+
#
|
208
|
+
# @param name [Symbol] the name of the property
|
209
|
+
# @param options [Hash] property options
|
210
|
+
# @option options [Symbol] :type The property type
|
211
|
+
# @option options [Symbol] :default The default value for the property
|
212
|
+
def property(name, options = {})
|
213
|
+
schema.add(name, options)
|
214
|
+
end
|
215
|
+
|
216
|
+
# Declare multiple properties with the same optional options
|
217
|
+
#
|
218
|
+
# @param [Array<Symbol>] names
|
219
|
+
# @param options [Hash] property options
|
220
|
+
# @option options [Symbol] :type The property type
|
221
|
+
# @option options [Symbol] :default The default value for the property
|
222
|
+
def properties(*names)
|
223
|
+
options = names.last.is_a?(Hash) ? names.pop : {}
|
224
|
+
names.each do |name|
|
225
|
+
property name, options
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def _belongs_to_associations
|
230
|
+
associations.select{|association| association.is_a?(Associations::BelongsTo::Association) }
|
231
|
+
end
|
232
|
+
|
233
|
+
def _prefix_path
|
234
|
+
_belongs_to_associations.map(&:to_prefix_path).join("/")
|
235
|
+
end
|
236
|
+
|
237
|
+
def _new_scope
|
238
|
+
query_builder.new(self)
|
239
|
+
end
|
240
|
+
|
241
|
+
def _custom_headers=(headers)
|
242
|
+
_header_store.replace(headers)
|
243
|
+
end
|
244
|
+
|
245
|
+
def _header_store
|
246
|
+
Thread.current["json_api_client-#{resource_name}"] ||= {}
|
247
|
+
end
|
248
|
+
|
249
|
+
def _build_connection(rebuild = false)
|
250
|
+
return connection_object unless connection_object.nil? || rebuild
|
251
|
+
self.connection_object = connection_class.new(connection_options.merge(site: site)).tap do |conn|
|
252
|
+
yield(conn) if block_given?
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
# Instantiate a new resource object
|
258
|
+
#
|
259
|
+
# @param params [Hash] Attributes, links, and relationships
|
260
|
+
def initialize(params = {})
|
261
|
+
self.links = self.class.linker.new(params.delete("links") || {})
|
262
|
+
self.relationships = self.class.relationship_linker.new(params.delete("relationships") || {})
|
263
|
+
self.class.associations.each do |association|
|
264
|
+
if params.has_key?(association.attr_name.to_s)
|
265
|
+
set_attribute(association.attr_name, association.parse(params[association.attr_name.to_s]))
|
266
|
+
end
|
267
|
+
end
|
268
|
+
self.attributes = params.merge(self.class.default_attributes)
|
269
|
+
self.class.schema.each_property do |property|
|
270
|
+
attributes[property.name] = property.default unless attributes.has_key?(property.name)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
# Set the current attributes and try to save them
|
275
|
+
#
|
276
|
+
# @param attrs [Hash] Attributes to update
|
277
|
+
# @return [Boolean] Whether the update succeeded or not
|
278
|
+
def update_attributes(attrs = {})
|
279
|
+
self.attributes = attrs
|
280
|
+
save
|
281
|
+
end
|
282
|
+
|
283
|
+
# Mark the record as persisted
|
284
|
+
def mark_as_persisted!
|
285
|
+
@persisted = true
|
286
|
+
end
|
287
|
+
|
288
|
+
# Whether or not this record has been persisted to the database previously
|
289
|
+
#
|
290
|
+
# @return [Boolean]
|
291
|
+
def persisted?
|
292
|
+
!!@persisted && has_attribute?(self.class.primary_key)
|
23
293
|
end
|
24
294
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
295
|
+
# Returns true if this is a new record (never persisted to the database)
|
296
|
+
#
|
297
|
+
# @return [Boolean]
|
298
|
+
def new_record?
|
299
|
+
!persisted?
|
300
|
+
end
|
301
|
+
|
302
|
+
# When we represent this resource as a relationship, we do so with id & type
|
303
|
+
#
|
304
|
+
# @return [Hash] Representation of this object as a relation
|
305
|
+
def as_relation
|
306
|
+
attributes.slice(:type, self.class.primary_key)
|
307
|
+
end
|
308
|
+
|
309
|
+
# When we represent this resource for serialization (create/update), we do so
|
310
|
+
# with this implementation
|
311
|
+
#
|
312
|
+
# @return [Hash] Representation of this object as JSONAPI object
|
313
|
+
def as_json_api(*)
|
314
|
+
attributes.slice(:id, :type).tap do |h|
|
315
|
+
relationships_for_serialization.tap do |r|
|
316
|
+
h[:relationships] = r unless r.empty?
|
317
|
+
end
|
318
|
+
h[:attributes] = attributes_for_serialization
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
# Mark all attributes for this record as dirty
|
323
|
+
def set_all_dirty!
|
324
|
+
set_all_attributes_dirty
|
325
|
+
relationships.set_all_attributes_dirty if relationships
|
326
|
+
end
|
327
|
+
|
328
|
+
# Commit the current changes to the resource to the remote server.
|
329
|
+
# If the resource was previously loaded from the server, we will
|
330
|
+
# try to update the record. Otherwise if it's a new record, then
|
331
|
+
# we will try to create it
|
332
|
+
#
|
333
|
+
# @return [Boolean] Whether or not the save succeeded
|
334
|
+
def save
|
335
|
+
return false unless valid?
|
336
|
+
|
337
|
+
self.last_result_set = if persisted?
|
338
|
+
self.class.requestor.update(self)
|
339
|
+
else
|
340
|
+
self.class.requestor.create(self)
|
341
|
+
end
|
38
342
|
|
343
|
+
if last_result_set.has_errors?
|
344
|
+
last_result_set.errors.each do |error|
|
345
|
+
if error.source_parameter
|
346
|
+
errors.add(error.source_parameter, error.title)
|
347
|
+
else
|
348
|
+
errors.add(:base, error.title)
|
349
|
+
end
|
350
|
+
end
|
351
|
+
false
|
352
|
+
else
|
353
|
+
self.errors.clear if self.errors
|
354
|
+
mark_as_persisted!
|
355
|
+
if updated = last_result_set.first
|
356
|
+
self.attributes = updated.attributes
|
357
|
+
end
|
358
|
+
true
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
# Try to destroy this resource
|
363
|
+
#
|
364
|
+
# @return [Boolean] Whether or not the destroy succeeded
|
365
|
+
def destroy
|
366
|
+
self.last_result_set = self.class.requestor.destroy(self)
|
367
|
+
if !last_result_set.has_errors?
|
368
|
+
self.attributes.clear
|
369
|
+
true
|
370
|
+
else
|
371
|
+
false
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
def inspect
|
376
|
+
"#<#{self.class.name}:@attributes=#{attributes.inspect}>"
|
377
|
+
end
|
378
|
+
|
379
|
+
protected
|
380
|
+
|
381
|
+
def method_missing(method, *args)
|
382
|
+
return super unless relationships && relationships.has_attribute?(method) && last_result_set.included
|
383
|
+
last_result_set.included.data_for(method, relationships[method])
|
384
|
+
end
|
385
|
+
|
386
|
+
def respond_to_missing?(symbol, include_all = false)
|
387
|
+
return true if relationships && relationships.has_attribute?(symbol)
|
388
|
+
super
|
389
|
+
end
|
390
|
+
|
391
|
+
def set_attribute(name, value)
|
392
|
+
property = property_for(name)
|
393
|
+
value = property.cast(value) if property
|
394
|
+
super(name, value)
|
395
|
+
end
|
396
|
+
|
397
|
+
def has_attribute?(attr_name)
|
398
|
+
!!property_for(attr_name) || super
|
399
|
+
end
|
400
|
+
|
401
|
+
def property_for(name)
|
402
|
+
self.class.schema.find(name)
|
403
|
+
end
|
404
|
+
|
405
|
+
def attributes_for_serialization
|
406
|
+
attributes.except(*self.class.read_only_attributes).slice(*changed)
|
407
|
+
end
|
408
|
+
|
409
|
+
def relationships_for_serialization
|
410
|
+
relationships.as_json_api
|
411
|
+
end
|
39
412
|
end
|
40
413
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: json_api_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.
|
4
|
+
version: 1.0.0.beta6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeff Ching
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-07-
|
11
|
+
date: 2015-07-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '2.2'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: activemodel
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 3.2.0
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 3.2.0
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: webmock
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -113,20 +127,9 @@ files:
|
|
113
127
|
- lib/json_api_client/error_collector.rb
|
114
128
|
- lib/json_api_client/errors.rb
|
115
129
|
- lib/json_api_client/helpers.rb
|
116
|
-
- lib/json_api_client/helpers/
|
117
|
-
- lib/json_api_client/helpers/
|
118
|
-
- lib/json_api_client/helpers/custom_endpoints.rb
|
119
|
-
- lib/json_api_client/helpers/custom_headers.rb
|
130
|
+
- lib/json_api_client/helpers/callbacks.rb
|
131
|
+
- lib/json_api_client/helpers/dirty.rb
|
120
132
|
- lib/json_api_client/helpers/dynamic_attributes.rb
|
121
|
-
- lib/json_api_client/helpers/initializable.rb
|
122
|
-
- lib/json_api_client/helpers/linkable.rb
|
123
|
-
- lib/json_api_client/helpers/paginatable.rb
|
124
|
-
- lib/json_api_client/helpers/parsable.rb
|
125
|
-
- lib/json_api_client/helpers/queryable.rb
|
126
|
-
- lib/json_api_client/helpers/relatable.rb
|
127
|
-
- lib/json_api_client/helpers/requestable.rb
|
128
|
-
- lib/json_api_client/helpers/schemable.rb
|
129
|
-
- lib/json_api_client/helpers/serializable.rb
|
130
133
|
- lib/json_api_client/implementation.rb
|
131
134
|
- lib/json_api_client/included_data.rb
|
132
135
|
- lib/json_api_client/linking.rb
|
@@ -172,9 +175,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
172
175
|
version: 1.3.1
|
173
176
|
requirements: []
|
174
177
|
rubyforge_project:
|
175
|
-
rubygems_version: 2.
|
178
|
+
rubygems_version: 2.4.5
|
176
179
|
signing_key:
|
177
180
|
specification_version: 4
|
178
181
|
summary: Build client libraries compliant with specification defined by jsonapi.org
|
179
182
|
test_files: []
|
180
|
-
has_rdoc:
|
@@ -1,57 +0,0 @@
|
|
1
|
-
module JsonApiClient
|
2
|
-
module Helpers
|
3
|
-
module Associable
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
included do
|
7
|
-
class_attribute :associations, instance_accessor: false
|
8
|
-
self.associations = []
|
9
|
-
|
10
|
-
include Associations::BelongsTo
|
11
|
-
include Associations::HasMany
|
12
|
-
include Associations::HasOne
|
13
|
-
|
14
|
-
initializer :load_associations
|
15
|
-
end
|
16
|
-
|
17
|
-
module ClassMethods
|
18
|
-
def belongs_to_associations
|
19
|
-
associations.select{|association| association.is_a?(Associations::BelongsTo::Association) }
|
20
|
-
end
|
21
|
-
|
22
|
-
def prefix_params
|
23
|
-
belongs_to_associations.map(&:param)
|
24
|
-
end
|
25
|
-
|
26
|
-
def prefix_path
|
27
|
-
belongs_to_associations.map(&:to_prefix_path).join("/")
|
28
|
-
end
|
29
|
-
|
30
|
-
def path(params = nil)
|
31
|
-
parts = [table_name]
|
32
|
-
if params
|
33
|
-
path_params = params.delete(:path) || params
|
34
|
-
parts.unshift(prefix_path % path_params.symbolize_keys)
|
35
|
-
else
|
36
|
-
parts.unshift(prefix_path)
|
37
|
-
end
|
38
|
-
parts.reject!{|part| part == "" }
|
39
|
-
File.join(*parts)
|
40
|
-
rescue KeyError
|
41
|
-
raise ArgumentError, "Not all prefix parameters specified"
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
protected
|
46
|
-
|
47
|
-
def load_associations(params)
|
48
|
-
self.class.associations.each do |association|
|
49
|
-
if params.has_key?(association.attr_name.to_s)
|
50
|
-
set_attribute(association.attr_name, association.parse(params[association.attr_name.to_s]))
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
@@ -1,55 +0,0 @@
|
|
1
|
-
module JsonApiClient
|
2
|
-
module Helpers
|
3
|
-
module Attributable
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
included do
|
7
|
-
include DynamicAttributes
|
8
|
-
attr_accessor :errors
|
9
|
-
initializer do |obj, params|
|
10
|
-
obj.attributes = params.merge(obj.class.default_attributes)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
module ClassMethods
|
15
|
-
def load(params)
|
16
|
-
new(params).tap do |resource|
|
17
|
-
resource.mark_as_persisted!
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def default_attributes
|
22
|
-
{type: table_name}
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def update_attributes(attrs = {})
|
27
|
-
self.attributes = attrs
|
28
|
-
save
|
29
|
-
end
|
30
|
-
|
31
|
-
def mark_as_persisted!
|
32
|
-
@persisted = true
|
33
|
-
end
|
34
|
-
|
35
|
-
def persisted?
|
36
|
-
!!@persisted && has_attribute?(primary_key)
|
37
|
-
end
|
38
|
-
|
39
|
-
def query_params
|
40
|
-
attributes.except(primary_key)
|
41
|
-
end
|
42
|
-
|
43
|
-
def to_param
|
44
|
-
attributes.fetch(primary_key, "").to_s
|
45
|
-
end
|
46
|
-
|
47
|
-
protected
|
48
|
-
|
49
|
-
def ==(other)
|
50
|
-
self.class == other.class && attributes == other.attributes
|
51
|
-
end
|
52
|
-
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
module JsonApiClient
|
2
|
-
module Helpers
|
3
|
-
module CustomEndpoints
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
module ClassMethods
|
7
|
-
def custom_endpoint(name, options = {})
|
8
|
-
if :collection == options.delete(:on)
|
9
|
-
collection_endpoint(name, options)
|
10
|
-
else
|
11
|
-
member_endpoint(name, options)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def collection_endpoint(name, options = {})
|
16
|
-
metaclass = class << self
|
17
|
-
self
|
18
|
-
end
|
19
|
-
metaclass.instance_eval do
|
20
|
-
define_method(name) do |*params|
|
21
|
-
request_params = params.first || {}
|
22
|
-
requestor.custom(name, options, request_params)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def member_endpoint(name, options = {})
|
28
|
-
define_method name do |*params|
|
29
|
-
request_params = params.first || {}
|
30
|
-
request_params[self.class.primary_key] = attributes.fetch(primary_key)
|
31
|
-
self.class.requestor.custom(name, options, request_params)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
module JsonApiClient
|
2
|
-
module Helpers
|
3
|
-
module CustomHeaders
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
module ClassMethods
|
7
|
-
def with_headers(headers)
|
8
|
-
self.custom_headers = headers
|
9
|
-
yield
|
10
|
-
ensure
|
11
|
-
self.custom_headers = {}
|
12
|
-
end
|
13
|
-
|
14
|
-
def custom_headers
|
15
|
-
header_store
|
16
|
-
end
|
17
|
-
|
18
|
-
def custom_headers=(headers)
|
19
|
-
header_store.replace(headers)
|
20
|
-
end
|
21
|
-
|
22
|
-
protected
|
23
|
-
|
24
|
-
def header_store
|
25
|
-
Thread.current["json_api_client-#{resource_name}"] ||= {}
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
module JsonApiClient
|
2
|
-
module Helpers
|
3
|
-
module Initializable
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
included do
|
7
|
-
class_attribute :initializers, instance_accessor: false
|
8
|
-
self.initializers = []
|
9
|
-
end
|
10
|
-
|
11
|
-
module ClassMethods
|
12
|
-
def initializer(method = nil, &block)
|
13
|
-
self.initializers.push(method || block)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def initialize(params = {})
|
18
|
-
self.class.initializers.each do |initializer|
|
19
|
-
if initializer.respond_to?(:call)
|
20
|
-
initializer.call(self, params)
|
21
|
-
else
|
22
|
-
self.send(initializer, params)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
module JsonApiClient
|
2
|
-
module Helpers
|
3
|
-
module Linkable
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
included do
|
7
|
-
class_attribute :linker, instance_accessor: false
|
8
|
-
self.linker = Linking::Links
|
9
|
-
|
10
|
-
# the links for this resource
|
11
|
-
attr_accessor :links
|
12
|
-
|
13
|
-
initializer do |obj, params|
|
14
|
-
links = params && params.delete("links")
|
15
|
-
links ||= {}
|
16
|
-
obj.links = obj.class.linker.new(links)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
module JsonApiClient
|
2
|
-
module Helpers
|
3
|
-
module Parsable
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
included do
|
7
|
-
class_attribute :parser, instance_accessor: false
|
8
|
-
self.parser = Parsers::Parser
|
9
|
-
end
|
10
|
-
|
11
|
-
module ClassMethods
|
12
|
-
def parse(data)
|
13
|
-
parser.parse(self, data)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
module JsonApiClient
|
2
|
-
module Helpers
|
3
|
-
module Queryable
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
included do
|
7
|
-
class << self
|
8
|
-
extend Forwardable
|
9
|
-
def_delegators :new_scope, :where, :order, :includes, :select, :all, :paginate, :page, :first, :find
|
10
|
-
end
|
11
|
-
class_attribute :connection_class, :connection_object, :connection_options, :query_builder, instance_accessor: false
|
12
|
-
self.connection_class = Connection
|
13
|
-
self.connection_options = {}
|
14
|
-
self.query_builder = Query::Builder
|
15
|
-
end
|
16
|
-
|
17
|
-
module ClassMethods
|
18
|
-
def new_scope
|
19
|
-
query_builder.new(self)
|
20
|
-
end
|
21
|
-
|
22
|
-
def connection(&block)
|
23
|
-
build_connection(&block)
|
24
|
-
connection_object
|
25
|
-
end
|
26
|
-
|
27
|
-
def build_connection
|
28
|
-
return connection_object unless connection_object.nil?
|
29
|
-
self.connection_object = connection_class.new(connection_options.merge(site: site)).tap do |conn|
|
30
|
-
yield(conn) if block_given?
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
@@ -1,39 +0,0 @@
|
|
1
|
-
module JsonApiClient
|
2
|
-
module Helpers
|
3
|
-
module Relatable
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
included do
|
7
|
-
class_attribute :relationship_linker, instance_accessor: false
|
8
|
-
self.relationship_linker = Relationships::Relations
|
9
|
-
|
10
|
-
# the relationships for this resource
|
11
|
-
attr_accessor :relationships
|
12
|
-
|
13
|
-
initializer do |obj, params|
|
14
|
-
relationships = params && params.delete("relationships")
|
15
|
-
relationships ||= {}
|
16
|
-
obj.relationships = obj.class.relationship_linker.new(relationships)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def as_relation
|
21
|
-
{
|
22
|
-
:type => self.class.table_name,
|
23
|
-
primary_key => self[primary_key]
|
24
|
-
}
|
25
|
-
end
|
26
|
-
|
27
|
-
def method_missing(method, *args)
|
28
|
-
return super unless relationships and relationships.has_attribute?(method) and result_set.included
|
29
|
-
result_set.included.data_for(method, relationships[method])
|
30
|
-
end
|
31
|
-
|
32
|
-
def respond_to_missing?(symbol, include_all = false)
|
33
|
-
return true if relationships && relationships.has_attribute?(symbol)
|
34
|
-
super
|
35
|
-
end
|
36
|
-
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
@@ -1,56 +0,0 @@
|
|
1
|
-
module JsonApiClient
|
2
|
-
module Helpers
|
3
|
-
module Requestable
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
included do
|
7
|
-
attr_accessor :last_result_set, :errors
|
8
|
-
class_attribute :requestor_class, instance_accessor: false
|
9
|
-
self.requestor_class = Query::Requestor
|
10
|
-
end
|
11
|
-
|
12
|
-
module ClassMethods
|
13
|
-
def create(conditions = {})
|
14
|
-
new(conditions).tap do |resource|
|
15
|
-
resource.save
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def requestor
|
20
|
-
@requestor ||= requestor_class.new(self)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def save
|
25
|
-
self.last_result_set = if persisted?
|
26
|
-
self.class.requestor.update(self)
|
27
|
-
else
|
28
|
-
self.class.requestor.create(self)
|
29
|
-
end
|
30
|
-
|
31
|
-
self.errors = last_result_set.errors
|
32
|
-
if last_result_set.has_errors?
|
33
|
-
false
|
34
|
-
else
|
35
|
-
self.errors.clear if self.errors
|
36
|
-
mark_as_persisted!
|
37
|
-
if updated = last_result_set.first
|
38
|
-
self.attributes = updated.attributes
|
39
|
-
end
|
40
|
-
true
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def destroy
|
45
|
-
self.last_result_set = self.class.requestor.destroy(self)
|
46
|
-
if !last_result_set.has_errors?
|
47
|
-
self.attributes.clear
|
48
|
-
true
|
49
|
-
else
|
50
|
-
false
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
@@ -1,68 +0,0 @@
|
|
1
|
-
module JsonApiClient
|
2
|
-
module Helpers
|
3
|
-
module Schemable
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
included do
|
7
|
-
initializer do |obj, params|
|
8
|
-
obj.send(:set_default_values)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
module ClassMethods
|
13
|
-
# Returns the schema for this resource class
|
14
|
-
#
|
15
|
-
# @return [Schema] the schema for this resource class
|
16
|
-
def schema
|
17
|
-
@schema ||= Schema.new
|
18
|
-
end
|
19
|
-
|
20
|
-
# Declares a new property by name
|
21
|
-
#
|
22
|
-
# @param name [Symbol] the name of the property
|
23
|
-
# @param options [Hash] property options
|
24
|
-
# @option options [Symbol] :type The property type
|
25
|
-
# @option options [Symbol] :default The default value for the property
|
26
|
-
def property(name, options = {})
|
27
|
-
schema.add(name, options)
|
28
|
-
end
|
29
|
-
|
30
|
-
# Declare multiple properties with the same optional options
|
31
|
-
#
|
32
|
-
# @param [Array<Symbol>] names
|
33
|
-
# @param options [Hash] property options
|
34
|
-
# @option options [Symbol] :type The property type
|
35
|
-
# @option options [Symbol] :default The default value for the property
|
36
|
-
def properties(*names)
|
37
|
-
options = names.last.is_a?(Hash) ? names.pop : {}
|
38
|
-
names.each do |name|
|
39
|
-
property name, options
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
protected
|
45
|
-
|
46
|
-
def set_attribute(name, value)
|
47
|
-
property = property_for(name)
|
48
|
-
value = property.cast(value) if property
|
49
|
-
super(name, value)
|
50
|
-
end
|
51
|
-
|
52
|
-
def has_attribute?(attr_name)
|
53
|
-
!!property_for(attr_name) || super
|
54
|
-
end
|
55
|
-
|
56
|
-
def set_default_values
|
57
|
-
self.class.schema.each_property do |property|
|
58
|
-
attributes[property.name] = property.default unless attributes.has_key?(property.name)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def property_for(name)
|
63
|
-
self.class.schema.find(name)
|
64
|
-
end
|
65
|
-
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
module JsonApiClient
|
2
|
-
module Helpers
|
3
|
-
module Serializable
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
included do
|
7
|
-
class_attribute :read_only_attributes, instance_accessor: false
|
8
|
-
self.read_only_attributes = ['id', 'type', 'links', 'meta', 'relationships']
|
9
|
-
end
|
10
|
-
|
11
|
-
def serializable_hash
|
12
|
-
attributes.slice('id', 'type').tap do |h|
|
13
|
-
relationships.serializable_hash.tap do |r|
|
14
|
-
h['relationships'] = r unless r.empty?
|
15
|
-
end
|
16
|
-
h['attributes'] = attributes_for_serialization
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
protected
|
21
|
-
|
22
|
-
def attributes_for_serialization
|
23
|
-
attributes.except(*self.class.read_only_attributes)
|
24
|
-
end
|
25
|
-
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|