resourcerer 0.2.2 → 2.0.4

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