resourcerer 1.0.0 → 2.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +191 -180
- data/lib/resourcerer.rb +12 -3
- data/lib/resourcerer/configuration.rb +166 -0
- data/lib/resourcerer/controller.rb +49 -0
- data/lib/resourcerer/resource.rb +195 -10
- data/lib/resourcerer/version.rb +5 -0
- data/spec/features/guitars_controller_spec.rb +51 -0
- data/spec/resourcerer/controller_spec.rb +394 -0
- data/spec/resourcerer/param_key_spec.rb +48 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/support/rails_app.rb +60 -0
- metadata +99 -29
- data/lib/resourcerer/configuration/strong_parameters.rb +0 -12
- data/lib/resourcerer/inflector.rb +0 -33
- data/lib/resourcerer/resource_configuration.rb +0 -49
- data/lib/resourcerer/resourceable.rb +0 -44
- data/lib/resourcerer/strategies/assign_attributes.rb +0 -34
- data/lib/resourcerer/strategies/assign_from_method.rb +0 -23
- data/lib/resourcerer/strategies/assign_from_params.rb +0 -13
- data/lib/resourcerer/strategies/default_strategy.rb +0 -40
- data/lib/resourcerer/strategies/eager_attributes_strategy.rb +0 -10
- data/lib/resourcerer/strategies/optional_strategy.rb +0 -24
- data/lib/resourcerer/strategies/strong_parameters_strategy.rb +0 -31
- data/lib/resourcerer/strategy.rb +0 -61
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'support/rails_app'
|
3
|
+
require 'rspec/rails'
|
4
|
+
|
5
|
+
RSpec.describe GuitarsController, type: :controller do
|
6
|
+
Given(:guitar) { Guitar.new }
|
7
|
+
|
8
|
+
context 'when a build block is used' do
|
9
|
+
Given {
|
10
|
+
expect(Guitar).to receive(:all).and_return([guitar])
|
11
|
+
}
|
12
|
+
When { get :index }
|
13
|
+
Then { controller.guitars == [guitar] }
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'normal resource' do
|
17
|
+
context 'finds model by id' do
|
18
|
+
Given {
|
19
|
+
expect(Guitar).to receive(:find).with('ES-335').and_return(guitar)
|
20
|
+
}
|
21
|
+
When { get :show, request_params(id: 'ES-335') }
|
22
|
+
Then { controller.guitar == guitar }
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'finds model by guitar_id' do
|
26
|
+
Given {
|
27
|
+
expect(Guitar).to receive(:find).with('ES-335').and_return(guitar)
|
28
|
+
}
|
29
|
+
When { get :new, request_params(guitar_id: 'ES-335') }
|
30
|
+
Then { controller.guitar == guitar }
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'builds guitar if id is not provided' do
|
34
|
+
When { get :new }
|
35
|
+
Then { controller.guitar.is_a?(Guitar) }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'when build params are used' do
|
40
|
+
When { post :create, request_params(guitar: { name: 'strat' }) }
|
41
|
+
Then { controller.guitar.name == 'strat' }
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'when a guitar? with a question mark is exposed' do
|
45
|
+
Given {
|
46
|
+
expect(Guitar).to receive(:find).with('ES-335').and_return(guitar)
|
47
|
+
}
|
48
|
+
When { get :show, request_params(id: 'ES-335') }
|
49
|
+
Then { controller.guitar? == true }
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,394 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Resourcerer::Controller do
|
4
|
+
class Thing; end
|
5
|
+
class DifferentThing; end
|
6
|
+
class BaseController; end
|
7
|
+
|
8
|
+
Given(:controller_klass) {
|
9
|
+
Class.new(BaseController) do
|
10
|
+
include Resourcerer::Controller
|
11
|
+
end
|
12
|
+
}
|
13
|
+
Given(:params) { {} }
|
14
|
+
Given(:actual_params) { params.with_indifferent_access }
|
15
|
+
Given(:request) { double('Request', get?: false) }
|
16
|
+
Given(:controller) { controller_klass.new }
|
17
|
+
Given(:thing) { double('Thing') }
|
18
|
+
|
19
|
+
def controller_thing
|
20
|
+
controller.send(:thing)
|
21
|
+
end
|
22
|
+
|
23
|
+
Given {
|
24
|
+
allow(Thing).to receive(:all).and_return(Thing)
|
25
|
+
allow(DifferentThing).to receive(:all).and_return(DifferentThing)
|
26
|
+
allow(Thing).to receive(:klass).and_return(Thing)
|
27
|
+
allow(DifferentThing).to receive(:klass).and_return(DifferentThing)
|
28
|
+
allow(controller).to receive(:params).and_return(actual_params)
|
29
|
+
allow(controller).to receive(:request).and_return(request)
|
30
|
+
allow(controller).to receive(:action_name).and_return('new')
|
31
|
+
}
|
32
|
+
|
33
|
+
delegate :resource, :resourcerer_config, to: :controller_klass
|
34
|
+
|
35
|
+
context 'getter/setter methods' do
|
36
|
+
Given { resource :thing }
|
37
|
+
Then { controller.respond_to?(:thing, true) }
|
38
|
+
And { controller.respond_to?(:thing=, true) }
|
39
|
+
And { controller.method(:thing=).parameters.size == 1 }
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'memoization' do
|
43
|
+
Given { resource :thing, build: -> { SecureRandom.hex(32) } }
|
44
|
+
Then { controller_thing == controller_thing }
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'resourcerer_config' do
|
48
|
+
context 'subclass configration does not propagate to superclass' do
|
49
|
+
Given(:config) { controller_klass.resourcerer_configuration }
|
50
|
+
Given(:subklass) { Class.new(controller_klass) }
|
51
|
+
Given(:subklass_config) { subklass.resourcerer_configuration }
|
52
|
+
Given {
|
53
|
+
controller_klass.resourcerer_config :foo, attrs: :bar
|
54
|
+
subklass.resourcerer_config :foo, attrs: :lol
|
55
|
+
subklass.resourcerer_config :fizz, attrs: :buzz
|
56
|
+
}
|
57
|
+
Then { subklass_config != config }
|
58
|
+
And { subklass_config[:foo].is_a?(Resourcerer::Configuration) }
|
59
|
+
And { subklass_config[:fizz].is_a?(Resourcerer::Configuration) }
|
60
|
+
And { config[:foo].is_a?(Resourcerer::Configuration) }
|
61
|
+
And { config[:fizz].nil? }
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'applying' do
|
65
|
+
Given(:params) {{ check_this_out: 'foo', whee: 'wut' }}
|
66
|
+
Given {
|
67
|
+
resourcerer_config :sluggable, find_by: :slug
|
68
|
+
resourcerer_config :weird_id_name, id: :check_this_out
|
69
|
+
resourcerer_config :another_id_name, id: :whee
|
70
|
+
resourcerer_config :multi, find_by: :slug, id: :check_this_out
|
71
|
+
}
|
72
|
+
|
73
|
+
after { expect(controller_thing).to eq(thing) }
|
74
|
+
|
75
|
+
context 'can be reused later' do
|
76
|
+
Given { resource :thing, using: :weird_id_name }
|
77
|
+
Then { expect(Thing).to receive(:find).with('foo').and_return(thing) }
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'can apply multple configs at once' do
|
81
|
+
Given { resource :thing, using: [:weird_id_name, :sluggable] }
|
82
|
+
Then { expect(Thing).to receive(:find_by!).with(slug: 'foo').and_return(thing) }
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'applies multiple configs in a correct order' do
|
86
|
+
Given { resource :thing, using: [:another_id_name, :weird_id_name] }
|
87
|
+
Then { expect(Thing).to receive(:find).with('wut').and_return(thing) }
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'can apply multiple options in a config' do
|
91
|
+
Given { resource :thing, using: :multi }
|
92
|
+
Then { expect(Thing).to receive(:find_by!).with(slug: 'foo').and_return(thing) }
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'applies multiple configs with multiple options in a correct order' do
|
96
|
+
Given { resource :thing, using: [:another_id_name, :multi] }
|
97
|
+
Then { expect(Thing).to receive(:find_by!).with(slug: 'wut').and_return(thing) }
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'default behaviour' do
|
103
|
+
context "setting value directly" do
|
104
|
+
Given {
|
105
|
+
expect(Thing).not_to receive(:new)
|
106
|
+
resource :thing
|
107
|
+
}
|
108
|
+
When {
|
109
|
+
controller.instance_eval do
|
110
|
+
self.thing = :foobar
|
111
|
+
end
|
112
|
+
}
|
113
|
+
Then { controller_thing == :foobar }
|
114
|
+
end
|
115
|
+
|
116
|
+
context 'assign' do
|
117
|
+
Given(:attrs) {{ lol: :wut }}
|
118
|
+
Given {
|
119
|
+
allow(controller).to receive(:thing_params).and_return(attrs)
|
120
|
+
expect(Thing).to receive(:new).with(attrs).and_return(thing)
|
121
|
+
}
|
122
|
+
after { expect(controller_thing).to eq(thing) }
|
123
|
+
|
124
|
+
context 'does not assign on non-update action' do
|
125
|
+
Given {
|
126
|
+
expect(controller).to receive(:action_name).and_return('index')
|
127
|
+
}
|
128
|
+
When { resource :thing }
|
129
|
+
Then { expect(thing).not_to receive(:assign_attributes) }
|
130
|
+
end
|
131
|
+
|
132
|
+
context 'does not assign on empty object' do
|
133
|
+
Given(:thing) { nil }
|
134
|
+
When { resource :thing }
|
135
|
+
Then { }
|
136
|
+
end
|
137
|
+
|
138
|
+
context 'assigns on update' do
|
139
|
+
Given {
|
140
|
+
expect(controller).to receive(:action_name).and_return('update')
|
141
|
+
}
|
142
|
+
When { resource :thing }
|
143
|
+
Then { expect(thing).to receive(:assign_attributes).with(attrs) }
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
context 'build' do
|
148
|
+
after { expect(controller_thing).to eq(thing) }
|
149
|
+
|
150
|
+
context 'params method is not available' do
|
151
|
+
context 'builds a new instance with empty hash' do
|
152
|
+
Given { resource :thing }
|
153
|
+
Then { expect(Thing).to receive(:new).with({}).and_return(thing) }
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
context 'params method is available' do
|
158
|
+
context 'ignores params on get request' do
|
159
|
+
Given { resource :thing }
|
160
|
+
Then {
|
161
|
+
expect(request).to receive(:get?).and_return(true)
|
162
|
+
expect(controller).not_to receive(:thing_params)
|
163
|
+
expect(Thing).to receive(:new).with({}).and_return(thing)
|
164
|
+
}
|
165
|
+
end
|
166
|
+
|
167
|
+
context 'uses params method on non-get request' do
|
168
|
+
Given { resource :thing }
|
169
|
+
Then {
|
170
|
+
expect(Thing).to receive(:new).with(foo: :bar).and_return(thing)
|
171
|
+
expect(controller).to receive(:thing_params).and_return(foo: :bar)
|
172
|
+
}
|
173
|
+
end
|
174
|
+
|
175
|
+
context 'can use custom params method name' do
|
176
|
+
Given { resource :thing, attrs: :custom_params_method_name }
|
177
|
+
Then {
|
178
|
+
expect(Thing).to receive(:new).with(foo: :bar).and_return(thing)
|
179
|
+
expect(controller).to receive(:custom_params_method_name).and_return(foo: :bar)
|
180
|
+
}
|
181
|
+
end
|
182
|
+
|
183
|
+
context 'can use custom build params' do
|
184
|
+
Given { resource :thing, attrs: ->{ foobar } }
|
185
|
+
Then {
|
186
|
+
expect(controller).to receive(:foobar).and_return(42)
|
187
|
+
expect(Thing).to receive(:new).with(42).and_return(thing)
|
188
|
+
}
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
context 'find' do
|
194
|
+
Given do
|
195
|
+
resource :thing, model: :different_thing
|
196
|
+
expect(DifferentThing).to receive(:find).with(10).and_return(thing)
|
197
|
+
end
|
198
|
+
|
199
|
+
context 'checks params[:thing_id] first' do
|
200
|
+
Given(:params) {{ thing_id: 10, different_thing_id: 11, id: 12 }}
|
201
|
+
Then { controller_thing == thing }
|
202
|
+
end
|
203
|
+
|
204
|
+
context 'checks params[:different_thing_id] second' do
|
205
|
+
Given(:params) {{ 'different_thing_id' => 10, id: 11 }}
|
206
|
+
Then { controller_thing == thing }
|
207
|
+
end
|
208
|
+
|
209
|
+
context 'checks params[:id] in the end' do
|
210
|
+
Given(:params) {{ id: 10 }}
|
211
|
+
Then { controller_thing == thing }
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
context 'assign?' do
|
217
|
+
Given(:attrs) {{ lol: :wut }}
|
218
|
+
Given {
|
219
|
+
allow(controller).to receive(:thing_params).and_return(attrs)
|
220
|
+
expect(Thing).to receive(:new).with(attrs).and_return(thing)
|
221
|
+
allow(controller).to receive(:action_name).and_return('index')
|
222
|
+
}
|
223
|
+
|
224
|
+
after { controller_thing == thing }
|
225
|
+
|
226
|
+
context 'assign? is false' do
|
227
|
+
When { resource :thing, assign?: false }
|
228
|
+
Then { expect(thing).not_to receive(:assign_attributes) }
|
229
|
+
end
|
230
|
+
|
231
|
+
context 'assign? is true' do
|
232
|
+
When { resource(:thing) { assign? true } }
|
233
|
+
Then { expect(thing).to receive(:assign_attributes).with(attrs) }
|
234
|
+
end
|
235
|
+
|
236
|
+
context 'passing a single action' do
|
237
|
+
context 'when it does not match the current action' do
|
238
|
+
When { resource(:thing) { assign? :edit } }
|
239
|
+
Then { expect(thing).not_to receive(:assign_attributes).with(attrs) }
|
240
|
+
end
|
241
|
+
|
242
|
+
context 'when it matches the current action' do
|
243
|
+
When { resource(:thing) { assign? :index } }
|
244
|
+
Then { expect(thing).to receive(:assign_attributes).with(attrs) }
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
context 'passing several actions' do
|
249
|
+
context 'when none matches the current action' do
|
250
|
+
When { resource :thing, assign?: [:update, :edit] }
|
251
|
+
Then { expect(thing).not_to receive(:assign_attributes).with(attrs) }
|
252
|
+
end
|
253
|
+
|
254
|
+
context 'when one matches the current action' do
|
255
|
+
When { resource :thing, assign?: [:update, :index, :edit] }
|
256
|
+
Then { expect(thing).to receive(:assign_attributes).with(attrs) }
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
context 'find_by' do
|
262
|
+
it 'throws and error when using with :find' do
|
263
|
+
action = ->{ resource :thing, find: -> { }, find_by: :bar }
|
264
|
+
expect(&action).to raise_error(ArgumentError, 'Using :find_by option with :find does not make sense')
|
265
|
+
end
|
266
|
+
|
267
|
+
context 'allows to specify what attribute to use for find' do
|
268
|
+
Given { expect(Thing).to receive(:find_by!).with(foo: 10).and_return(42) }
|
269
|
+
When {
|
270
|
+
resource :thing, find_by: :foo
|
271
|
+
controller.params.merge! id: 10
|
272
|
+
}
|
273
|
+
Then { expect(controller_thing).to eq(42) }
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
context 'collection' do
|
278
|
+
Given(:collection) { double('Collection', klass: Thing) }
|
279
|
+
Given {
|
280
|
+
allow(collection).to receive(:klass).and_return(Thing)
|
281
|
+
}
|
282
|
+
|
283
|
+
context 'allows overriding collection using block' do
|
284
|
+
Given { expect(collection).to receive(:new).and_return(42) }
|
285
|
+
When {
|
286
|
+
scope = self.collection
|
287
|
+
resource(:thing) { collection { scope } }
|
288
|
+
}
|
289
|
+
Then { controller_thing == 42 }
|
290
|
+
end
|
291
|
+
|
292
|
+
context 'build/find' do
|
293
|
+
Given(:current_user) { double('User') }
|
294
|
+
Given {
|
295
|
+
expect(controller).to receive(:current_user).and_return(current_user)
|
296
|
+
expect(current_user).to receive(:things).and_return(collection)
|
297
|
+
resource :thing, collection: -> { current_user.things }
|
298
|
+
}
|
299
|
+
|
300
|
+
context 'sets the collection to belong to collection defined by controller method' do
|
301
|
+
When { expect(collection).to receive(:new).with({}).and_return(42) }
|
302
|
+
Then { controller_thing == 42 }
|
303
|
+
end
|
304
|
+
|
305
|
+
context 'collections the find to proper collection' do
|
306
|
+
Given(:params) {{ thing_id: 10 }}
|
307
|
+
When { expect(collection).to receive(:find).with(10).and_return(42) }
|
308
|
+
Then { controller_thing == 42 }
|
309
|
+
Then { controller.resource(:thing, collection: -> { current_user.things }) == 42 }
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
context 'model' do
|
315
|
+
Given(:different_thing) { double('DifferentThing') }
|
316
|
+
Given { expect(DifferentThing).to receive(:new).with({}).and_return(different_thing) }
|
317
|
+
|
318
|
+
context 'allows overriding model class with proc' do
|
319
|
+
When { resource(:thing) { model { DifferentThing } } }
|
320
|
+
Then { controller_thing == different_thing }
|
321
|
+
end
|
322
|
+
|
323
|
+
context 'allows overriding model with class' do
|
324
|
+
When { resource :thing, model: DifferentThing }
|
325
|
+
Then { controller_thing == different_thing }
|
326
|
+
end
|
327
|
+
|
328
|
+
context 'allows overriding model class with symbol' do
|
329
|
+
When { resource :thing, model: :different_thing }
|
330
|
+
Then { controller_thing == different_thing }
|
331
|
+
end
|
332
|
+
|
333
|
+
context 'allows overriding model class with string' do
|
334
|
+
When { resource :thing, model: 'DifferentThing' }
|
335
|
+
Then { controller_thing == different_thing }
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
context 'id' do
|
340
|
+
Given {
|
341
|
+
expect(Thing).to receive(:find).with(42).and_return(thing)
|
342
|
+
}
|
343
|
+
|
344
|
+
context 'allows overriding id with proc' do
|
345
|
+
Given { expect(controller).to receive(:get_thing_id_somehow).and_return(42) }
|
346
|
+
When { resource(:thing) { id { get_thing_id_somehow } } }
|
347
|
+
Then { controller_thing == thing }
|
348
|
+
end
|
349
|
+
|
350
|
+
context 'allows overriding id with symbol' do
|
351
|
+
Given(:params) {{ thing_id: 10, custom_thing_id: 42 }}
|
352
|
+
When { resource :thing, id: :custom_thing_id }
|
353
|
+
Then { controller_thing == thing }
|
354
|
+
end
|
355
|
+
|
356
|
+
context 'allows overriding id with an array of symbols' do
|
357
|
+
Given { controller.params.merge! another_id_param: 42 }
|
358
|
+
When { resource :thing, id: %w[non-existent-id lolwut another_id_param] }
|
359
|
+
Then { controller_thing == thing }
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
context 'permit' do
|
364
|
+
Given(:actual_params) { double('Params', :[] => nil) }
|
365
|
+
Given(:attrs) {{ name: 'Max', email: 'max@email.com' }}
|
366
|
+
Given(:fields) { [:name, :email] }
|
367
|
+
|
368
|
+
it 'throws and error when using with :attrs' do
|
369
|
+
action = ->{ resource :thing, attrs: -> { }, permit: :bar }
|
370
|
+
expect(&action).to raise_error(ArgumentError, 'Using :permit option with :attrs does not make sense')
|
371
|
+
end
|
372
|
+
|
373
|
+
context 'allows to specify permitted attributes' do
|
374
|
+
Given {
|
375
|
+
expect(actual_params).to receive(:require).with(:thing).and_return(actual_params)
|
376
|
+
expect(actual_params).to receive(:permit).with(*fields).and_return(attrs)
|
377
|
+
expect(Thing).to receive(:new).with(attrs).and_return(thing)
|
378
|
+
}
|
379
|
+
|
380
|
+
context 'permit using a proc' do
|
381
|
+
When { resource :thing, permit: fields }
|
382
|
+
Then { controller_thing == thing }
|
383
|
+
end
|
384
|
+
|
385
|
+
context 'permit passing fields directly' do
|
386
|
+
When {
|
387
|
+
permitted_attributes = fields
|
388
|
+
resource(:thing) { permit permitted_attributes }
|
389
|
+
}
|
390
|
+
Then { controller_thing == thing }
|
391
|
+
end
|
392
|
+
end
|
393
|
+
end
|
394
|
+
end
|