jsonapi_compliable 0.6.4 → 0.6.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/.travis.yml +11 -3
  4. data/.yardopts +1 -0
  5. data/README.md +10 -1
  6. data/Rakefile +1 -0
  7. data/docs/JsonapiCompliable.html +202 -0
  8. data/docs/JsonapiCompliable/Adapters.html +119 -0
  9. data/docs/JsonapiCompliable/Adapters/Abstract.html +2285 -0
  10. data/docs/JsonapiCompliable/Adapters/ActiveRecord.html +2151 -0
  11. data/docs/JsonapiCompliable/Adapters/ActiveRecordSideloading.html +582 -0
  12. data/docs/JsonapiCompliable/Adapters/Null.html +1682 -0
  13. data/docs/JsonapiCompliable/Base.html +1395 -0
  14. data/docs/JsonapiCompliable/Deserializer.html +835 -0
  15. data/docs/JsonapiCompliable/Errors.html +115 -0
  16. data/docs/JsonapiCompliable/Errors/BadFilter.html +124 -0
  17. data/docs/JsonapiCompliable/Errors/StatNotFound.html +266 -0
  18. data/docs/JsonapiCompliable/Errors/UnsupportedPageSize.html +264 -0
  19. data/docs/JsonapiCompliable/Errors/ValidationError.html +124 -0
  20. data/docs/JsonapiCompliable/Extensions.html +117 -0
  21. data/docs/JsonapiCompliable/Extensions/BooleanAttribute.html +212 -0
  22. data/docs/JsonapiCompliable/Extensions/BooleanAttribute/ClassMethods.html +229 -0
  23. data/docs/JsonapiCompliable/Extensions/ExtraAttribute.html +242 -0
  24. data/docs/JsonapiCompliable/Extensions/ExtraAttribute/ClassMethods.html +237 -0
  25. data/docs/JsonapiCompliable/Query.html +1099 -0
  26. data/docs/JsonapiCompliable/Rails.html +211 -0
  27. data/docs/JsonapiCompliable/Resource.html +5241 -0
  28. data/docs/JsonapiCompliable/Scope.html +703 -0
  29. data/docs/JsonapiCompliable/Scoping.html +117 -0
  30. data/docs/JsonapiCompliable/Scoping/Base.html +843 -0
  31. data/docs/JsonapiCompliable/Scoping/DefaultFilter.html +318 -0
  32. data/docs/JsonapiCompliable/Scoping/ExtraFields.html +301 -0
  33. data/docs/JsonapiCompliable/Scoping/Filter.html +313 -0
  34. data/docs/JsonapiCompliable/Scoping/Filterable.html +364 -0
  35. data/docs/JsonapiCompliable/Scoping/Paginate.html +613 -0
  36. data/docs/JsonapiCompliable/Scoping/Sort.html +454 -0
  37. data/docs/JsonapiCompliable/SerializableTempId.html +216 -0
  38. data/docs/JsonapiCompliable/Sideload.html +2484 -0
  39. data/docs/JsonapiCompliable/Stats.html +117 -0
  40. data/docs/JsonapiCompliable/Stats/DSL.html +999 -0
  41. data/docs/JsonapiCompliable/Stats/Payload.html +391 -0
  42. data/docs/JsonapiCompliable/Util.html +117 -0
  43. data/docs/JsonapiCompliable/Util/FieldParams.html +228 -0
  44. data/docs/JsonapiCompliable/Util/Hash.html +471 -0
  45. data/docs/JsonapiCompliable/Util/IncludeParams.html +299 -0
  46. data/docs/JsonapiCompliable/Util/Persistence.html +435 -0
  47. data/docs/JsonapiCompliable/Util/RelationshipPayload.html +563 -0
  48. data/docs/JsonapiCompliable/Util/RenderOptions.html +250 -0
  49. data/docs/JsonapiCompliable/Util/ValidationResponse.html +532 -0
  50. data/docs/_index.html +527 -0
  51. data/docs/class_list.html +51 -0
  52. data/docs/css/common.css +1 -0
  53. data/docs/css/full_list.css +58 -0
  54. data/docs/css/style.css +492 -0
  55. data/docs/file.README.html +99 -0
  56. data/docs/file_list.html +56 -0
  57. data/docs/frames.html +17 -0
  58. data/docs/index.html +99 -0
  59. data/docs/js/app.js +248 -0
  60. data/docs/js/full_list.js +216 -0
  61. data/docs/js/jquery.js +4 -0
  62. data/docs/method_list.html +1731 -0
  63. data/docs/top-level-namespace.html +110 -0
  64. data/gemfiles/rails_5.gemfile +1 -1
  65. data/lib/jsonapi_compliable/adapters/abstract.rb +267 -4
  66. data/lib/jsonapi_compliable/adapters/active_record.rb +23 -1
  67. data/lib/jsonapi_compliable/adapters/null.rb +43 -3
  68. data/lib/jsonapi_compliable/base.rb +182 -33
  69. data/lib/jsonapi_compliable/deserializer.rb +90 -21
  70. data/lib/jsonapi_compliable/extensions/boolean_attribute.rb +12 -0
  71. data/lib/jsonapi_compliable/extensions/extra_attribute.rb +32 -0
  72. data/lib/jsonapi_compliable/extensions/temp_id.rb +11 -0
  73. data/lib/jsonapi_compliable/query.rb +94 -2
  74. data/lib/jsonapi_compliable/rails.rb +8 -0
  75. data/lib/jsonapi_compliable/resource.rb +548 -11
  76. data/lib/jsonapi_compliable/scope.rb +43 -1
  77. data/lib/jsonapi_compliable/scoping/base.rb +59 -8
  78. data/lib/jsonapi_compliable/scoping/default_filter.rb +33 -0
  79. data/lib/jsonapi_compliable/scoping/extra_fields.rb +33 -0
  80. data/lib/jsonapi_compliable/scoping/filter.rb +29 -2
  81. data/lib/jsonapi_compliable/scoping/filterable.rb +4 -0
  82. data/lib/jsonapi_compliable/scoping/paginate.rb +33 -0
  83. data/lib/jsonapi_compliable/scoping/sort.rb +18 -0
  84. data/lib/jsonapi_compliable/sideload.rb +229 -1
  85. data/lib/jsonapi_compliable/stats/dsl.rb +44 -0
  86. data/lib/jsonapi_compliable/stats/payload.rb +20 -0
  87. data/lib/jsonapi_compliable/util/field_params.rb +1 -0
  88. data/lib/jsonapi_compliable/util/hash.rb +18 -0
  89. data/lib/jsonapi_compliable/util/include_params.rb +22 -0
  90. data/lib/jsonapi_compliable/util/persistence.rb +13 -3
  91. data/lib/jsonapi_compliable/util/relationship_payload.rb +2 -0
  92. data/lib/jsonapi_compliable/util/render_options.rb +2 -0
  93. data/lib/jsonapi_compliable/util/validation_response.rb +16 -0
  94. data/lib/jsonapi_compliable/version.rb +1 -1
  95. metadata +60 -5
  96. data/gemfiles/rails_4.gemfile.lock +0 -208
  97. data/gemfiles/rails_5.gemfile.lock +0 -212
  98. data/lib/jsonapi_compliable/write.rb +0 -93
@@ -0,0 +1,110 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>
7
+ Top Level Namespace
8
+
9
+ &mdash; Documentation by YARD 0.9.9
10
+
11
+ </title>
12
+
13
+ <link rel="stylesheet" href="css/style.css" type="text/css" charset="utf-8" />
14
+
15
+ <link rel="stylesheet" href="css/common.css" type="text/css" charset="utf-8" />
16
+
17
+ <script type="text/javascript" charset="utf-8">
18
+ pathId = "";
19
+ relpath = '';
20
+ </script>
21
+
22
+
23
+ <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
24
+
25
+ <script type="text/javascript" charset="utf-8" src="js/app.js"></script>
26
+
27
+
28
+ </head>
29
+ <body>
30
+ <div class="nav_wrap">
31
+ <iframe id="nav" src="class_list.html?1"></iframe>
32
+ <div id="resizer"></div>
33
+ </div>
34
+
35
+ <div id="main" tabindex="-1">
36
+ <div id="header">
37
+ <div id="menu">
38
+
39
+ <a href="_index.html">Index</a> &raquo;
40
+
41
+
42
+ <span class="title">Top Level Namespace</span>
43
+
44
+ </div>
45
+
46
+ <div id="search">
47
+
48
+ <a class="full_list_link" id="class_list_link"
49
+ href="class_list.html">
50
+
51
+ <svg width="24" height="24">
52
+ <rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
53
+ <rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
54
+ <rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
55
+ </svg>
56
+ </a>
57
+
58
+ </div>
59
+ <div class="clear"></div>
60
+ </div>
61
+
62
+ <div id="content"><h1>Top Level Namespace
63
+
64
+
65
+
66
+ </h1>
67
+ <div class="box_info">
68
+
69
+
70
+
71
+
72
+
73
+
74
+
75
+
76
+
77
+
78
+
79
+ </div>
80
+
81
+ <h2>Defined Under Namespace</h2>
82
+ <p class="children">
83
+
84
+
85
+ <strong class="modules">Modules:</strong> <span class='object_link'><a href="JsonapiCompliable.html" title="JsonapiCompliable (module)">JsonapiCompliable</a></span>
86
+
87
+
88
+
89
+
90
+ </p>
91
+
92
+
93
+
94
+
95
+
96
+
97
+
98
+
99
+
100
+ </div>
101
+
102
+ <div id="footer">
103
+ Generated on Fri May 5 15:53:21 2017 by
104
+ <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
105
+ 0.9.9 (ruby-2.3.0).
106
+ </div>
107
+
108
+ </div>
109
+ </body>
110
+ </html>
@@ -2,7 +2,7 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "rails", "~> 5.0"
5
+ gem "rails", ['>= 5.0', '< 5.1']
6
6
  gem "jsonapi-rails", "~> 0.1", :require => "jsonapi/rails"
7
7
  gem "rspec-rails"
8
8
 
@@ -1,33 +1,296 @@
1
1
  module JsonapiCompliable
2
2
  module Adapters
3
+ # Adapters DRY up common resource logic.
4
+ #
5
+ # For instance, there's no reason to write ActiveRecord logic like this in
6
+ # every Resource:
7
+ #
8
+ # allow_filter :title do |scope, value|
9
+ # scope.where(title: value)
10
+ # end
11
+ #
12
+ # sort do |scope, att, dir|
13
+ # scope.order(att => dir)
14
+ # end
15
+ #
16
+ # paginate do |scope, current_page, per_page|
17
+ # scope.page(current_page).per(per_page)
18
+ # end
19
+ #
20
+ # This logic can be re-used through an *Adapter*:
21
+ #
22
+ # use_adapter JsonapiCompliable::Adapters::ActiveRecord
23
+ # allow_filter :title
24
+ #
25
+ # Adapters are pretty simple to write. The corresponding code for the above
26
+ # ActiveRecord adapter, which should look pretty familiar:
27
+ #
28
+ # class JsonapiCompliable::Adapters::ActiveRecord
29
+ # def filter(scope, attribute, value)
30
+ # scope.where(attribute => value)
31
+ # end
32
+ #
33
+ # def order(scope, attribute, direction)
34
+ # scope.order(attribute => direction)
35
+ # end
36
+ #
37
+ # def paginate(scope, current_page, per_page)
38
+ # scope.page(current_page).per(per_page)
39
+ # end
40
+ # end
41
+ #
42
+ # An adapter can have a corresponding +sideloading_module+. This module
43
+ # gets mixed in to a Sideload. In other words, *Resource* is to
44
+ # *Adapter* as *Sideload* is to *Adapter#sideloading_module*. Use this
45
+ # module to define DSL methods that wrap #allow_sideload:
46
+ #
47
+ # class MyAdapter < JsonapiCompliable::Adapters::Abstract
48
+ # # ... code ...
49
+ # def sideloading_module
50
+ # MySideloadingAdapter
51
+ # end
52
+ # end
53
+ #
54
+ # module MySideloadingAdapter
55
+ # def belongs_to(association_name)
56
+ # allow_sideload association_name do
57
+ # # ... code ...
58
+ # end
59
+ # end
60
+ # end
61
+ #
62
+ # # And now in your Resource:
63
+ # class MyResource < ApplicationResource
64
+ # # ... code ...
65
+ # use_adapter MyAdapter
66
+ #
67
+ # belongs_to :my_association
68
+ # end
69
+ #
70
+ # If you need the adapter to do *nothing*, because perhaps the API you
71
+ # are hitting does not support sorting,
72
+ # use +JsonapiCompliable::Adapters::Null+.
73
+ #
74
+ # @see Resource.use_adapter
75
+ # @see Adapters::ActiveRecord
76
+ # @see Adapters::ActiveRecordSideloading
77
+ # @see Adapters::Null
3
78
  class Abstract
79
+ # @param scope The scope object we are chaining
80
+ # @param [Symbol] attribute The attribute name we are filtering
81
+ # @param value The corresponding query parameter value
82
+ # @return the scope
83
+ #
84
+ # @example ActiveRecord default
85
+ # def filter(scope, attribute, value)
86
+ # scope.where(attribute => value)
87
+ # end
4
88
  def filter(scope, attribute, value)
5
89
  raise 'you must override #filter in an adapter subclass'
6
90
  end
7
91
 
92
+ # @param scope The scope object we are chaining
93
+ # @param [Symbol] attribute The attribute name we are sorting
94
+ # @param [Symbol] direction The direction we are sorting (asc/desc)
95
+ # @return the scope
96
+ #
97
+ # @example ActiveRecord default
98
+ # def order(scope, attribute, direction)
99
+ # scope.order(attribute => direction)
100
+ # end
8
101
  def order(scope, attribute, direction)
9
102
  raise 'you must override #order in an adapter subclass'
10
103
  end
11
104
 
12
- def paginate(scope, number, size)
105
+ # @param scope The scope object we are chaining
106
+ # @param [Integer] current_page The current page number
107
+ # @param [Integer] per_page The number of results per page
108
+ # @return the scope
109
+ #
110
+ # @example ActiveRecord default
111
+ # # via kaminari gem
112
+ # def paginate(scope, current_page, per_page)
113
+ # scope.page(current_page).per(per_page)
114
+ # end
115
+ def paginate(scope, current_page, per_page)
13
116
  raise 'you must override #paginate in an adapter subclass'
14
117
  end
15
118
 
16
- def sideload(scope, includes)
17
- raise 'you must override #sideload in an adapter subclass'
119
+ # @param scope the scope object we are chaining
120
+ # @param [Symbol] attr corresponding stat attribute name
121
+ # @return [Numeric] the count of the scope
122
+ # @example ActiveRecord default
123
+ # def count(scope, attr)
124
+ # column = attr == :total ? :all : attr
125
+ # scope.uniq.count(column)
126
+ # end
127
+ def count(scope, attr)
128
+ raise 'you must override #count in an adapter subclass'
18
129
  end
19
130
 
20
- def transaction
131
+ # @param scope the scope object we are chaining
132
+ # @param [Symbol] attr corresponding stat attribute name
133
+ # @return [Float] the average of the scope
134
+ # @example ActiveRecord default
135
+ # def average(scope, attr)
136
+ # scope.average(attr).to_f
137
+ # end
138
+ def average(scope, attr)
139
+ raise 'you must override #average in an adapter subclass'
140
+ end
141
+
142
+ # @param scope the scope object we are chaining
143
+ # @param [Symbol] attr corresponding stat attribute name
144
+ # @return [Numeric] the sum of the scope
145
+ # @example ActiveRecord default
146
+ # def sum(scope, attr)
147
+ # scope.sum(attr)
148
+ # end
149
+ def sum(scope, attr)
150
+ raise 'you must override #sum in an adapter subclass'
151
+ end
152
+
153
+ # @param scope the scope object we are chaining
154
+ # @param [Symbol] attr corresponding stat attribute name
155
+ # @return [Numeric] the maximum value of the scope
156
+ # @example ActiveRecord default
157
+ # def maximum(scope, attr)
158
+ # scope.maximum(attr)
159
+ # end
160
+ def maximum(scope, attr)
161
+ raise 'you must override #maximum in an adapter subclass'
162
+ end
163
+
164
+ # @param scope the scope object we are chaining
165
+ # @param [Symbol] attr corresponding stat attribute name
166
+ # @return [Numeric] the maximum value of the scope
167
+ # @example ActiveRecord default
168
+ # def maximum(scope, attr)
169
+ # scope.maximum(attr)
170
+ # end
171
+ def minimum(scope, attr)
172
+ raise 'you must override #maximum in an adapter subclass'
173
+ end
174
+
175
+ # This method must +yield+ the code to run within the transaction.
176
+ # This method should roll back the transaction if an error is raised.
177
+ #
178
+ # @param [Class] model_class The class we're operating on
179
+ # @example ActiveRecord default
180
+ # def transaction(model_class)
181
+ # model_class.transaction do
182
+ # yield
183
+ # end
184
+ # end
185
+ #
186
+ # @see Resource.model
187
+ def transaction(model_class)
21
188
  raise 'you must override #transaction in an adapter subclass, it must yield'
22
189
  end
23
190
 
191
+ # Resolve the scope. This is where you'd actually fire SQL,
192
+ # actually make an HTTP call, etc.
193
+ #
194
+ # @example ActiveRecordDefault
195
+ # def resolve(scope)
196
+ # scope.to_a
197
+ # end
198
+ #
199
+ # @example Suggested Customization
200
+ # # When making a service call, we suggest this abstraction
201
+ # # 'scope' here is a hash
202
+ # def resolve(scope)
203
+ # # The implementation of .where can be whatever you want
204
+ # SomeModelClass.where(scope)
205
+ # end
206
+ #
207
+ # @see Adapters::ActiveRecord#resolve
208
+ # @param scope The scope object to resolve
209
+ # @return an array of Model instances
24
210
  def resolve(scope)
25
211
  scope
26
212
  end
27
213
 
214
+ # Assign these two objects together.
215
+ #
216
+ # @example Basic accessor
217
+ # def associate(parent, child, association_name, association_type)
218
+ # if association_type == :has_many
219
+ # parent.send(association_name).push(child)
220
+ # else
221
+ # child.send(:"#{association_name}=", parent)
222
+ # end
223
+ # end
224
+ #
225
+ # +association_name+ and +association_type+ come from your sideload
226
+ # configuration:
227
+ #
228
+ # allow_sideload :the_name, type: the_type do
229
+ # # ... code.
230
+ # end
231
+ #
232
+ # @param parent The parent object (via the JSONAPI 'relationships' graph)
233
+ # @param child The child object (via the JSONAPI 'relationships' graph)
234
+ # @param association_name The 'relationships' key we are processing
235
+ # @param association_type The Sideload type (see Sideload#type). Usually :has_many/:belongs_to/etc
236
+ def associate(parent, child, association_name, association_type)
237
+ raise 'you must override #associate in an adapter subclass'
238
+ end
239
+
240
+ # This module gets mixed in to Sideload classes
241
+ # This is where you define methods like has_many,
242
+ # belongs_to etc that wrap the lower-level Sideload#allow_sideload
243
+ #
244
+ # @see Resource#allow_sideload
245
+ # @see Sideload#allow_sideload
246
+ # @see Adapters::ActiveRecord#sideloading_module
247
+ # @see Adapters::ActiveRecordSideloading
248
+ # @return the module to mix in
28
249
  def sideloading_module
29
250
  Module.new
30
251
  end
252
+
253
+ # @param [Class] model_class The configured model class (see Resource.model)
254
+ # @param [Hash] create_params Attributes + id
255
+ # @return the model instance just created
256
+ # @see Resource.model
257
+ # @example ActiveRecord default
258
+ # def create(model_class, create_params)
259
+ # instance = model_class.new(create_params)
260
+ # instance.save
261
+ # instance
262
+ # end
263
+ def create(model_class, create_params)
264
+ raise 'you must override #create in an adapter subclass'
265
+ end
266
+
267
+ # @param [Class] model_class The configured model class (see Resource.model)
268
+ # @param [Hash] update_params Attributes + id
269
+ # @return the model instance just created
270
+ # @see Resource.model
271
+ # @example ActiveRecord default
272
+ # def update(model_class, update_params)
273
+ # instance = model_class.find(update_params.delete(:id))
274
+ # instance.update_attributes(update_params)
275
+ # instance
276
+ # end
277
+ def update(model_class, update_params)
278
+ raise 'you must override #update in an adapter subclass'
279
+ end
280
+
281
+ # @param [Class] model_class The configured model class (see Resource.model)
282
+ # @param [Integer] id the id for this model
283
+ # @return the model instance just destroyed
284
+ # @see Resource.model
285
+ # @example ActiveRecord default
286
+ # def destroy(model_class, id)
287
+ # instance = model_class.find(id)
288
+ # instance.destroy
289
+ # instance
290
+ # end
291
+ def destroy(model_class, id)
292
+ raise 'you must override #destroy in an adapter subclass'
293
+ end
31
294
  end
32
295
  end
33
296
  end
@@ -2,53 +2,72 @@ require 'jsonapi_compliable/adapters/active_record_sideloading'
2
2
 
3
3
  module JsonapiCompliable
4
4
  module Adapters
5
+ # @see Adapters::Abstract
5
6
  class ActiveRecord < Abstract
7
+ # (see Adapters::Abstract#filter)
6
8
  def filter(scope, attribute, value)
7
9
  scope.where(attribute => value)
8
10
  end
9
11
 
12
+ # (see Adapters::Abstract#order)
10
13
  def order(scope, attribute, direction)
11
14
  scope.order(attribute => direction)
12
15
  end
13
16
 
17
+ # (see Adapters::Abstract#paginate)
14
18
  def paginate(scope, current_page, per_page)
15
19
  scope.page(current_page).per(per_page)
16
20
  end
17
21
 
22
+ # (see Adapters::Abstract#count)
18
23
  def count(scope, attr)
19
- scope.uniq.count
24
+ column = attr == :total ? :all : attr
25
+ scope.uniq.count(column)
20
26
  end
21
27
 
28
+ # (see Adapters::Abstract#average)
22
29
  def average(scope, attr)
23
30
  scope.average(attr).to_f
24
31
  end
25
32
 
33
+ # (see Adapters::Abstract#sum)
26
34
  def sum(scope, attr)
27
35
  scope.sum(attr)
28
36
  end
29
37
 
38
+ # (see Adapters::Abstract#maximum)
30
39
  def maximum(scope, attr)
31
40
  scope.maximum(attr)
32
41
  end
33
42
 
43
+ # (see Adapters::Abstract#minimum)
34
44
  def minimum(scope, attr)
35
45
  scope.minimum(attr)
36
46
  end
37
47
 
48
+ # (see Adapters::Abstract#resolve)
38
49
  def resolve(scope)
39
50
  scope.to_a
40
51
  end
41
52
 
53
+ # Run this write request within an ActiveRecord transaction
54
+ # @param [Class] model_class The ActiveRecord class we are saving
55
+ # @return Result of yield
56
+ # @see Adapters::Abstract#transaction
42
57
  def transaction(model_class)
43
58
  model_class.transaction do
44
59
  yield
45
60
  end
46
61
  end
47
62
 
63
+ # (see Adapters::Abstract#sideloading_module)
48
64
  def sideloading_module
49
65
  JsonapiCompliable::Adapters::ActiveRecordSideloading
50
66
  end
51
67
 
68
+ # When a has_many relationship, we need to avoid Activerecord implicitly
69
+ # firing a query. Otherwise, simple assignment will do
70
+ # @see Adapters::Abstract#associate
52
71
  def associate(parent, child, association_name, association_type)
53
72
  if association_type == :has_many
54
73
  parent.association(association_name).loaded!
@@ -58,18 +77,21 @@ module JsonapiCompliable
58
77
  end
59
78
  end
60
79
 
80
+ # (see Adapters::Abstract#create)
61
81
  def create(model_class, create_params)
62
82
  instance = model_class.new(create_params)
63
83
  instance.save
64
84
  instance
65
85
  end
66
86
 
87
+ # (see Adapters::Abstract#update)
67
88
  def update(model_class, update_params)
68
89
  instance = model_class.find(update_params.delete(:id))
69
90
  instance.update_attributes(update_params)
70
91
  instance
71
92
  end
72
93
 
94
+ # (see Adapters::Abstract#destroy)
73
95
  def destroy(model_class, id)
74
96
  instance = model_class.find(id)
75
97
  instance.destroy