him 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ci.yml +40 -0
  3. data/.gitignore +6 -0
  4. data/.qlty/qlty.toml +57 -0
  5. data/.rspec +1 -0
  6. data/.ruby-version +1 -0
  7. data/.yardopts +2 -0
  8. data/CONTRIBUTING.md +26 -0
  9. data/Gemfile +2 -0
  10. data/LICENSE +8 -0
  11. data/README.md +1007 -0
  12. data/Rakefile +11 -0
  13. data/UPGRADE.md +101 -0
  14. data/gemfiles/Gemfile.activemodel-6.1 +6 -0
  15. data/gemfiles/Gemfile.activemodel-7.0 +6 -0
  16. data/gemfiles/Gemfile.activemodel-7.1 +6 -0
  17. data/gemfiles/Gemfile.activemodel-7.2 +6 -0
  18. data/gemfiles/Gemfile.activemodel-8.0 +6 -0
  19. data/him.gemspec +28 -0
  20. data/lib/him/api.rb +121 -0
  21. data/lib/him/collection.rb +21 -0
  22. data/lib/him/errors.rb +29 -0
  23. data/lib/him/json_api/model.rb +42 -0
  24. data/lib/him/middleware/accept_json.rb +18 -0
  25. data/lib/him/middleware/first_level_parse_json.rb +37 -0
  26. data/lib/him/middleware/json_api_parser.rb +65 -0
  27. data/lib/him/middleware/parse_json.rb +22 -0
  28. data/lib/him/middleware/second_level_parse_json.rb +37 -0
  29. data/lib/him/middleware.rb +12 -0
  30. data/lib/him/model/associations/association.rb +147 -0
  31. data/lib/him/model/associations/association_proxy.rb +47 -0
  32. data/lib/him/model/associations/belongs_to_association.rb +95 -0
  33. data/lib/him/model/associations/has_many_association.rb +113 -0
  34. data/lib/him/model/associations/has_one_association.rb +79 -0
  35. data/lib/him/model/associations.rb +141 -0
  36. data/lib/him/model/attributes.rb +337 -0
  37. data/lib/him/model/base.rb +33 -0
  38. data/lib/him/model/http.rb +113 -0
  39. data/lib/him/model/introspection.rb +77 -0
  40. data/lib/him/model/nested_attributes.rb +45 -0
  41. data/lib/him/model/orm.rb +306 -0
  42. data/lib/him/model/parse.rb +224 -0
  43. data/lib/him/model/paths.rb +125 -0
  44. data/lib/him/model/relation.rb +212 -0
  45. data/lib/him/model.rb +79 -0
  46. data/lib/him/version.rb +3 -0
  47. data/lib/him.rb +22 -0
  48. data/spec/api_spec.rb +120 -0
  49. data/spec/collection_spec.rb +70 -0
  50. data/spec/json_api/model_spec.rb +260 -0
  51. data/spec/middleware/accept_json_spec.rb +11 -0
  52. data/spec/middleware/first_level_parse_json_spec.rb +63 -0
  53. data/spec/middleware/json_api_parser_spec.rb +52 -0
  54. data/spec/middleware/second_level_parse_json_spec.rb +35 -0
  55. data/spec/model/associations/association_proxy_spec.rb +29 -0
  56. data/spec/model/associations_spec.rb +1010 -0
  57. data/spec/model/attributes_spec.rb +384 -0
  58. data/spec/model/callbacks_spec.rb +194 -0
  59. data/spec/model/dirty_spec.rb +133 -0
  60. data/spec/model/http_spec.rb +187 -0
  61. data/spec/model/introspection_spec.rb +110 -0
  62. data/spec/model/nested_attributes_spec.rb +135 -0
  63. data/spec/model/orm_spec.rb +717 -0
  64. data/spec/model/parse_spec.rb +619 -0
  65. data/spec/model/paths_spec.rb +348 -0
  66. data/spec/model/relation_spec.rb +255 -0
  67. data/spec/model/validations_spec.rb +45 -0
  68. data/spec/model_spec.rb +55 -0
  69. data/spec/spec_helper.rb +25 -0
  70. data/spec/support/extensions/array.rb +6 -0
  71. data/spec/support/extensions/hash.rb +6 -0
  72. data/spec/support/macros/her_macros.rb +17 -0
  73. data/spec/support/macros/model_macros.rb +36 -0
  74. data/spec/support/macros/request_macros.rb +27 -0
  75. metadata +201 -0
@@ -0,0 +1,619 @@
1
+ # encoding: utf-8
2
+
3
+ require File.join(File.dirname(__FILE__), "../spec_helper.rb")
4
+
5
+ describe Him::Model::Parse do
6
+ context "when include_root_in_json is set" do
7
+ before do
8
+ Him::API.setup url: "https://api.example.com" do |builder|
9
+ builder.use Him::Middleware::FirstLevelParseJSON
10
+ builder.use Faraday::Request::UrlEncoded
11
+ end
12
+
13
+ Him::API.default_api.connection.adapter :test do |stub|
14
+ stub.post("/users") { |env| [200, {}, { user: { id: 1, fullname: params(env)[:user][:fullname] } }.to_json] }
15
+ stub.post("/users/admins") { |env| [200, {}, { user: { id: 1, fullname: params(env)[:user][:fullname] } }.to_json] }
16
+ end
17
+ end
18
+
19
+ context "to true" do
20
+ before do
21
+ spawn_model "Foo::User" do
22
+ include_root_in_json true
23
+ parse_root_in_json true
24
+ custom_post :admins
25
+ end
26
+ end
27
+
28
+ it "inherits attributes from parent class" do
29
+ spawn_model "Foo::ChildUser", super_class: Foo::User do
30
+ end
31
+
32
+ expect(Foo::ChildUser).to be_include_root_in_json
33
+ end
34
+
35
+ it "allows `include_root_in_json` to be set to `false` on a child model" do
36
+ spawn_model "Foo::ChildUser", super_class: Foo::User do
37
+ include_root_in_json false
38
+ end
39
+
40
+ expect(Foo::ChildUser).to_not be_include_root_in_json
41
+ end
42
+
43
+ it "wraps params in the element name in `to_params`" do
44
+ @new_user = Foo::User.new(fullname: "Tobias Fünke")
45
+ expect(@new_user.to_params).to eq(user: { fullname: "Tobias Fünke" })
46
+ end
47
+
48
+ it "wraps params in the element name in `.create`" do
49
+ @new_user = Foo::User.admins(fullname: "Tobias Fünke")
50
+ expect(@new_user.fullname).to eq("Tobias Fünke")
51
+ end
52
+ end
53
+
54
+ context "to false" do
55
+ before do
56
+ spawn_model "Foo::User" do
57
+ include_root_in_json false
58
+ end
59
+ end
60
+
61
+ it "inherits attributes from parent class" do
62
+ spawn_model "Foo::ChildUser", super_class: Foo::User do
63
+ end
64
+
65
+ expect(Foo::ChildUser).to_not be_include_root_in_json
66
+ end
67
+
68
+ it "allows `include_root_in_json` to be set to `true` on a child model" do
69
+ spawn_model "Foo::ChildUser", super_class: Foo::User do
70
+ include_root_in_json true
71
+ end
72
+
73
+ expect(Foo::ChildUser).to be_include_root_in_json
74
+ end
75
+ end
76
+
77
+ context "to a symbol" do
78
+ before do
79
+ spawn_model "Foo::User" do
80
+ include_root_in_json :person
81
+ parse_root_in_json :person
82
+ end
83
+ end
84
+
85
+ it "wraps params in the specified value" do
86
+ @new_user = Foo::User.new(fullname: "Tobias Fünke")
87
+ expect(@new_user.to_params).to eq(person: { fullname: "Tobias Fünke" })
88
+ end
89
+ end
90
+
91
+ context "in the parent class" do
92
+ before do
93
+ spawn_model("Foo::Model") { include_root_in_json true }
94
+
95
+ class User < Foo::Model; end
96
+ @spawned_models << :User
97
+ end
98
+
99
+ it "wraps params with the class name" do
100
+ @new_user = User.new(fullname: "Tobias Fünke")
101
+ expect(@new_user.to_params).to eq(user: { fullname: "Tobias Fünke" })
102
+ end
103
+ end
104
+ end
105
+
106
+ context "when `request_new_object_on_build` is set" do
107
+ context "to true" do
108
+ before do
109
+ spawn_model "Foo::User" do
110
+ request_new_object_on_build true
111
+ end
112
+ end
113
+
114
+ it "inherits attributes from parent class" do
115
+ spawn_model "Foo::ChildUser", super_class: Foo::User do
116
+ end
117
+
118
+ expect(Foo::ChildUser).to be_request_new_object_on_build
119
+ end
120
+
121
+ it "allows `request_new_object_on_build` to be set to `false` on a child model" do
122
+ spawn_model "Foo::ChildUser", super_class: Foo::User do
123
+ request_new_object_on_build false
124
+ end
125
+
126
+ expect(Foo::ChildUser).to_not be_request_new_object_on_build
127
+ end
128
+ end
129
+
130
+ context "to false" do
131
+ before do
132
+ spawn_model "Foo::User" do
133
+ request_new_object_on_build false
134
+ end
135
+ end
136
+
137
+ it "inherits attributes from parent class" do
138
+ spawn_model "Foo::ChildUser", super_class: Foo::User do
139
+ end
140
+
141
+ expect(Foo::ChildUser).to_not be_request_new_object_on_build
142
+ end
143
+
144
+ it "allows `request_new_object_on_build` to be set to `true` on a child model" do
145
+ spawn_model "Foo::ChildUser", super_class: Foo::User do
146
+ request_new_object_on_build true
147
+ end
148
+
149
+ expect(Foo::ChildUser).to be_request_new_object_on_build
150
+ end
151
+ end
152
+ end
153
+
154
+ context "when parse_root_in_json is set" do
155
+ before do
156
+ Him::API.setup url: "https://api.example.com" do |builder|
157
+ builder.use Him::Middleware::FirstLevelParseJSON
158
+ builder.use Faraday::Request::UrlEncoded
159
+ end
160
+ end
161
+
162
+ context "to true" do
163
+ before do
164
+ Him::API.default_api.connection.adapter :test do |stub|
165
+ stub.post("/users") { [200, {}, { user: { id: 1, fullname: "Lindsay Fünke" } }.to_json] }
166
+ stub.get("/users") { [200, {}, [{ user: { id: 1, fullname: "Lindsay Fünke" } }].to_json] }
167
+ stub.get("/users/admins") { [200, {}, [{ user: { id: 1, fullname: "Lindsay Fünke" } }].to_json] }
168
+ stub.get("/users/1") { [200, {}, { user: { id: 1, fullname: "Lindsay Fünke" } }.to_json] }
169
+ stub.put("/users/1") { [200, {}, { user: { id: 1, fullname: "Tobias Fünke Jr." } }.to_json] }
170
+ end
171
+
172
+ spawn_model("Foo::User") do
173
+ parse_root_in_json true
174
+ custom_get :admins
175
+ end
176
+ end
177
+
178
+ it "inherits attributes from parent class" do
179
+ spawn_model "Foo::ChildUser", super_class: Foo::User do
180
+ end
181
+
182
+ expect(Foo::ChildUser).to be_parse_root_in_json
183
+ end
184
+
185
+ it "allows `parse_root_in_json` to be set to `false` on a child model" do
186
+ spawn_model "Foo::ChildUser", super_class: Foo::User do
187
+ parse_root_in_json false
188
+ end
189
+
190
+ expect(Foo::ChildUser).to_not be_parse_root_in_json
191
+ end
192
+
193
+ it "parse the data from the JSON root element after .create" do
194
+ @new_user = Foo::User.create(fullname: "Lindsay Fünke")
195
+ expect(@new_user.fullname).to eq("Lindsay Fünke")
196
+ end
197
+
198
+ it "parse the data from the JSON root element after an arbitrary HTTP request" do
199
+ @new_user = Foo::User.admins
200
+ expect(@new_user.first.fullname).to eq("Lindsay Fünke")
201
+ end
202
+
203
+ it "parse the data from the JSON root element after .all" do
204
+ @users = Foo::User.all
205
+ expect(@users.first.fullname).to eq("Lindsay Fünke")
206
+ end
207
+
208
+ it "parse the data from the JSON root element after .find" do
209
+ @user = Foo::User.find(1)
210
+ expect(@user.fullname).to eq("Lindsay Fünke")
211
+ end
212
+
213
+ it "parse the data from the JSON root element after .save" do
214
+ @user = Foo::User.find(1)
215
+ @user.fullname = "Tobias Fünke"
216
+ @user.save
217
+ expect(@user.fullname).to eq("Tobias Fünke Jr.")
218
+ end
219
+ end
220
+
221
+ context "to false" do
222
+ before do
223
+ spawn_model "Foo::User" do
224
+ parse_root_in_json false
225
+ end
226
+ end
227
+
228
+ it "inherits attributes from parent class" do
229
+ spawn_model "Foo::ChildUser", super_class: Foo::User do
230
+ end
231
+
232
+ expect(Foo::ChildUser).to_not be_parse_root_in_json
233
+ end
234
+
235
+ it "allows `parse_root_in_json` to be set to `true` on a child model" do
236
+ spawn_model "Foo::ChildUser", super_class: Foo::User do
237
+ parse_root_in_json true
238
+ end
239
+
240
+ expect(Foo::ChildUser).to be_parse_root_in_json
241
+ end
242
+ end
243
+
244
+ context "to a symbol" do
245
+ before do
246
+ Him::API.default_api.connection.adapter :test do |stub|
247
+ stub.post("/users") { [200, {}, { person: { id: 1, fullname: "Lindsay Fünke" } }.to_json] }
248
+ end
249
+
250
+ spawn_model("Foo::User") { parse_root_in_json :person }
251
+ end
252
+
253
+ it "parse the data with the symbol" do
254
+ @new_user = Foo::User.create(fullname: "Lindsay Fünke")
255
+ expect(@new_user.id).to eq(1)
256
+ expect(@new_user.fullname).to eq("Lindsay Fünke")
257
+ end
258
+ end
259
+
260
+ context "in the parent class" do
261
+ before do
262
+ Him::API.default_api.connection.adapter :test do |stub|
263
+ stub.post("/users") { [200, {}, { user: { id: 1, fullname: "Lindsay Fünke" } }.to_json] }
264
+ stub.get("/users") { [200, {}, { users: [{ id: 1, fullname: "Lindsay Fünke" }] }.to_json] }
265
+ end
266
+
267
+ spawn_model("Foo::Model") { parse_root_in_json true, format: :active_model_serializers }
268
+ class User < Foo::Model
269
+
270
+ collection_path "/users"
271
+ end
272
+
273
+ @spawned_models << :User
274
+ end
275
+
276
+ it "parse the data with the symbol" do
277
+ @new_user = User.create(fullname: "Lindsay Fünke")
278
+ expect(@new_user.fullname).to eq("Lindsay Fünke")
279
+ end
280
+
281
+ it "parses the collection of data" do
282
+ @users = User.all
283
+ expect(@users.first.fullname).to eq("Lindsay Fünke")
284
+ end
285
+ end
286
+
287
+ context "to true with format: :active_model_serializers" do
288
+ before do
289
+ Him::API.default_api.connection.adapter :test do |stub|
290
+ stub.post("/users") { [200, {}, { user: { id: 1, fullname: "Lindsay Fünke" } }.to_json] }
291
+ stub.get("/users") { [200, {}, { users: [{ id: 1, fullname: "Lindsay Fünke" }] }.to_json] }
292
+ stub.get("/users/admins") { [200, {}, { users: [{ id: 1, fullname: "Lindsay Fünke" }] }.to_json] }
293
+ stub.get("/users/1") { [200, {}, { user: { id: 1, fullname: "Lindsay Fünke" } }.to_json] }
294
+ stub.put("/users/1") { [200, {}, { user: { id: 1, fullname: "Tobias Fünke Jr." } }.to_json] }
295
+ end
296
+
297
+ spawn_model("Foo::User") do
298
+ parse_root_in_json true, format: :active_model_serializers
299
+ custom_get :admins
300
+ end
301
+ end
302
+
303
+ it "parse the data from the JSON root element after .create" do
304
+ @new_user = Foo::User.create(fullname: "Lindsay Fünke")
305
+ expect(@new_user.fullname).to eq("Lindsay Fünke")
306
+ end
307
+
308
+ it "parse the data from the JSON root element after an arbitrary HTTP request" do
309
+ @users = Foo::User.admins
310
+ expect(@users.first.fullname).to eq("Lindsay Fünke")
311
+ end
312
+
313
+ it "parse the data from the JSON root element after .all" do
314
+ @users = Foo::User.all
315
+ expect(@users.first.fullname).to eq("Lindsay Fünke")
316
+ end
317
+
318
+ it "parse the data from the JSON root element after .find" do
319
+ @user = Foo::User.find(1)
320
+ expect(@user.fullname).to eq("Lindsay Fünke")
321
+ end
322
+
323
+ it "parse the data from the JSON root element after .save" do
324
+ @user = Foo::User.find(1)
325
+ @user.fullname = "Tobias Fünke"
326
+ @user.save
327
+ expect(@user.fullname).to eq("Tobias Fünke Jr.")
328
+ end
329
+ end
330
+ end
331
+
332
+ context "when to_params is set" do
333
+ before do
334
+ Him::API.setup url: "https://api.example.com" do |builder|
335
+ builder.use Him::Middleware::FirstLevelParseJSON
336
+ builder.use Faraday::Request::UrlEncoded
337
+ builder.adapter :test do |stub|
338
+ stub.post("/users") { |env| ok! id: 1, fullname: params(env)["fullname"] }
339
+ end
340
+ end
341
+
342
+ spawn_model "Foo::User" do
343
+ def to_params
344
+ { fullname: "Lindsay Fünke" }
345
+ end
346
+ end
347
+ end
348
+
349
+ it "changes the request parameters for one-line resource creation" do
350
+ @user = Foo::User.create(fullname: "Tobias Fünke")
351
+ expect(@user.fullname).to eq("Lindsay Fünke")
352
+ end
353
+
354
+ it "changes the request parameters for Model.new + #save" do
355
+ @user = Foo::User.new(fullname: "Tobias Fünke")
356
+ @user.save
357
+ expect(@user.fullname).to eq("Lindsay Fünke")
358
+ end
359
+ end
360
+
361
+ context "when parse_root_in_json is true without AMS format" do
362
+ before do
363
+ Him::API.setup url: "https://api.example.com" do |builder|
364
+ builder.use Him::Middleware::FirstLevelParseJSON
365
+ builder.adapter :test do |stub|
366
+ stub.get("/users") { [200, {}, { users: [{ id: 1, name: "Tobias" }] }.to_json] }
367
+ stub.get("/users/1") { [200, {}, { user: { id: 1, name: "Tobias" } }.to_json] }
368
+ end
369
+ end
370
+
371
+ spawn_model "Foo::User" do
372
+ parse_root_in_json true
373
+ end
374
+ end
375
+
376
+ it "unwraps collection root key" do
377
+ users = Foo::User.all
378
+ expect(users.length).to eq(1)
379
+ expect(users.first.name).to eq("Tobias")
380
+ end
381
+
382
+ it "unwraps single resource root key" do
383
+ user = Foo::User.find(1)
384
+ expect(user.name).to eq("Tobias")
385
+ end
386
+ end
387
+
388
+ context "when associations reference each other" do
389
+ before do
390
+ Him::API.setup url: "https://api.example.com" do |builder|
391
+ builder.use Him::Middleware::FirstLevelParseJSON
392
+ builder.use Faraday::Request::UrlEncoded
393
+ end
394
+
395
+ Him::API.default_api.connection.adapter :test do |stub|
396
+ stub.get("/users/1") { |env| [200, {}, { id: 1, name: "Tobias", comments: [{ id: 2, body: "Hey!", user_id: 1 }] }.to_json] }
397
+ end
398
+
399
+ spawn_model "Foo::User" do
400
+ has_many :comments, class_name: "Foo::Comment"
401
+ end
402
+
403
+ spawn_model "Foo::Comment" do
404
+ belongs_to :user, class_name: "Foo::User"
405
+ end
406
+ end
407
+
408
+ it "does not infinitely loop when calling to_params with cyclic associations" do
409
+ user = Foo::User.find(1)
410
+ expect { Timeout.timeout(5) { user.to_params } }.not_to raise_error
411
+ end
412
+
413
+ it "does not include belongs_to parent data in nested to_params" do
414
+ user = Foo::User.find(1)
415
+ params = user.to_params
416
+ comment_params = params[:comments].first
417
+ expect(comment_params).not_to have_key(:user)
418
+ end
419
+ end
420
+
421
+ context "when parsed_data has string keys" do
422
+ before do
423
+ Him::API.setup url: "https://api.example.com" do |builder|
424
+ builder.use Class.new(Faraday::Middleware) {
425
+ def on_complete(env)
426
+ env[:body] = {
427
+ "data" => JSON.parse(env[:body]),
428
+ "metadata" => {},
429
+ "errors" => {}
430
+ }
431
+ end
432
+ }
433
+ builder.adapter :test do |stub|
434
+ stub.get("/users") { [200, {}, [{ "id" => 1, "name" => "Tobias" }].to_json] }
435
+ stub.get("/users/1") { [200, {}, { "id" => 1, "name" => "Tobias" }.to_json] }
436
+ end
437
+ end
438
+
439
+ spawn_model "Foo::User"
440
+ end
441
+
442
+ it "handles collections with string-keyed parsed data" do
443
+ users = Foo::User.all
444
+ expect(users.length).to eq(1)
445
+ expect(users.first.name).to eq("Tobias")
446
+ end
447
+
448
+ it "handles single resources with string-keyed parsed data" do
449
+ user = Foo::User.find(1)
450
+ expect(user.name).to eq("Tobias")
451
+ end
452
+ end
453
+
454
+ context "when parse_root_in_json set json_api to true" do
455
+ before do
456
+ Him::API.setup url: "https://api.example.com" do |builder|
457
+ builder.use Him::Middleware::FirstLevelParseJSON
458
+ builder.use Faraday::Request::UrlEncoded
459
+ builder.adapter :test do |stub|
460
+ stub.get("/users") { [200, {}, { users: [{ id: 1, fullname: "Lindsay Fünke" }] }.to_json] }
461
+ stub.get("/users/admins") { [200, {}, { users: [{ id: 1, fullname: "Lindsay Fünke" }] }.to_json] }
462
+ stub.get("/users/1") { [200, {}, { users: [{ id: 1, fullname: "Lindsay Fünke" }] }.to_json] }
463
+ stub.post("/users") { [200, {}, { users: [{ fullname: "Lindsay Fünke" }] }.to_json] }
464
+ stub.put("/users/1") { [200, {}, { users: [{ id: 1, fullname: "Tobias Fünke Jr." }] }.to_json] }
465
+ end
466
+ end
467
+
468
+ spawn_model("Foo::User") do
469
+ parse_root_in_json true, format: :json_api
470
+ include_root_in_json true
471
+ custom_get :admins
472
+ end
473
+ end
474
+
475
+ it "parse the data from the JSON root element after .create" do
476
+ @new_user = Foo::User.create(fullname: "Lindsay Fünke")
477
+ expect(@new_user.fullname).to eq("Lindsay Fünke")
478
+ end
479
+
480
+ it "parse the data from the JSON root element after an arbitrary HTTP request" do
481
+ @new_user = Foo::User.admins
482
+ expect(@new_user.first.fullname).to eq("Lindsay Fünke")
483
+ end
484
+
485
+ it "parse the data from the JSON root element after .all" do
486
+ @users = Foo::User.all
487
+ expect(@users.first.fullname).to eq("Lindsay Fünke")
488
+ end
489
+
490
+ it "parse the data from the JSON root element after .find" do
491
+ @user = Foo::User.find(1)
492
+ expect(@user.fullname).to eq("Lindsay Fünke")
493
+ end
494
+
495
+ it "parse the data from the JSON root element after .save" do
496
+ @user = Foo::User.find(1)
497
+ @user.fullname = "Tobias Fünke"
498
+ @user.save
499
+ expect(@user.fullname).to eq("Tobias Fünke Jr.")
500
+ end
501
+
502
+ it "parse the data from the JSON root element after new/save" do
503
+ @user = Foo::User.new
504
+ @user.fullname = "Lindsay Fünke (before save)"
505
+ @user.save
506
+ expect(@user.fullname).to eq("Lindsay Fünke")
507
+ end
508
+ end
509
+
510
+ context "when include_root_in_json set json_api" do
511
+ before do
512
+ Him::API.setup url: "https://api.example.com" do |builder|
513
+ builder.use Him::Middleware::FirstLevelParseJSON
514
+ builder.use Faraday::Request::UrlEncoded
515
+ end
516
+
517
+ Him::API.default_api.connection.adapter :test do |stub|
518
+ stub.post("/users") { |env| [200, {}, { users: [{ id: 1, fullname: params(env)[:users][:fullname] }] }.to_json] }
519
+ end
520
+ end
521
+
522
+ context "to true" do
523
+ before do
524
+ spawn_model "Foo::User" do
525
+ include_root_in_json true
526
+ parse_root_in_json true, format: :json_api
527
+ custom_post :admins
528
+ end
529
+ end
530
+
531
+ it "wraps params in the element name in `to_params`" do
532
+ @new_user = Foo::User.new(fullname: "Tobias Fünke")
533
+ expect(@new_user.to_params).to eq(users: [{ fullname: "Tobias Fünke" }])
534
+ end
535
+
536
+ it "wraps params in the element name in `.where`" do
537
+ @new_user = Foo::User.where(fullname: "Tobias Fünke").build
538
+ expect(@new_user.fullname).to eq("Tobias Fünke")
539
+ end
540
+ end
541
+ end
542
+
543
+ context "when send_only_modified_attributes is set" do
544
+ before do
545
+ Him::API.setup url: "https://api.example.com", send_only_modified_attributes: true do |builder|
546
+ builder.use Him::Middleware::FirstLevelParseJSON
547
+ builder.use Faraday::Request::UrlEncoded
548
+ end
549
+
550
+ Him::API.default_api.connection.adapter :test do |stub|
551
+ stub.get("/users/1") { [200, {}, { id: 1, first_name: "Gooby", last_name: "Pls" }.to_json] }
552
+ end
553
+
554
+ spawn_model "Foo::User" do
555
+ include_root_in_json true
556
+ end
557
+ end
558
+
559
+ it "only sends the attributes that were modified" do
560
+ user = Foo::User.find 1
561
+ user.first_name = "Someone"
562
+ expect(user.to_params).to eql(user: { first_name: "Someone" })
563
+ end
564
+
565
+ it "sends all attributes when changes is empty (custom actions)" do
566
+ user = Foo::User.find 1
567
+ params = Foo::User.to_params(user.attributes)
568
+ expect(params).to eql(user: { id: 1, first_name: "Gooby", last_name: "Pls" })
569
+ end
570
+ end
571
+
572
+ context 'when passed a non-Her ActiveModel instance' do
573
+ before do
574
+ klass = Class.new do
575
+ include ActiveModel::Serialization
576
+
577
+ def attributes
578
+ { 'name' => nil }
579
+ end
580
+
581
+ def name
582
+ 'foo'
583
+ end
584
+ end
585
+
586
+ @model = klass.new
587
+
588
+ Him::API.setup
589
+ spawn_model 'Foo::User'
590
+ end
591
+
592
+ it 'serializes the instance in `to_params`' do
593
+ attributes = { model: @model }
594
+ user = Foo::User.new(attributes)
595
+ expect(user.to_params).to eq(model: { name: 'foo' })
596
+ end
597
+ end
598
+
599
+ context "when attribute uses the same name as root element" do
600
+ before do
601
+ Him::API.setup url: "https://api.example.com" do |builder|
602
+ builder.use Him::Middleware::FirstLevelParseJSON
603
+ builder.use Faraday::Request::UrlEncoded
604
+ end
605
+
606
+ Him::API.default_api.connection.adapter :test do |stub|
607
+ stub.post("/users") { |env| [200, {}, { user: "foobar", id: 1, fullname: params(env)[:fullname] }.to_json] }
608
+ end
609
+
610
+ spawn_model "Foo::User"
611
+ end
612
+
613
+ it "parses as attribute instead of root element" do
614
+ user = Foo::User.create(fullname: "barfoo")
615
+ expect(user.fullname).to eq "barfoo"
616
+ expect(user.user).to eq "foobar"
617
+ end
618
+ end
619
+ end