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