her 0.8.2 → 0.9.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.
- checksums.yaml +4 -4
- data/.rspec +1 -1
- data/.rubocop.yml +1291 -0
- data/.travis.yml +2 -0
- data/README.md +23 -3
- data/her.gemspec +1 -3
- data/lib/her/middleware/json_api_parser.rb +1 -1
- data/lib/her/model/associations/association.rb +31 -0
- data/lib/her/model/associations/association_proxy.rb +1 -1
- data/lib/her/model/attributes.rb +2 -0
- data/lib/her/model/orm.rb +79 -6
- data/lib/her/model/parse.rb +8 -12
- data/lib/her/model/relation.rb +45 -1
- data/lib/her/version.rb +1 -1
- data/spec/api_spec.rb +34 -31
- data/spec/collection_spec.rb +25 -10
- data/spec/json_api/model_spec.rb +75 -72
- data/spec/middleware/accept_json_spec.rb +1 -1
- data/spec/middleware/first_level_parse_json_spec.rb +20 -20
- data/spec/middleware/json_api_parser_spec.rb +26 -7
- data/spec/middleware/second_level_parse_json_spec.rb +8 -9
- data/spec/model/associations/association_proxy_spec.rb +2 -5
- data/spec/model/associations_spec.rb +248 -161
- data/spec/model/attributes_spec.rb +106 -99
- data/spec/model/callbacks_spec.rb +58 -26
- data/spec/model/dirty_spec.rb +30 -29
- data/spec/model/http_spec.rb +67 -35
- data/spec/model/introspection_spec.rb +26 -22
- data/spec/model/nested_attributes_spec.rb +31 -31
- data/spec/model/orm_spec.rb +312 -155
- data/spec/model/parse_spec.rb +77 -77
- data/spec/model/paths_spec.rb +109 -109
- data/spec/model/relation_spec.rb +76 -68
- data/spec/model/validations_spec.rb +6 -6
- data/spec/model_spec.rb +17 -17
- data/spec/spec_helper.rb +2 -3
- data/spec/support/macros/model_macros.rb +2 -2
- metadata +32 -59
data/spec/model/orm_spec.rb
CHANGED
@@ -5,14 +5,14 @@ describe Her::Model::ORM do
|
|
5
5
|
context "mapping data to Ruby objects" do
|
6
6
|
before do
|
7
7
|
api = Her::API.new
|
8
|
-
api.setup :
|
8
|
+
api.setup url: "https://api.example.com" do |builder|
|
9
9
|
builder.use Her::Middleware::FirstLevelParseJSON
|
10
10
|
builder.use Faraday::Request::UrlEncoded
|
11
11
|
builder.adapter :test do |stub|
|
12
|
-
stub.get("/users/1") {
|
13
|
-
stub.get("/users") {
|
14
|
-
stub.get("/admin_users") {
|
15
|
-
stub.get("/admin_users/1") {
|
12
|
+
stub.get("/users/1") { [200, {}, { id: 1, name: "Tobias Fünke" }.to_json] }
|
13
|
+
stub.get("/users") { [200, {}, [{ id: 1, name: "Tobias Fünke" }, { id: 2, name: "Lindsay Fünke" }].to_json] }
|
14
|
+
stub.get("/admin_users") { [200, {}, [{ admin_id: 1, name: "Tobias Fünke" }, { admin_id: 2, name: "Lindsay Fünke" }].to_json] }
|
15
|
+
stub.get("/admin_users/1") { [200, {}, { admin_id: 1, name: "Tobias Fünke" }.to_json] }
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
@@ -28,53 +28,55 @@ describe Her::Model::ORM do
|
|
28
28
|
|
29
29
|
it "maps a single resource to a Ruby object" do
|
30
30
|
@user = Foo::User.find(1)
|
31
|
-
@user.id.
|
32
|
-
@user.name.
|
31
|
+
expect(@user.id).to eq(1)
|
32
|
+
expect(@user.name).to eq("Tobias Fünke")
|
33
33
|
|
34
34
|
@admin = Foo::AdminUser.find(1)
|
35
|
-
@admin.id.
|
36
|
-
@admin.name.
|
35
|
+
expect(@admin.id).to eq(1)
|
36
|
+
expect(@admin.name).to eq("Tobias Fünke")
|
37
37
|
end
|
38
38
|
|
39
39
|
it "maps a collection of resources to an array of Ruby objects" do
|
40
40
|
@users = Foo::User.all
|
41
|
-
@users.length.
|
42
|
-
@users.first.name.
|
41
|
+
expect(@users.length).to eq(2)
|
42
|
+
expect(@users.first.name).to eq("Tobias Fünke")
|
43
43
|
|
44
44
|
@users = Foo::AdminUser.all
|
45
|
-
@users.length.
|
46
|
-
@users.first.name.
|
45
|
+
expect(@users.length).to eq(2)
|
46
|
+
expect(@users.first.name).to eq("Tobias Fünke")
|
47
47
|
end
|
48
48
|
|
49
49
|
it "handles new resource" do
|
50
|
-
@new_user = Foo::User.new(:
|
51
|
-
@new_user.new
|
52
|
-
@new_user.new_record
|
53
|
-
@new_user.fullname.
|
50
|
+
@new_user = Foo::User.new(fullname: "Tobias Fünke")
|
51
|
+
expect(@new_user.new?).to be_truthy
|
52
|
+
expect(@new_user.new_record?).to be_truthy
|
53
|
+
expect(@new_user.fullname).to eq("Tobias Fünke")
|
54
54
|
|
55
55
|
@existing_user = Foo::User.find(1)
|
56
|
-
@existing_user.new
|
57
|
-
@existing_user.new_record
|
56
|
+
expect(@existing_user.new?).to be_falsey
|
57
|
+
expect(@existing_user.new_record?).to be_falsey
|
58
58
|
end
|
59
59
|
|
60
|
-
it
|
61
|
-
@new_user = Foo::AdminUser.new(:
|
62
|
-
@new_user.
|
60
|
+
it "handles new resource with custom primary key" do
|
61
|
+
@new_user = Foo::AdminUser.new(fullname: "Lindsay Fünke", id: -1)
|
62
|
+
expect(@new_user).to be_new
|
63
63
|
|
64
64
|
@existing_user = Foo::AdminUser.find(1)
|
65
|
-
@existing_user.
|
65
|
+
expect(@existing_user).not_to be_new
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
69
|
context "mapping data, metadata and error data to Ruby objects" do
|
70
70
|
before do
|
71
71
|
api = Her::API.new
|
72
|
-
api.setup :
|
72
|
+
api.setup url: "https://api.example.com" do |builder|
|
73
73
|
builder.use Her::Middleware::SecondLevelParseJSON
|
74
74
|
builder.use Faraday::Request::UrlEncoded
|
75
75
|
builder.adapter :test do |stub|
|
76
|
+
stub.get("/users") { [200, {}, { data: [{ id: 1, name: "Tobias Fünke" }, { id: 2, name: "Lindsay Fünke" }], metadata: { total_pages: 10, next_page: 2 }, errors: %w(Oh My God) }.to_json] }
|
76
77
|
stub.get("/users") { |env| [200, {}, { :data => [{ :id => 1, :name => "Tobias Fünke" }, { :id => 2, :name => "Lindsay Fünke" }], :metadata => { :total_pages => 10, :next_page => 2 }, :errors => ["Oh", "My", "God"] }.to_json] }
|
77
78
|
stub.post("/users") { |env| [200, {}, { :data => { :name => "George Michael Bluth" }, :metadata => { :foo => "bar" }, :errors => ["Yes", "Sir"] }.to_json] }
|
79
|
+
stub.delete("/users/1") { |env| [200, {}, { :data => { :id => 1 }, :metadata => { :foo => "bar" }, :errors => ["Yes", "Sir"] }.to_json] }
|
78
80
|
end
|
79
81
|
end
|
80
82
|
|
@@ -85,34 +87,44 @@ describe Her::Model::ORM do
|
|
85
87
|
|
86
88
|
it "handles metadata on a collection" do
|
87
89
|
@users = User.all
|
88
|
-
@users.metadata[:total_pages].
|
90
|
+
expect(@users.metadata[:total_pages]).to eq(10)
|
89
91
|
end
|
90
92
|
|
91
93
|
it "handles error data on a collection" do
|
92
94
|
@users = User.all
|
93
|
-
@users.errors.length.
|
95
|
+
expect(@users.errors.length).to eq(3)
|
94
96
|
end
|
95
97
|
|
96
98
|
it "handles metadata on a resource" do
|
97
|
-
@user = User.create(:
|
98
|
-
@user.metadata[:foo].
|
99
|
+
@user = User.create(name: "George Michael Bluth")
|
100
|
+
expect(@user.metadata[:foo]).to eq("bar")
|
99
101
|
end
|
100
102
|
|
101
103
|
it "handles error data on a resource" do
|
102
|
-
@user = User.create(:
|
103
|
-
@user.response_errors.
|
104
|
+
@user = User.create(name: "George Michael Bluth")
|
105
|
+
expect(@user.response_errors).to eq(%w(Yes Sir))
|
106
|
+
end
|
107
|
+
|
108
|
+
it "handles metadata on a destroyed resource" do
|
109
|
+
@user = User.destroy_existing(1)
|
110
|
+
expect(@user.metadata[:foo]).to eq("bar")
|
111
|
+
end
|
112
|
+
|
113
|
+
it "handles error data on a destroyed resource" do
|
114
|
+
@user = User.destroy_existing(1)
|
115
|
+
expect(@user.response_errors).to eq(%w(Yes Sir))
|
104
116
|
end
|
105
117
|
end
|
106
118
|
|
107
119
|
context "mapping data, metadata and error data in string keys to Ruby objects" do
|
108
120
|
before do
|
109
121
|
api = Her::API.new
|
110
|
-
api.setup :
|
122
|
+
api.setup url: "https://api.example.com" do |builder|
|
111
123
|
builder.use Her::Middleware::SecondLevelParseJSON
|
112
124
|
builder.use Faraday::Request::UrlEncoded
|
113
125
|
builder.adapter :test do |stub|
|
114
|
-
stub.get("/users") {
|
115
|
-
stub.post("/users") {
|
126
|
+
stub.get("/users") { [200, {}, { data: [{ id: 1, name: "Tobias Fünke" }, { id: 2, name: "Lindsay Fünke" }], metadata: { total_pages: 10, next_page: 2 }, errors: %w(Oh My God) }.to_json] }
|
127
|
+
stub.post("/users") { [200, {}, { data: { name: "George Michael Bluth" }, metadata: { foo: "bar" }, errors: %w(Yes Sir) }.to_json] }
|
116
128
|
end
|
117
129
|
end
|
118
130
|
|
@@ -123,34 +135,34 @@ describe Her::Model::ORM do
|
|
123
135
|
|
124
136
|
it "handles metadata on a collection" do
|
125
137
|
@users = User.all
|
126
|
-
@users.metadata[:total_pages].
|
138
|
+
expect(@users.metadata[:total_pages]).to eq(10)
|
127
139
|
end
|
128
140
|
|
129
141
|
it "handles error data on a collection" do
|
130
142
|
@users = User.all
|
131
|
-
@users.errors.length.
|
143
|
+
expect(@users.errors.length).to eq(3)
|
132
144
|
end
|
133
145
|
|
134
146
|
it "handles metadata on a resource" do
|
135
|
-
@user = User.create(:
|
136
|
-
@user.metadata[:foo].
|
147
|
+
@user = User.create(name: "George Michael Bluth")
|
148
|
+
expect(@user.metadata[:foo]).to eq("bar")
|
137
149
|
end
|
138
150
|
|
139
151
|
it "handles error data on a resource" do
|
140
|
-
@user = User.create(:
|
141
|
-
@user.response_errors.
|
152
|
+
@user = User.create(name: "George Michael Bluth")
|
153
|
+
expect(@user.response_errors).to eq(%w(Yes Sir))
|
142
154
|
end
|
143
155
|
end
|
144
156
|
|
145
157
|
context "defining custom getters and setters" do
|
146
158
|
before do
|
147
159
|
api = Her::API.new
|
148
|
-
api.setup :
|
160
|
+
api.setup url: "https://api.example.com" do |builder|
|
149
161
|
builder.use Her::Middleware::FirstLevelParseJSON
|
150
162
|
builder.use Faraday::Request::UrlEncoded
|
151
163
|
builder.adapter :test do |stub|
|
152
|
-
stub.get("/users/1") {
|
153
|
-
stub.get("/users/2") {
|
164
|
+
stub.get("/users/1") { [200, {}, { id: 1, friends: %w(Maeby GOB Anne) }.to_json] }
|
165
|
+
stub.get("/users/2") { [200, {}, { id: 1 }.to_json] }
|
154
166
|
end
|
155
167
|
end
|
156
168
|
|
@@ -159,7 +171,7 @@ describe Her::Model::ORM do
|
|
159
171
|
belongs_to :organization
|
160
172
|
|
161
173
|
def friends=(val)
|
162
|
-
val = val.
|
174
|
+
val = val.delete("\r").split("\n").map { |friend| friend.gsub(/^\s*\*\s*/, "") } if val && val.is_a?(String)
|
163
175
|
@attributes[:friends] = val
|
164
176
|
end
|
165
177
|
|
@@ -171,18 +183,18 @@ describe Her::Model::ORM do
|
|
171
183
|
|
172
184
|
it "handles custom setters" do
|
173
185
|
@user = User.find(1)
|
174
|
-
@user.friends.
|
186
|
+
expect(@user.friends).to eq("* Maeby\n* GOB\n* Anne")
|
175
187
|
@user.instance_eval do
|
176
|
-
@attributes[:friends] =
|
188
|
+
@attributes[:friends] = %w(Maeby GOB Anne)
|
177
189
|
end
|
178
190
|
end
|
179
191
|
|
180
192
|
it "handles custom getters" do
|
181
193
|
@user = User.new
|
182
194
|
@user.friends = "* George\n* Oscar\n* Lucille"
|
183
|
-
@user.friends.
|
195
|
+
expect(@user.friends).to eq("* George\n* Oscar\n* Lucille")
|
184
196
|
@user.instance_eval do
|
185
|
-
@attributes[:friends] =
|
197
|
+
@attributes[:friends] = %w(George Oscar Lucille)
|
186
198
|
end
|
187
199
|
end
|
188
200
|
end
|
@@ -190,16 +202,18 @@ describe Her::Model::ORM do
|
|
190
202
|
context "finding resources" do
|
191
203
|
before do
|
192
204
|
api = Her::API.new
|
193
|
-
api.setup :
|
205
|
+
api.setup url: "https://api.example.com" do |builder|
|
194
206
|
builder.use Her::Middleware::FirstLevelParseJSON
|
195
207
|
builder.use Faraday::Request::UrlEncoded
|
196
208
|
builder.adapter :test do |stub|
|
197
|
-
stub.get("/users/1") {
|
198
|
-
stub.get("/users/2") {
|
199
|
-
stub.get("/users?id[]=1&id[]=2") {
|
200
|
-
stub.get("/users?age=42&foo=bar") {
|
201
|
-
stub.get("/users?age=42") {
|
202
|
-
stub.get("/users?age=40") {
|
209
|
+
stub.get("/users/1") { [200, {}, { id: 1, age: 42 }.to_json] }
|
210
|
+
stub.get("/users/2") { [200, {}, { id: 2, age: 34 }.to_json] }
|
211
|
+
stub.get("/users?id[]=1&id[]=2") { [200, {}, [{ id: 1, age: 42 }, { id: 2, age: 34 }].to_json] }
|
212
|
+
stub.get("/users?age=42&foo=bar") { [200, {}, [{ id: 3, age: 42 }].to_json] }
|
213
|
+
stub.get("/users?age=42") { [200, {}, [{ id: 1, age: 42 }].to_json] }
|
214
|
+
stub.get("/users?age=40") { [200, {}, [{ id: 1, age: 40 }].to_json] }
|
215
|
+
stub.get("/users?name=baz") { [200, {}, [].to_json] }
|
216
|
+
stub.post("/users") { [200, {}, { id: 5, name: "baz" }.to_json] }
|
203
217
|
end
|
204
218
|
end
|
205
219
|
|
@@ -210,58 +224,84 @@ describe Her::Model::ORM do
|
|
210
224
|
|
211
225
|
it "handles finding by a single id" do
|
212
226
|
@user = User.find(1)
|
213
|
-
@user.id.
|
227
|
+
expect(@user.id).to eq(1)
|
214
228
|
end
|
215
229
|
|
216
230
|
it "handles finding by multiple ids" do
|
217
231
|
@users = User.find(1, 2)
|
218
|
-
@users.
|
219
|
-
@users.length.
|
220
|
-
@users[0].id.
|
221
|
-
@users[1].id.
|
232
|
+
expect(@users).to be_kind_of(Array)
|
233
|
+
expect(@users.length).to eq(2)
|
234
|
+
expect(@users[0].id).to eq(1)
|
235
|
+
expect(@users[1].id).to eq(2)
|
222
236
|
end
|
223
237
|
|
224
238
|
it "handles finding by an array of ids" do
|
225
239
|
@users = User.find([1, 2])
|
226
|
-
@users.
|
227
|
-
@users.length.
|
228
|
-
@users[0].id.
|
229
|
-
@users[1].id.
|
240
|
+
expect(@users).to be_kind_of(Array)
|
241
|
+
expect(@users.length).to eq(2)
|
242
|
+
expect(@users[0].id).to eq(1)
|
243
|
+
expect(@users[1].id).to eq(2)
|
230
244
|
end
|
231
245
|
|
232
246
|
it "handles finding by an array of ids of length 1" do
|
233
247
|
@users = User.find([1])
|
234
|
-
@users.
|
235
|
-
@users.length.
|
236
|
-
@users[0].id.
|
248
|
+
expect(@users).to be_kind_of(Array)
|
249
|
+
expect(@users.length).to eq(1)
|
250
|
+
expect(@users[0].id).to eq(1)
|
237
251
|
end
|
238
252
|
|
239
253
|
it "handles finding by an array id param of length 2" do
|
240
254
|
@users = User.find(id: [1, 2])
|
241
|
-
@users.
|
242
|
-
@users.length.
|
243
|
-
@users[0].id.
|
244
|
-
@users[1].id.
|
255
|
+
expect(@users).to be_kind_of(Array)
|
256
|
+
expect(@users.length).to eq(2)
|
257
|
+
expect(@users[0].id).to eq(1)
|
258
|
+
expect(@users[1].id).to eq(2)
|
245
259
|
end
|
246
260
|
|
247
|
-
it
|
261
|
+
it "handles finding with id parameter as an array" do
|
248
262
|
@users = User.where(id: [1, 2])
|
249
|
-
@users.
|
250
|
-
@users.length.
|
251
|
-
@users[0].id.
|
252
|
-
@users[1].id.
|
263
|
+
expect(@users).to be_kind_of(Array)
|
264
|
+
expect(@users.length).to eq(2)
|
265
|
+
expect(@users[0].id).to eq(1)
|
266
|
+
expect(@users[1].id).to eq(2)
|
267
|
+
end
|
268
|
+
|
269
|
+
it "handles finding by attributes" do
|
270
|
+
@user = User.find_by(age: 42)
|
271
|
+
expect(@user).to be_a(User)
|
272
|
+
expect(@user.id).to eq(1)
|
273
|
+
end
|
274
|
+
|
275
|
+
it "handles find or create by attributes" do
|
276
|
+
@user = User.find_or_create_by(name: "baz")
|
277
|
+
expect(@user).to be_a(User)
|
278
|
+
expect(@user.id).to eq(5)
|
279
|
+
end
|
280
|
+
|
281
|
+
it "handles find or initialize by attributes" do
|
282
|
+
@user = User.find_or_initialize_by(name: "baz")
|
283
|
+
expect(@user).to be_a(User)
|
284
|
+
expect(@user).to_not be_persisted
|
253
285
|
end
|
254
286
|
|
255
287
|
it "handles finding with other parameters" do
|
256
|
-
@users = User.where(:
|
257
|
-
@users.
|
258
|
-
@users.first.id.
|
288
|
+
@users = User.where(age: 42, foo: "bar").all
|
289
|
+
expect(@users).to be_kind_of(Array)
|
290
|
+
expect(@users.first.id).to eq(3)
|
259
291
|
end
|
260
292
|
|
261
293
|
it "handles finding with other parameters and scoped" do
|
262
294
|
@users = User.scoped
|
263
|
-
@users.where(:
|
264
|
-
@users.where(:
|
295
|
+
expect(@users.where(age: 42)).to be_all { |u| u.age == 42 }
|
296
|
+
expect(@users.where(age: 40)).to be_all { |u| u.age == 40 }
|
297
|
+
end
|
298
|
+
|
299
|
+
it "handles reloading a resource" do
|
300
|
+
@user = User.find(1)
|
301
|
+
@user.age = "Oops"
|
302
|
+
@user.reload
|
303
|
+
expect(@user.age).to eq 42
|
304
|
+
expect(@user).to be_persisted
|
265
305
|
end
|
266
306
|
end
|
267
307
|
|
@@ -272,20 +312,20 @@ describe Her::Model::ORM do
|
|
272
312
|
end
|
273
313
|
|
274
314
|
it "builds a new resource without requesting it" do
|
275
|
-
Foo::User.
|
276
|
-
@new_user = Foo::User.build(:
|
277
|
-
@new_user.new
|
278
|
-
@new_user.fullname.
|
315
|
+
expect(Foo::User).not_to receive(:request)
|
316
|
+
@new_user = Foo::User.build(fullname: "Tobias Fünke")
|
317
|
+
expect(@new_user.new?).to be_truthy
|
318
|
+
expect(@new_user.fullname).to eq("Tobias Fünke")
|
279
319
|
end
|
280
320
|
end
|
281
321
|
|
282
322
|
context "when request_new_object_on_build is set" do
|
283
323
|
before do
|
284
|
-
Her::API.setup :
|
324
|
+
Her::API.setup url: "https://api.example.com" do |builder|
|
285
325
|
builder.use Her::Middleware::FirstLevelParseJSON
|
286
326
|
builder.use Faraday::Request::UrlEncoded
|
287
327
|
builder.adapter :test do |stub|
|
288
|
-
stub.get("/users/new") { |env| ok! :
|
328
|
+
stub.get("/users/new") { |env| ok! id: nil, fullname: params(env)[:fullname], email: "tobias@bluthcompany.com" }
|
289
329
|
end
|
290
330
|
end
|
291
331
|
|
@@ -293,23 +333,23 @@ describe Her::Model::ORM do
|
|
293
333
|
end
|
294
334
|
|
295
335
|
it "requests a new resource" do
|
296
|
-
Foo::User.
|
297
|
-
@new_user = Foo::User.build(:
|
298
|
-
@new_user.new
|
299
|
-
@new_user.fullname.
|
300
|
-
@new_user.email.
|
336
|
+
expect(Foo::User).to receive(:request).once.and_call_original
|
337
|
+
@new_user = Foo::User.build(fullname: "Tobias Fünke")
|
338
|
+
expect(@new_user.new?).to be_truthy
|
339
|
+
expect(@new_user.fullname).to eq("Tobias Fünke")
|
340
|
+
expect(@new_user.email).to eq("tobias@bluthcompany.com")
|
301
341
|
end
|
302
342
|
end
|
303
343
|
end
|
304
344
|
|
305
345
|
context "creating resources" do
|
306
346
|
before do
|
307
|
-
Her::API.setup :
|
347
|
+
Her::API.setup url: "https://api.example.com" do |builder|
|
308
348
|
builder.use Her::Middleware::FirstLevelParseJSON
|
309
349
|
builder.use Faraday::Request::UrlEncoded
|
310
350
|
builder.adapter :test do |stub|
|
311
|
-
stub.post("/users") { |env| [200, {}, { :
|
312
|
-
stub.post("/companies") {
|
351
|
+
stub.post("/users") { |env| [200, {}, { id: 1, fullname: Faraday::Utils.parse_query(env[:body])["fullname"], email: Faraday::Utils.parse_query(env[:body])["email"] }.to_json] }
|
352
|
+
stub.post("/companies") { [200, {}, { errors: ["name is required"] }.to_json] }
|
313
353
|
end
|
314
354
|
end
|
315
355
|
|
@@ -318,27 +358,27 @@ describe Her::Model::ORM do
|
|
318
358
|
end
|
319
359
|
|
320
360
|
it "handle one-line resource creation" do
|
321
|
-
@user = Foo::User.create(:
|
322
|
-
@user.id.
|
323
|
-
@user.fullname.
|
324
|
-
@user.email.
|
361
|
+
@user = Foo::User.create(fullname: "Tobias Fünke", email: "tobias@bluth.com")
|
362
|
+
expect(@user.id).to eq(1)
|
363
|
+
expect(@user.fullname).to eq("Tobias Fünke")
|
364
|
+
expect(@user.email).to eq("tobias@bluth.com")
|
325
365
|
end
|
326
366
|
|
327
367
|
it "handle resource creation through Model.new + #save" do
|
328
|
-
@user = Foo::User.new(:
|
329
|
-
@user.save.
|
330
|
-
@user.fullname.
|
368
|
+
@user = Foo::User.new(fullname: "Tobias Fünke")
|
369
|
+
expect(@user.save).to be_truthy
|
370
|
+
expect(@user.fullname).to eq("Tobias Fünke")
|
331
371
|
end
|
332
372
|
|
333
373
|
it "handle resource creation through Model.new + #save!" do
|
334
|
-
@user = Foo::User.new(:
|
335
|
-
@user.save
|
336
|
-
@user.fullname.
|
374
|
+
@user = Foo::User.new(fullname: "Tobias Fünke")
|
375
|
+
expect(@user.save!).to be_truthy
|
376
|
+
expect(@user.fullname).to eq("Tobias Fünke")
|
337
377
|
end
|
338
378
|
|
339
379
|
it "returns false when #save gets errors" do
|
340
380
|
@company = Foo::Company.new
|
341
|
-
@company.save.
|
381
|
+
expect(@company.save).to be_falsey
|
342
382
|
end
|
343
383
|
|
344
384
|
it "raises ResourceInvalid when #save! gets errors" do
|
@@ -347,54 +387,110 @@ describe Her::Model::ORM do
|
|
347
387
|
end
|
348
388
|
|
349
389
|
it "don't overwrite data if response is empty" do
|
350
|
-
@company = Foo::Company.new(:
|
351
|
-
@company.save.
|
352
|
-
@company.name.
|
390
|
+
@company = Foo::Company.new(name: "Company Inc.")
|
391
|
+
expect(@company.save).to be_falsey
|
392
|
+
expect(@company.name).to eq("Company Inc.")
|
353
393
|
end
|
354
394
|
end
|
355
395
|
|
356
396
|
context "updating resources" do
|
357
397
|
before do
|
358
|
-
Her::API.setup :
|
398
|
+
Her::API.setup url: "https://api.example.com" do |builder|
|
359
399
|
builder.use Her::Middleware::FirstLevelParseJSON
|
360
400
|
builder.use Faraday::Request::UrlEncoded
|
361
401
|
builder.adapter :test do |stub|
|
362
|
-
stub.get("/users/1") {
|
363
|
-
stub.put("/users/1") {
|
402
|
+
stub.get("/users/1") { [200, {}, { id: 1, fullname: "Tobias Fünke", admin: false }.to_json] }
|
403
|
+
stub.put("/users/1") { [200, {}, { id: 1, fullname: "Lindsay Fünke", admin: true }.to_json] }
|
404
|
+
stub.get("/pages/1") { [200, {}, { id: 1, views: 1, unique_visitors: 4 }.to_json] }
|
405
|
+
stub.put("/pages/1") { [200, {}, { id: 1, views: 2, unique_visitors: 3 }.to_json] }
|
364
406
|
end
|
365
407
|
end
|
366
408
|
|
367
409
|
spawn_model "Foo::User"
|
410
|
+
spawn_model "Foo::Page"
|
368
411
|
end
|
369
412
|
|
370
413
|
it "handle resource data update without saving it" do
|
371
414
|
@user = Foo::User.find(1)
|
372
|
-
@user.fullname.
|
415
|
+
expect(@user.fullname).to eq("Tobias Fünke")
|
373
416
|
@user.fullname = "Kittie Sanchez"
|
374
|
-
@user.fullname.
|
417
|
+
expect(@user.fullname).to eq("Kittie Sanchez")
|
375
418
|
end
|
376
419
|
|
377
420
|
it "handle resource update through the .update class method" do
|
378
|
-
@user = Foo::User.save_existing(1,
|
379
|
-
@user.fullname.
|
421
|
+
@user = Foo::User.save_existing(1, fullname: "Lindsay Fünke")
|
422
|
+
expect(@user.fullname).to eq("Lindsay Fünke")
|
380
423
|
end
|
381
424
|
|
382
425
|
it "handle resource update through #save on an existing resource" do
|
383
426
|
@user = Foo::User.find(1)
|
384
427
|
@user.fullname = "Lindsay Fünke"
|
385
428
|
@user.save
|
386
|
-
@user.fullname.
|
429
|
+
expect(@user.fullname).to eq("Lindsay Fünke")
|
430
|
+
end
|
431
|
+
|
432
|
+
it "handles resource update through #toggle without saving it" do
|
433
|
+
@user = Foo::User.find(1)
|
434
|
+
expect(@user.admin).to be_falsey
|
435
|
+
expect(@user).to_not receive(:save)
|
436
|
+
@user.toggle(:admin)
|
437
|
+
expect(@user.admin).to be_truthy
|
438
|
+
end
|
439
|
+
|
440
|
+
it "handles resource update through #toggle!" do
|
441
|
+
@user = Foo::User.find(1)
|
442
|
+
expect(@user.admin).to be_falsey
|
443
|
+
expect(@user).to receive(:save).and_return(true)
|
444
|
+
@user.toggle!(:admin)
|
445
|
+
expect(@user.admin).to be_truthy
|
446
|
+
end
|
447
|
+
|
448
|
+
it "handles resource update through #increment without saving it" do
|
449
|
+
page = Foo::Page.find(1)
|
450
|
+
expect(page.views).to be 1
|
451
|
+
expect(page).to_not receive(:save)
|
452
|
+
page.increment(:views)
|
453
|
+
expect(page.views).to be 2
|
454
|
+
page.increment(:views, 2)
|
455
|
+
expect(page.views).to be 4
|
456
|
+
end
|
457
|
+
|
458
|
+
it "handles resource update through #increment!" do
|
459
|
+
page = Foo::Page.find(1)
|
460
|
+
expect(page.views).to be 1
|
461
|
+
expect(page).to receive(:save).and_return(true)
|
462
|
+
page.increment!(:views)
|
463
|
+
expect(page.views).to be 2
|
464
|
+
end
|
465
|
+
|
466
|
+
it "handles resource update through #decrement without saving it" do
|
467
|
+
page = Foo::Page.find(1)
|
468
|
+
expect(page.unique_visitors).to be 4
|
469
|
+
expect(page).to_not receive(:save)
|
470
|
+
page.decrement(:unique_visitors)
|
471
|
+
expect(page.unique_visitors).to be 3
|
472
|
+
page.decrement(:unique_visitors, 2)
|
473
|
+
expect(page.unique_visitors).to be 1
|
474
|
+
end
|
475
|
+
|
476
|
+
it "handles resource update through #decrement!" do
|
477
|
+
page = Foo::Page.find(1)
|
478
|
+
expect(page.unique_visitors).to be 4
|
479
|
+
expect(page).to receive(:save).and_return(true)
|
480
|
+
page.decrement!(:unique_visitors)
|
481
|
+
expect(page.unique_visitors).to be 3
|
387
482
|
end
|
388
483
|
end
|
389
484
|
|
390
485
|
context "deleting resources" do
|
486
|
+
let(:status) { 200 }
|
391
487
|
before do
|
392
|
-
Her::API.setup :
|
488
|
+
Her::API.setup url: "https://api.example.com" do |builder|
|
393
489
|
builder.use Her::Middleware::FirstLevelParseJSON
|
394
490
|
builder.use Faraday::Request::UrlEncoded
|
395
491
|
builder.adapter :test do |stub|
|
396
|
-
stub.get("/users/1") {
|
397
|
-
stub.delete("/users/1") {
|
492
|
+
stub.get("/users/1") { [200, {}, { id: 1, fullname: "Tobias Fünke", active: true }.to_json] }
|
493
|
+
stub.delete("/users/1") { [status, {}, { id: 1, fullname: "Lindsay Fünke", active: false }.to_json] }
|
398
494
|
end
|
399
495
|
end
|
400
496
|
|
@@ -403,104 +499,165 @@ describe Her::Model::ORM do
|
|
403
499
|
|
404
500
|
it "handle resource deletion through the .destroy class method" do
|
405
501
|
@user = Foo::User.destroy_existing(1)
|
406
|
-
@user.active.
|
407
|
-
@user.
|
502
|
+
expect(@user.active).to be_falsey
|
503
|
+
expect(@user).to be_destroyed
|
408
504
|
end
|
409
505
|
|
410
506
|
it "handle resource deletion through #destroy on an existing resource" do
|
411
507
|
@user = Foo::User.find(1)
|
412
508
|
@user.destroy
|
413
|
-
@user.active.
|
414
|
-
@user.
|
509
|
+
expect(@user.active).to be_falsey
|
510
|
+
expect(@user).to be_destroyed
|
511
|
+
end
|
512
|
+
|
513
|
+
context "with response_errors" do
|
514
|
+
let(:status) { 422 }
|
515
|
+
it "set user.destroyed to false if errors are present through the .destroy class method" do
|
516
|
+
@user = Foo::User.destroy_existing(1)
|
517
|
+
expect(@user).not_to be_destroyed
|
518
|
+
end
|
519
|
+
|
520
|
+
it "set user.destroyed to false if errors are present through #destroy on an existing resource" do
|
521
|
+
@user = Foo::User.find(1)
|
522
|
+
@user.destroy
|
523
|
+
expect(@user).not_to be_destroyed
|
524
|
+
end
|
415
525
|
end
|
416
526
|
|
417
527
|
context "with params" do
|
418
528
|
before do
|
419
|
-
Her::API.setup :
|
529
|
+
Her::API.setup url: "https://api.example.com" do |builder|
|
420
530
|
builder.use Her::Middleware::FirstLevelParseJSON
|
421
531
|
builder.use Faraday::Request::UrlEncoded
|
422
532
|
builder.adapter :test do |stub|
|
423
|
-
stub.delete("/users/1?delete_type=soft") {
|
533
|
+
stub.delete("/users/1?delete_type=soft") { [200, {}, { id: 1, fullname: "Lindsay Fünke", active: false }.to_json] }
|
424
534
|
end
|
425
535
|
end
|
426
536
|
end
|
427
537
|
|
428
538
|
it "handle resource deletion through the .destroy class method" do
|
429
|
-
@user = Foo::User.destroy_existing(1, delete_type:
|
430
|
-
@user.active.
|
431
|
-
@user.
|
539
|
+
@user = Foo::User.destroy_existing(1, delete_type: "soft")
|
540
|
+
expect(@user.active).to be_falsey
|
541
|
+
expect(@user).to be_destroyed
|
432
542
|
end
|
433
543
|
|
434
544
|
it "handle resource deletion through #destroy on an existing resource" do
|
435
545
|
@user = Foo::User.find(1)
|
436
|
-
@user.destroy(delete_type:
|
437
|
-
@user.active.
|
438
|
-
@user.
|
546
|
+
@user.destroy(delete_type: "soft")
|
547
|
+
expect(@user.active).to be_falsey
|
548
|
+
expect(@user).to be_destroyed
|
439
549
|
end
|
440
550
|
end
|
441
551
|
end
|
442
552
|
|
443
|
-
context
|
553
|
+
context "customizing HTTP methods" do
|
444
554
|
before do
|
445
|
-
Her::API.setup :
|
555
|
+
Her::API.setup url: "https://api.example.com" do |builder|
|
446
556
|
builder.use Her::Middleware::FirstLevelParseJSON
|
447
557
|
builder.use Faraday::Request::UrlEncoded
|
448
558
|
end
|
449
559
|
end
|
450
560
|
|
451
|
-
context
|
561
|
+
context "create" do
|
452
562
|
before do
|
453
563
|
Her::API.default_api.connection.adapter :test do |stub|
|
454
|
-
stub.put(
|
564
|
+
stub.put("/users") { [200, {}, { id: 1, fullname: "Tobias Fünke" }.to_json] }
|
455
565
|
end
|
456
|
-
spawn_model
|
566
|
+
spawn_model "Foo::User" do
|
457
567
|
attributes :fullname, :email
|
458
|
-
method_for :create,
|
568
|
+
method_for :create, "PUT"
|
459
569
|
end
|
460
570
|
end
|
461
571
|
|
462
|
-
context
|
463
|
-
it
|
464
|
-
user = Foo::User.new(:
|
465
|
-
user.
|
466
|
-
user.save.
|
572
|
+
context "for top-level class" do
|
573
|
+
it "uses the custom method (PUT) instead of default method (POST)" do
|
574
|
+
user = Foo::User.new(fullname: "Tobias Fünke")
|
575
|
+
expect(user).to be_new
|
576
|
+
expect(user.save).to be_truthy
|
467
577
|
end
|
468
578
|
end
|
469
579
|
|
470
|
-
context
|
580
|
+
context "for children class" do
|
471
581
|
before do
|
472
582
|
class User < Foo::User; end
|
473
583
|
@spawned_models << :User
|
474
584
|
end
|
475
585
|
|
476
|
-
it
|
477
|
-
user = User.new(:
|
478
|
-
user.
|
479
|
-
user.save.
|
586
|
+
it "uses the custom method (PUT) instead of default method (POST)" do
|
587
|
+
user = User.new(fullname: "Tobias Fünke")
|
588
|
+
expect(user).to be_new
|
589
|
+
expect(user.save).to be_truthy
|
480
590
|
end
|
481
591
|
end
|
482
592
|
end
|
483
593
|
|
484
|
-
context
|
594
|
+
context "update" do
|
485
595
|
before do
|
486
596
|
Her::API.default_api.connection.adapter :test do |stub|
|
487
|
-
stub.get(
|
488
|
-
stub.post(
|
597
|
+
stub.get("/users/1") { [200, {}, { id: 1, fullname: "Lindsay Fünke" }.to_json] }
|
598
|
+
stub.post("/users/1") { [200, {}, { id: 1, fullname: "Tobias Fünke" }.to_json] }
|
489
599
|
end
|
490
600
|
|
491
|
-
spawn_model
|
601
|
+
spawn_model "Foo::User" do
|
492
602
|
attributes :fullname, :email
|
493
603
|
method_for :update, :post
|
494
604
|
end
|
495
605
|
end
|
496
606
|
|
497
|
-
it
|
607
|
+
it "uses the custom method (POST) instead of default method (PUT)" do
|
498
608
|
user = Foo::User.find(1)
|
499
|
-
user.fullname.
|
500
|
-
user.fullname =
|
609
|
+
expect(user.fullname).to eq "Lindsay Fünke"
|
610
|
+
user.fullname = "Toby Fünke"
|
501
611
|
user.save
|
502
|
-
user.fullname.
|
612
|
+
expect(user.fullname).to eq "Tobias Fünke"
|
503
613
|
end
|
504
614
|
end
|
505
615
|
end
|
616
|
+
|
617
|
+
context "registering callbacks" do
|
618
|
+
before do
|
619
|
+
Her::API.setup url: "https://api.example.com" do |builder|
|
620
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
621
|
+
builder.use Faraday::Request::UrlEncoded
|
622
|
+
builder.adapter :test do |stub|
|
623
|
+
stub.get("/users/1") { [200, {}, { id: 1, fullname: "Tobias Fünke" }.to_json] }
|
624
|
+
stub.put("/users/1") { [200, {}, { id: 1, fullname: "Tobias Fünke" }.to_json] }
|
625
|
+
stub.post("/users") { [200, {}, { id: 2, fullname: "Lindsay Fünke" }.to_json] }
|
626
|
+
end
|
627
|
+
end
|
628
|
+
|
629
|
+
spawn_model "User" do
|
630
|
+
before_save :before_save_callback
|
631
|
+
before_create :before_create_callback
|
632
|
+
before_update :before_update_callback
|
633
|
+
after_update :after_update_callback
|
634
|
+
after_create :after_create_callback
|
635
|
+
after_save :after_save_callback
|
636
|
+
def before_save_callback; end
|
637
|
+
def before_create_callback; end
|
638
|
+
def before_update_callback; end
|
639
|
+
def after_update_callback; end
|
640
|
+
def after_create_callback; end
|
641
|
+
def after_save_callback; end
|
642
|
+
end
|
643
|
+
end
|
644
|
+
|
645
|
+
it "runs create callbacks in the correct order" do
|
646
|
+
@user = User.new(fullname: "Tobias Fünke")
|
647
|
+
expect(@user).to receive(:before_save_callback).ordered
|
648
|
+
expect(@user).to receive(:before_create_callback).ordered
|
649
|
+
expect(@user).to receive(:after_create_callback).ordered
|
650
|
+
expect(@user).to receive(:after_save_callback).ordered
|
651
|
+
@user.save
|
652
|
+
end
|
653
|
+
|
654
|
+
it "runs update callbacks in the correct order" do
|
655
|
+
@user = User.find(1)
|
656
|
+
expect(@user).to receive(:before_save_callback).ordered
|
657
|
+
expect(@user).to receive(:before_update_callback).ordered
|
658
|
+
expect(@user).to receive(:after_update_callback).ordered
|
659
|
+
expect(@user).to receive(:after_save_callback).ordered
|
660
|
+
@user.save
|
661
|
+
end
|
662
|
+
end
|
506
663
|
end
|