resourcerer 1.0.0 → 2.0.3

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.3'
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,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