restorm 1.0.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 +7 -0
- data/.gitignore +4 -0
- data/.rspec +1 -0
- data/.rubocop.yml +31 -0
- data/.rubocop_todo.yml +232 -0
- data/.ruby-version +1 -0
- data/.travis.yml +55 -0
- data/.yardopts +2 -0
- data/CONTRIBUTING.md +26 -0
- data/Gemfile +10 -0
- data/HER_README.md +1065 -0
- data/LICENSE +7 -0
- data/README.md +7 -0
- data/Rakefile +11 -0
- data/UPGRADE.md +101 -0
- data/gemfiles/Gemfile.activemodel-4.2 +6 -0
- data/gemfiles/Gemfile.activemodel-5.0 +6 -0
- data/gemfiles/Gemfile.activemodel-5.1 +6 -0
- data/gemfiles/Gemfile.activemodel-5.2 +6 -0
- data/gemfiles/Gemfile.faraday-1.0 +6 -0
- data/lib/restorm/api.rb +121 -0
- data/lib/restorm/collection.rb +13 -0
- data/lib/restorm/errors.rb +29 -0
- data/lib/restorm/json_api/model.rb +42 -0
- data/lib/restorm/middleware/accept_json.rb +18 -0
- data/lib/restorm/middleware/first_level_parse_json.rb +37 -0
- data/lib/restorm/middleware/json_api_parser.rb +37 -0
- data/lib/restorm/middleware/parse_json.rb +22 -0
- data/lib/restorm/middleware/second_level_parse_json.rb +37 -0
- data/lib/restorm/middleware.rb +12 -0
- data/lib/restorm/model/associations/association.rb +128 -0
- data/lib/restorm/model/associations/association_proxy.rb +44 -0
- data/lib/restorm/model/associations/belongs_to_association.rb +95 -0
- data/lib/restorm/model/associations/has_many_association.rb +100 -0
- data/lib/restorm/model/associations/has_one_association.rb +79 -0
- data/lib/restorm/model/associations.rb +141 -0
- data/lib/restorm/model/attributes.rb +322 -0
- data/lib/restorm/model/base.rb +33 -0
- data/lib/restorm/model/deprecated_methods.rb +61 -0
- data/lib/restorm/model/http.rb +119 -0
- data/lib/restorm/model/introspection.rb +67 -0
- data/lib/restorm/model/nested_attributes.rb +45 -0
- data/lib/restorm/model/orm.rb +299 -0
- data/lib/restorm/model/parse.rb +223 -0
- data/lib/restorm/model/paths.rb +125 -0
- data/lib/restorm/model/relation.rb +209 -0
- data/lib/restorm/model.rb +75 -0
- data/lib/restorm/version.rb +3 -0
- data/lib/restorm.rb +19 -0
- data/restorm.gemspec +29 -0
- data/spec/api_spec.rb +120 -0
- data/spec/collection_spec.rb +41 -0
- data/spec/json_api/model_spec.rb +169 -0
- data/spec/middleware/accept_json_spec.rb +11 -0
- data/spec/middleware/first_level_parse_json_spec.rb +63 -0
- data/spec/middleware/json_api_parser_spec.rb +52 -0
- data/spec/middleware/second_level_parse_json_spec.rb +35 -0
- data/spec/model/associations/association_proxy_spec.rb +29 -0
- data/spec/model/associations_spec.rb +911 -0
- data/spec/model/attributes_spec.rb +354 -0
- data/spec/model/callbacks_spec.rb +176 -0
- data/spec/model/dirty_spec.rb +133 -0
- data/spec/model/http_spec.rb +201 -0
- data/spec/model/introspection_spec.rb +81 -0
- data/spec/model/nested_attributes_spec.rb +135 -0
- data/spec/model/orm_spec.rb +704 -0
- data/spec/model/parse_spec.rb +520 -0
- data/spec/model/paths_spec.rb +348 -0
- data/spec/model/relation_spec.rb +247 -0
- data/spec/model/validations_spec.rb +43 -0
- data/spec/model_spec.rb +45 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/support/macros/her_macros.rb +17 -0
- data/spec/support/macros/model_macros.rb +36 -0
- data/spec/support/macros/request_macros.rb +27 -0
- metadata +203 -0
@@ -0,0 +1,354 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require File.join(File.dirname(__FILE__), "../spec_helper.rb")
|
4
|
+
|
5
|
+
describe Restorm::Model::Attributes do
|
6
|
+
context "mapping data to Ruby objects" do
|
7
|
+
before { spawn_model "Foo::User" }
|
8
|
+
|
9
|
+
it "handles new resource" do
|
10
|
+
@new_user = Foo::User.new(fullname: "Tobias Fünke")
|
11
|
+
expect(@new_user.new?).to be_truthy
|
12
|
+
expect(@new_user.fullname).to eq("Tobias Fünke")
|
13
|
+
end
|
14
|
+
|
15
|
+
it "handles new resource with block" do
|
16
|
+
@new_user = Foo::User.new do |user|
|
17
|
+
user.fullname = "Tobias Fünke"
|
18
|
+
end
|
19
|
+
expect(@new_user.new?).to be_truthy
|
20
|
+
expect(@new_user.fullname).to eq("Tobias Fünke")
|
21
|
+
end
|
22
|
+
|
23
|
+
it "accepts new resource with strings as hash keys" do
|
24
|
+
@new_user = Foo::User.new("fullname" => "Tobias Fünke")
|
25
|
+
expect(@new_user.fullname).to eq("Tobias Fünke")
|
26
|
+
end
|
27
|
+
|
28
|
+
it "handles method missing for getter" do
|
29
|
+
@new_user = Foo::User.new(fullname: "Mayonegg")
|
30
|
+
expect { @new_user.unknown_method_for_a_user }.to raise_error(NoMethodError)
|
31
|
+
expect { @new_user.fullname }.not_to raise_error
|
32
|
+
end
|
33
|
+
|
34
|
+
it "handles method missing for setter" do
|
35
|
+
@new_user = Foo::User.new
|
36
|
+
expect { @new_user.fullname = "Tobias Fünke" }.not_to raise_error
|
37
|
+
end
|
38
|
+
|
39
|
+
it "handles method missing for query" do
|
40
|
+
@new_user = Foo::User.new
|
41
|
+
expect { @new_user.fullname? }.not_to raise_error
|
42
|
+
end
|
43
|
+
|
44
|
+
it "handles respond_to for getter" do
|
45
|
+
@new_user = Foo::User.new(fullname: "Mayonegg")
|
46
|
+
expect(@new_user).not_to respond_to(:unknown_method_for_a_user)
|
47
|
+
expect(@new_user).to respond_to(:fullname)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "handles respond_to for setter" do
|
51
|
+
@new_user = Foo::User.new
|
52
|
+
expect(@new_user).to respond_to(:fullname=)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "handles respond_to for query" do
|
56
|
+
@new_user = Foo::User.new
|
57
|
+
expect(@new_user).to respond_to(:fullname?)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "handles has_attribute? for getter" do
|
61
|
+
@new_user = Foo::User.new(fullname: "Mayonegg")
|
62
|
+
expect(@new_user).not_to have_attribute(:unknown_method_for_a_user)
|
63
|
+
expect(@new_user).to have_attribute(:fullname)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "handles get_attribute for getter" do
|
67
|
+
@new_user = Foo::User.new(fullname: "Mayonegg")
|
68
|
+
expect(@new_user.get_attribute(:unknown_method_for_a_user)).to be_nil
|
69
|
+
expect(@new_user.get_attribute(:fullname)).to eq("Mayonegg")
|
70
|
+
end
|
71
|
+
|
72
|
+
it "handles get_attribute for getter with dash" do
|
73
|
+
@new_user = Foo::User.new(:'life-span' => "3 years")
|
74
|
+
expect(@new_user.get_attribute(:unknown_method_for_a_user)).to be_nil
|
75
|
+
expect(@new_user.get_attribute(:'life-span')).to eq("3 years")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context "assigning new resource data" do
|
80
|
+
before do
|
81
|
+
spawn_model "Foo::User"
|
82
|
+
@user = Foo::User.new(active: false)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "handles data update through #assign_attributes" do
|
86
|
+
@user.assign_attributes active: true
|
87
|
+
expect(@user).to be_active
|
88
|
+
end
|
89
|
+
|
90
|
+
it "expects to receive hash" do
|
91
|
+
expect { @user.assign_attributes(1) }.to raise_error(ArgumentError, 'When assigning attributes, you must pass a hash as an argument.')
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context "checking resource equality" do
|
96
|
+
before do
|
97
|
+
Restorm::API.setup url: "https://api.example.com" do |builder|
|
98
|
+
builder.use Restorm::Middleware::FirstLevelParseJSON
|
99
|
+
builder.use Faraday::Request::UrlEncoded
|
100
|
+
builder.adapter :test do |stub|
|
101
|
+
stub.get("/users/1") { [200, {}, { id: 1, fullname: "Lindsay Fünke" }.to_json] }
|
102
|
+
stub.get("/users/2") { [200, {}, { id: 1, fullname: "Tobias Fünke" }.to_json] }
|
103
|
+
stub.get("/admins/1") { [200, {}, { id: 1, fullname: "Lindsay Fünke" }.to_json] }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
spawn_model "Foo::User"
|
108
|
+
spawn_model "Foo::Admin"
|
109
|
+
end
|
110
|
+
|
111
|
+
let(:user) { Foo::User.find(1) }
|
112
|
+
|
113
|
+
it "returns true for the exact same object" do
|
114
|
+
expect(user).to eq(user)
|
115
|
+
end
|
116
|
+
|
117
|
+
it "returns true for the same resource via find" do
|
118
|
+
expect(user).to eq(Foo::User.find(1))
|
119
|
+
end
|
120
|
+
|
121
|
+
it "returns true for the same class with identical data" do
|
122
|
+
expect(user).to eq(Foo::User.new(id: 1, fullname: "Lindsay Fünke"))
|
123
|
+
end
|
124
|
+
|
125
|
+
it "returns true for a different resource with the same data" do
|
126
|
+
expect(user).to eq(Foo::Admin.find(1))
|
127
|
+
end
|
128
|
+
|
129
|
+
it "returns false for the same class with different data" do
|
130
|
+
expect(user).not_to eq(Foo::User.new(id: 2, fullname: "Tobias Fünke"))
|
131
|
+
end
|
132
|
+
|
133
|
+
it "returns false for a non-resource with the same data" do
|
134
|
+
fake_user = double(data: { id: 1, fullname: "Lindsay Fünke" })
|
135
|
+
expect(user).not_to eq(fake_user)
|
136
|
+
end
|
137
|
+
|
138
|
+
it "delegates eql? to ==" do
|
139
|
+
other = Object.new
|
140
|
+
expect(user).to receive(:==).with(other).and_return(true)
|
141
|
+
expect(user.eql?(other)).to be_truthy
|
142
|
+
end
|
143
|
+
|
144
|
+
it "treats equal resources as equal for Array#uniq" do
|
145
|
+
user2 = Foo::User.find(1)
|
146
|
+
expect([user, user2].uniq).to eq([user])
|
147
|
+
end
|
148
|
+
|
149
|
+
it "treats equal resources as equal for hash keys" do
|
150
|
+
Foo::User.find(1)
|
151
|
+
hash = { user => true }
|
152
|
+
hash[Foo::User.find(1)] = false
|
153
|
+
expect(hash.size).to eq(1)
|
154
|
+
expect(hash).to eq(user => false)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
context "handling metadata and errors" do
|
159
|
+
before do
|
160
|
+
Restorm::API.setup url: "https://api.example.com" do |builder|
|
161
|
+
builder.use Restorm::Middleware::FirstLevelParseJSON
|
162
|
+
builder.adapter :test do |stub|
|
163
|
+
stub.post("/users") { [200, {}, { id: 1, fullname: "Tobias Fünke" }.to_json] }
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
spawn_model "Foo::User" do
|
168
|
+
store_response_errors :errors
|
169
|
+
store_metadata :my_data
|
170
|
+
end
|
171
|
+
|
172
|
+
@user = Foo::User.new(_errors: %w[Foo Bar], _metadata: { secret: true })
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should return response_errors stored in the method provided by `store_response_errors`" do
|
176
|
+
expect(@user.errors).to eq(%w[Foo Bar])
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should remove the default method for errors" do
|
180
|
+
expect { @user.response_errors }.to raise_error(NoMethodError)
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should return metadata stored in the method provided by `store_metadata`" do
|
184
|
+
expect(@user.my_data).to eq(secret: true)
|
185
|
+
end
|
186
|
+
|
187
|
+
it "should remove the default method for metadata" do
|
188
|
+
expect { @user.metadata }.to raise_error(NoMethodError)
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should work with #save" do
|
192
|
+
@user.assign_attributes(fullname: "Tobias Fünke")
|
193
|
+
@user.save
|
194
|
+
expect { @user.metadata }.to raise_error(NoMethodError)
|
195
|
+
expect(@user.my_data).to be_empty
|
196
|
+
expect(@user.errors).to be_empty
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
context "overwriting default attribute methods" do
|
201
|
+
context "for getter method" do
|
202
|
+
before do
|
203
|
+
Restorm::API.setup url: "https://api.example.com" do |builder|
|
204
|
+
builder.use Restorm::Middleware::FirstLevelParseJSON
|
205
|
+
builder.adapter :test do |stub|
|
206
|
+
stub.get("/users/1") { [200, {}, { id: 1, fullname: "Tobias Fünke", document: { url: "http://example.com" } }.to_json] }
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
spawn_model "Foo::User" do
|
211
|
+
def document
|
212
|
+
attributes[:document][:url]
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
it "bypasses Restorm's method" do
|
218
|
+
@user = Foo::User.find(1)
|
219
|
+
expect(@user.document).to eq("http://example.com")
|
220
|
+
|
221
|
+
@user = Foo::User.find(1)
|
222
|
+
expect(@user.document).to eq("http://example.com")
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
context "for setter method" do
|
227
|
+
before do
|
228
|
+
Restorm::API.setup url: "https://api.example.com" do |builder|
|
229
|
+
builder.use Restorm::Middleware::FirstLevelParseJSON
|
230
|
+
builder.adapter :test do |stub|
|
231
|
+
stub.get("/users/1") { [200, {}, { id: 1, fullname: "Tobias Fünke", document: { url: "http://example.com" } }.to_json] }
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
spawn_model "Foo::User" do
|
236
|
+
def document=(document)
|
237
|
+
@_restorm_attributes[:document] = document[:url]
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
it "bypasses Restorm's method" do
|
243
|
+
@user = Foo::User.find(1)
|
244
|
+
expect(@user.document).to eq("http://example.com")
|
245
|
+
|
246
|
+
@user = Foo::User.find(1)
|
247
|
+
expect(@user.document).to eq("http://example.com")
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
context "for predicate method" do
|
252
|
+
before do
|
253
|
+
Restorm::API.setup url: "https://api.example.com" do |builder|
|
254
|
+
builder.use Restorm::Middleware::FirstLevelParseJSON
|
255
|
+
builder.adapter :test do |stub|
|
256
|
+
stub.get("/users/1") { [200, {}, { id: 1, fullname: "Lindsay Fünke", document: { url: nil } }.to_json] }
|
257
|
+
stub.get("/users/2") { [200, {}, { id: 1, fullname: "Tobias Fünke", document: { url: "http://example.com" } }.to_json] }
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
spawn_model "Foo::User" do
|
262
|
+
def document?
|
263
|
+
document[:url].present?
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
it "byoasses Restorm's method" do
|
269
|
+
@user = Foo::User.find(1)
|
270
|
+
expect(@user.document?).to be_falsey
|
271
|
+
|
272
|
+
@user = Foo::User.find(1)
|
273
|
+
expect(@user.document?).to be_falsey
|
274
|
+
|
275
|
+
@user = Foo::User.find(2)
|
276
|
+
expect(@user.document?).to be_truthy
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
context "attributes class method" do
|
282
|
+
before do
|
283
|
+
spawn_model "Foo::User" do
|
284
|
+
attributes :fullname, :document
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
context "instance" do
|
289
|
+
subject { Foo::User.new }
|
290
|
+
|
291
|
+
it { is_expected.to respond_to(:fullname) }
|
292
|
+
it { is_expected.to respond_to(:fullname=) }
|
293
|
+
it { is_expected.to respond_to(:fullname?) }
|
294
|
+
end
|
295
|
+
|
296
|
+
it "defines setter that affects attributes" do
|
297
|
+
user = Foo::User.new
|
298
|
+
user.fullname = "Tobias Fünke"
|
299
|
+
expect(user.attributes[:fullname]).to eq("Tobias Fünke")
|
300
|
+
end
|
301
|
+
|
302
|
+
it "defines getter that reads attributes" do
|
303
|
+
user = Foo::User.new
|
304
|
+
user.assign_attributes(fullname: "Tobias Fünke")
|
305
|
+
expect(user.fullname).to eq("Tobias Fünke")
|
306
|
+
end
|
307
|
+
|
308
|
+
it "defines predicate that reads attributes" do
|
309
|
+
user = Foo::User.new
|
310
|
+
expect(user.fullname?).to be_falsey
|
311
|
+
user.assign_attributes(fullname: "Tobias Fünke")
|
312
|
+
expect(user.fullname?).to be_truthy
|
313
|
+
end
|
314
|
+
|
315
|
+
context "when attribute methods are already defined" do
|
316
|
+
before do
|
317
|
+
class AbstractUser
|
318
|
+
|
319
|
+
def fullname
|
320
|
+
raise NotImplementedError
|
321
|
+
end
|
322
|
+
|
323
|
+
def fullname=(value)
|
324
|
+
raise NotImplementedError
|
325
|
+
end
|
326
|
+
|
327
|
+
def fullname?
|
328
|
+
raise NotImplementedError
|
329
|
+
end
|
330
|
+
end
|
331
|
+
@spawned_models << :AbstractUser
|
332
|
+
|
333
|
+
spawn_model "Foo::User", super_class: AbstractUser do
|
334
|
+
attributes :fullname
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
it "overrides getter method" do
|
339
|
+
user = Foo::User.new
|
340
|
+
expect { user.fullname }.to_not raise_error(NotImplementedError)
|
341
|
+
end
|
342
|
+
|
343
|
+
it "overrides setter method" do
|
344
|
+
user = Foo::User.new
|
345
|
+
expect { user.fullname = "foo" }.to_not raise_error(NotImplementedError)
|
346
|
+
end
|
347
|
+
|
348
|
+
it "overrides predicate method" do
|
349
|
+
user = Foo::User.new
|
350
|
+
expect { user.fullname? }.to_not raise_error(NotImplementedError)
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require File.join(File.dirname(__FILE__), "../spec_helper.rb")
|
4
|
+
|
5
|
+
describe "Restorm::Model and ActiveModel::Callbacks" do
|
6
|
+
before do
|
7
|
+
Restorm::API.setup url: "https://api.example.com" do |builder|
|
8
|
+
builder.use Restorm::Middleware::FirstLevelParseJSON
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context :before_save do
|
13
|
+
subject { User.create(name: "Tobias Funke") }
|
14
|
+
before do
|
15
|
+
Restorm::API.default_api.connection.adapter :test do |stub|
|
16
|
+
stub.post("/users") { |env| [200, {}, { id: 1, name: env[:body][:name] }.to_json] }
|
17
|
+
stub.put("/users/1") { |env| [200, {}, { id: 1, name: env[:body][:name] }.to_json] }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "when using a symbol callback" do
|
22
|
+
before do
|
23
|
+
spawn_model "User" do
|
24
|
+
before_save :alter_name
|
25
|
+
def alter_name
|
26
|
+
name.upcase!
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#name" do
|
32
|
+
subject { super().name }
|
33
|
+
it { is_expected.to eq("TOBIAS FUNKE") }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when using a block callback" do
|
38
|
+
before do
|
39
|
+
spawn_model "User" do
|
40
|
+
before_save -> { name.upcase! }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "#name" do
|
45
|
+
subject { super().name }
|
46
|
+
it { is_expected.to eq("TOBIAS FUNKE") }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "when changing a value of an existing resource in a callback" do
|
51
|
+
before do
|
52
|
+
spawn_model "User" do
|
53
|
+
before_save :alter_name
|
54
|
+
def alter_name
|
55
|
+
self.name = "Lumberjack" if persisted?
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should call the server with the changed value" do
|
61
|
+
expect(subject.name).to eq("Tobias Funke")
|
62
|
+
subject.save
|
63
|
+
expect(subject.name).to eq("Lumberjack")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context :before_create do
|
69
|
+
subject { User.create(name: "Tobias Funke") }
|
70
|
+
before do
|
71
|
+
Restorm::API.default_api.connection.adapter :test do |stub|
|
72
|
+
stub.post("/users") { |env| [200, {}, { id: 1, name: env[:body][:name] }.to_json] }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "when using a symbol callback" do
|
77
|
+
before do
|
78
|
+
spawn_model "User" do
|
79
|
+
before_create :alter_name
|
80
|
+
def alter_name
|
81
|
+
name.upcase!
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "#name" do
|
87
|
+
subject { super().name }
|
88
|
+
it { is_expected.to eq("TOBIAS FUNKE") }
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "when using a block callback" do
|
93
|
+
before do
|
94
|
+
spawn_model "User" do
|
95
|
+
before_create -> { name.upcase! }
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe "#name" do
|
100
|
+
subject { super().name }
|
101
|
+
it { is_expected.to eq("TOBIAS FUNKE") }
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context :after_find do
|
107
|
+
subject { User.find(1) }
|
108
|
+
before do
|
109
|
+
Restorm::API.default_api.connection.adapter :test do |stub|
|
110
|
+
stub.get("/users/1") { [200, {}, { id: 1, name: "Tobias Funke" }.to_json] }
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context "when using a symbol callback" do
|
115
|
+
before do
|
116
|
+
spawn_model "User" do
|
117
|
+
after_find :alter_name
|
118
|
+
def alter_name
|
119
|
+
name.upcase!
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "#name" do
|
125
|
+
subject { super().name }
|
126
|
+
it { is_expected.to eq("TOBIAS FUNKE") }
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context "when using a block callback" do
|
131
|
+
before do
|
132
|
+
spawn_model "User" do
|
133
|
+
after_find -> { name.upcase! }
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe "#name" do
|
138
|
+
subject { super().name }
|
139
|
+
it { is_expected.to eq("TOBIAS FUNKE") }
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
context :after_initialize do
|
145
|
+
subject { User.new(name: "Tobias Funke") }
|
146
|
+
|
147
|
+
context "when using a symbol callback" do
|
148
|
+
before do
|
149
|
+
spawn_model "User" do
|
150
|
+
after_initialize :alter_name
|
151
|
+
def alter_name
|
152
|
+
name.upcase!
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
describe "#name" do
|
158
|
+
subject { super().name }
|
159
|
+
it { is_expected.to eq("TOBIAS FUNKE") }
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
context "when using a block callback" do
|
164
|
+
before do
|
165
|
+
spawn_model "User" do
|
166
|
+
after_initialize -> { name.upcase! }
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
describe "#name" do
|
171
|
+
subject { super().name }
|
172
|
+
it { is_expected.to eq("TOBIAS FUNKE") }
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require File.join(File.dirname(__FILE__), "../spec_helper.rb")
|
4
|
+
|
5
|
+
describe "Restorm::Model and ActiveModel::Dirty" do
|
6
|
+
context "checking dirty attributes" do
|
7
|
+
before do
|
8
|
+
Restorm::API.setup url: "https://api.example.com" do |builder|
|
9
|
+
builder.use Restorm::Middleware::FirstLevelParseJSON
|
10
|
+
builder.use Faraday::Request::UrlEncoded
|
11
|
+
builder.adapter :test do |stub|
|
12
|
+
stub.get("/users") { [200, {}, [{ id: 1, fullname: "Lindsay Fünke" }, { id: 2, fullname: "Maeby Fünke" }].to_json] }
|
13
|
+
stub.get("/users/1") { [200, {}, { id: 1, fullname: "Lindsay Fünke" }.to_json] }
|
14
|
+
stub.get("/users/2") { [200, {}, { id: 2, fullname: "Maeby Fünke" }.to_json] }
|
15
|
+
stub.get("/users/3") { [200, {}, { user_id: 3, fullname: "Maeby Fünke" }.to_json] }
|
16
|
+
stub.put("/users/1") { [200, {}, { id: 1, fullname: "Tobias Fünke" }.to_json] }
|
17
|
+
stub.put("/users/2") { [400, {}, { errors: ["Email cannot be blank"] }.to_json] }
|
18
|
+
stub.post("/users") { [200, {}, { id: 1, fullname: "Tobias Fünke" }.to_json] }
|
19
|
+
stub.get("/users/1/posts") { [200, {}, [{ id: 1, user_id: 1, body: "Hello" }].to_json] }
|
20
|
+
stub.get("/users/1/posts/1") { [200, {}, { id: 1, user_id: 1, body: "Hello" }.to_json] }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
spawn_model "Foo::Post" do
|
25
|
+
belongs_to :user
|
26
|
+
attributes :body
|
27
|
+
end
|
28
|
+
spawn_model "Foo::User" do
|
29
|
+
has_many :posts
|
30
|
+
attributes :fullname, :email
|
31
|
+
end
|
32
|
+
spawn_model "Dynamic::User" do
|
33
|
+
primary_key :user_id
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "for existing resource" do
|
38
|
+
let(:user) { Foo::User.find(1) }
|
39
|
+
it "has no changes" do
|
40
|
+
expect(user.changes).to be_empty
|
41
|
+
expect(user).not_to be_changed
|
42
|
+
end
|
43
|
+
context "with successful save" do
|
44
|
+
it "tracks dirty attributes" do
|
45
|
+
user.fullname = "Tobias Fünke"
|
46
|
+
expect(user.fullname_changed?).to be_truthy
|
47
|
+
expect(user.email_changed?).to be_falsey
|
48
|
+
expect(user).to be_changed
|
49
|
+
user.save
|
50
|
+
expect(user).not_to be_changed
|
51
|
+
end
|
52
|
+
|
53
|
+
it "tracks only changed dirty attributes" do
|
54
|
+
user.fullname = user.fullname
|
55
|
+
expect(user.fullname_changed?).to be_falsey
|
56
|
+
end
|
57
|
+
|
58
|
+
it "tracks previous changes" do
|
59
|
+
user.fullname = "Tobias Fünke"
|
60
|
+
user.save
|
61
|
+
expect(user.previous_changes).to eq("fullname" => ["Lindsay Fünke", "Tobias Fünke"])
|
62
|
+
end
|
63
|
+
|
64
|
+
it "tracks dirty attribute for mass assign for dynamic created attributes" do
|
65
|
+
user = Dynamic::User.find(3)
|
66
|
+
user.assign_attributes(fullname: "New Fullname")
|
67
|
+
expect(user.fullname_changed?).to be_truthy
|
68
|
+
expect(user).to be_changed
|
69
|
+
expect(user.changes.length).to eq(1)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "with erroneous save" do
|
74
|
+
it "tracks dirty attributes" do
|
75
|
+
user = Foo::User.find(2)
|
76
|
+
user.fullname = "Tobias Fünke"
|
77
|
+
expect(user.fullname_changed?).to be_truthy
|
78
|
+
expect(user.email_changed?).to be_falsey
|
79
|
+
expect(user).to be_changed
|
80
|
+
user.save
|
81
|
+
expect(user).to be_changed
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context "for an existing resource from an association" do
|
87
|
+
let(:post) { Foo::User.find(1).posts.find(1) }
|
88
|
+
it "has no changes" do
|
89
|
+
expect(post.changes).to be_empty
|
90
|
+
expect(post).to_not be_changed
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context "for an existing resource from an association collection" do
|
95
|
+
let(:post) { Foo::User.find(1).posts.first }
|
96
|
+
it "has no changes" do
|
97
|
+
expect(post.changes).to be_empty
|
98
|
+
expect(post).to_not be_changed
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context "for resources from a collection" do
|
103
|
+
let(:users) { Foo::User.all.fetch }
|
104
|
+
it "has no changes" do
|
105
|
+
users.each do |user|
|
106
|
+
expect(user.changes).to be_empty
|
107
|
+
expect(user).to_not be_changed
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
context "for new resource" do
|
113
|
+
let(:user) { Foo::User.new(fullname: "Lindsay Fünke") }
|
114
|
+
it "has changes" do
|
115
|
+
expect(user).to be_changed
|
116
|
+
end
|
117
|
+
it "tracks dirty attributes" do
|
118
|
+
user.fullname = "Tobias Fünke"
|
119
|
+
expect(user.fullname_changed?).to be_truthy
|
120
|
+
expect(user).to be_changed
|
121
|
+
user.save
|
122
|
+
expect(user).not_to be_changed
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context "for a new resource from an association" do
|
127
|
+
let(:post) { Foo::User.find(1).posts.build }
|
128
|
+
it "has changes" do
|
129
|
+
expect(post).to be_changed
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|