resourcerer 0.2.2 → 2.0.4

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.
@@ -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