resourcerer 1.0.0 → 2.0.3

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