snusnu-merb_resource_controller 0.1.0 → 0.2.0

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.
data/README.textile CHANGED
@@ -200,84 +200,222 @@ how the controllers behave. Of course you are also free to override all the meth
200
200
  <pre>
201
201
  <code>
202
202
  def index
203
+ set_action_specific_provides(:index)
203
204
  load_resource
204
205
  display requested_resource
205
206
  end
206
207
 
207
208
  def show
209
+ set_action_specific_provides(:show)
208
210
  load_resource
209
211
  raise Merb::ControllerExceptions::NotFound unless requested_resource
210
212
  display requested_resource
211
213
  end
212
214
 
213
215
  def new
214
- only_provides :html
216
+ set_action_specific_provides(:new)
215
217
  load_resource
216
218
  set_member(new_member)
217
219
  display member
218
220
  end
219
221
 
220
222
  def edit
221
- only_provides :html
223
+ set_action_specific_provides(:edit)
222
224
  load_resource
223
225
  raise Merb::ControllerExceptions::NotFound unless requested_resource
224
226
  display requested_resource
225
227
  end
226
228
 
227
229
  def create
230
+ set_action_specific_provides(:create)
228
231
  load_resource
229
- set_member(new_member(params[member_name]))
232
+ set_member(new_member)
230
233
  if member.save
231
- options = flash_supported? ? { :message => successful_create_messages } : {}
232
- redirect redirect_on_successful_create, options
234
+ handle_successful_create
233
235
  else
234
- message.merge!(failed_create_messages) if flash_supported?
235
- render :new
236
+ handle_failed_create
236
237
  end
237
238
  end
238
239
 
239
240
  def update
241
+ set_action_specific_provides(:update)
240
242
  load_resource
241
243
  raise Merb::ControllerExceptions::NotFound unless requested_resource
242
244
  if requested_resource.update_attributes(params[member_name])
243
- options = flash_supported? ? { :message => successful_update_messages } : {}
244
- redirect redirect_on_successful_update, options
245
+ handle_successful_update
245
246
  else
246
- message.merge!(failed_update_messages) if flash_supported?
247
- display requested_resource, :edit
247
+ handle_failed_update
248
248
  end
249
249
  end
250
250
 
251
251
  def destroy
252
+ set_action_specific_provides(:destroy)
252
253
  load_resource
253
254
  raise Merb::ControllerExceptions::NotFound unless requested_resource
254
255
  if requested_resource.destroy
255
- options = flash_supported? ? { :message => successful_destroy_messages } : {}
256
- redirect redirect_on_successful_destroy, options
256
+ handle_successful_destroy
257
257
  else
258
- raise Merb::ControllerExceptions::InternalServerError
258
+ handle_failed_destroy
259
259
  end
260
260
  end
261
261
  </code>
262
262
  </pre>
263
263
 
264
- h2. Additional Helper Methods
264
+ h2. Additional Methods to override
265
+
266
+ In addition to the actions and the methods they are using, you will probably want to override some other methods that
267
+ @merb_resource_controller@ uses to do its thing. Here are some default method implementations you can override to this effect:
265
268
 
266
- In addition to the actions and the methods they are using, you will probably want to override the redirection targets
267
- These are the default method implementations you can override to this effect:
269
+ h3. Customize the create action
268
270
 
269
271
  <pre>
270
272
  <code>
273
+ def handle_successful_create
274
+ handle_content_type(:create, content_type, :success)
275
+ end
276
+
277
+ def handle_failed_create
278
+ handle_content_type(:create, content_type, :failure)
279
+ end
280
+
281
+
282
+ def html_response_on_successful_create
283
+ options = flash_messages_for?(:create) ? { :message => successful_create_messages } : {}
284
+ redirect redirect_on_successful_create, options
285
+ end
286
+
287
+ def html_response_on_failed_create
288
+ message.merge!(failed_create_messages) if flash_messages_for?(:create)
289
+ render :new, :status => 406
290
+ end
291
+
292
+
293
+ def xml_response_on_successful_create
294
+ display member, :status => 201, :location => resource(member)
295
+ end
296
+
297
+ def xml_response_on_failed_create
298
+ display member.errors, :status => 422
299
+ end
300
+
301
+
302
+ def json_response_on_successful_create
303
+ display member, :status => 201, :location => resource(member)
304
+ end
305
+
306
+ def json_response_on_failed_create
307
+ display member.errors, :status => 422
308
+ end
309
+
310
+
271
311
  def redirect_on_successful_create
272
312
  target = singleton_controller? ? member_name : member
273
313
  resource(*(has_parent? ? parents + [ target ] : [ target ]))
274
314
  end
275
315
 
316
+ # These are available by default (i.e. if all actions are available)
317
+ # If you specify specific actions inside the block passed to #controlling
318
+ # you need to pass the :flash option to the ResourceProxy#action like so:
319
+ # action :create, :flash => true
320
+
321
+ def successful_create_messages
322
+ { :notice => "#{member.class.name} was successfully created" }
323
+ end
324
+
325
+ def failed_create_messages
326
+ { :error => "Failed to create new #{member.class.name}" }
327
+ end
328
+ </code>
329
+ </pre>
330
+
331
+ h3. Customize the update action
332
+
333
+ <code>
334
+ <pre>
335
+ def handle_successful_update
336
+ handle_content_type(:update, content_type, :success)
337
+ end
338
+
339
+ def handle_failed_update
340
+ handle_content_type(:update, content_type, :failure)
341
+ end
342
+
343
+
344
+ def html_response_on_successful_update
345
+ options = flash_messages_for?(:update) ? { :message => successful_update_messages } : {}
346
+ redirect redirect_on_successful_update, options
347
+ end
348
+
349
+ def html_response_on_failed_update
350
+ message.merge!(failed_update_messages) if flash_messages_for?(:update)
351
+ display requested_resource, :edit, :status => 406
352
+ end
353
+
354
+
355
+ def xml_response_on_successful_update
356
+ "" # render no content, just 200 (OK) status.
357
+ end
358
+
359
+ def xml_response_on_failed_update
360
+ display member.errors, :status => 422
361
+ end
362
+
363
+
364
+ def json_response_on_successful_update
365
+ "" # render no content, just 200 (OK) status.
366
+ end
367
+
368
+ def json_response_on_failed_update
369
+ display member.errors, :status => 422
370
+ end
371
+
276
372
  def redirect_on_successful_update
277
373
  target = singleton_controller? ? member_name : member
278
374
  resource(*(has_parent? ? parents + [ target ] : [ target ]))
279
375
  end
280
376
 
377
+ # These are available by default (i.e. if all actions are available)
378
+ # If you specify specific actions inside the block passed to #controlling
379
+ # you need to pass the :flash option to the ResourceProxy#action like so:
380
+ # action :update, :flash => true
381
+
382
+ def successful_update_messages
383
+ { :notice => "#{member.class.name} was successfully updated" }
384
+ end
385
+
386
+ def failed_update_messages
387
+ { :error => "Failed to update #{member.class.name}" }
388
+ end
389
+ </code>
390
+ </pre>
391
+
392
+ h3. Customize the destroy action
393
+
394
+ <code>
395
+ <pre>
396
+ def handle_successful_destroy
397
+ handle_content_type(:destroy, content_type, :success)
398
+ end
399
+
400
+ def handle_failed_destroy
401
+ raise Merb::ControllerExceptions::InternalServerError
402
+ end
403
+
404
+
405
+ def html_response_on_successful_destroy
406
+ options = flash_messages_for?(:destroy) ? { :message => successful_destroy_messages } : {}
407
+ redirect redirect_on_successful_destroy, options
408
+ end
409
+
410
+ def xml_response_on_successful_destroy
411
+ "" # render no content, just 200 (OK) status.
412
+ end
413
+
414
+ def json_response_on_successful_destroy
415
+ "" # render no content, just 200 (OK) status.
416
+ end
417
+
418
+
281
419
  def redirect_on_successful_destroy
282
420
  if singleton_controller?
283
421
  has_parent? ? resource(parent) : '/'
@@ -285,6 +423,19 @@ def redirect_on_successful_destroy
285
423
  resource(*(has_parent? ? parents + [ collection_name ] : [ collection_name ]))
286
424
  end
287
425
  end
426
+
427
+ # These are available by default (i.e. if all actions are available)
428
+ # If you specify specific actions inside the block passed to #controlling
429
+ # you need to pass the :flash option to the ResourceProxy#action like so:
430
+ # action :destroy, :flash => true
431
+
432
+ def successful_destroy_messages
433
+ { :notice => "#{member.class.name} was successfully destroyed" }
434
+ end
435
+
436
+ def failed_destroy_messages
437
+ { :error => "Failed to destroy #{member.class.name}" }
438
+ end
288
439
  </code>
289
440
  </pre>
290
441
 
@@ -301,6 +452,5 @@ behaves under the given circumstances.
301
452
  h2. TODO
302
453
 
303
454
  # Infer route nesting strategy from @Merb::Router@
304
- # Customizable support for @provides@ and @only_provides@
305
455
  # Support for user stamps (aka created_by and updated_by)
306
456
  # Support for pagination once an _official_ merb pagination solution exists
data/Rakefile CHANGED
@@ -6,7 +6,7 @@ require 'merb-core/tasks/merb'
6
6
  require "spec/rake/spectask"
7
7
 
8
8
  GEM_NAME = "merb_resource_controller"
9
- GEM_VERSION = "0.1.0"
9
+ GEM_VERSION = "0.2.0"
10
10
  AUTHOR = "Martin Gamsjaeger"
11
11
  EMAIL = "gamsnjaga@gmail.com"
12
12
  HOMEPAGE = "http://merbivore.com/"
data/TODO CHANGED
@@ -2,6 +2,5 @@ TODO
2
2
  ====
3
3
 
4
4
  # Infer route nesting strategy from @Merb::Router@
5
- # Customizable support for @provides@ and @only_provides@
6
5
  # Support for user stamps (aka created_by and updated_by)
7
6
  # Support for pagination once an _official_ merb pagination solution exists
@@ -11,9 +11,10 @@ if defined?(Merb::Plugins)
11
11
  Merb::BootLoader.before_app_loads do
12
12
  # require code that must be loaded before the application
13
13
  mrc = File.join(File.dirname(__FILE__), 'merb_resource_controller')
14
- require mrc / 'resource_proxy'
15
14
  require mrc / 'actions'
15
+ require mrc / 'action_descriptor'
16
16
  require mrc / 'resource_controller'
17
+ require mrc / 'resource_proxy'
17
18
  if Merb::Plugins.config[:merb_resource_controller][:identity_map]
18
19
  require mrc / 'identity_map_support'
19
20
  end
@@ -0,0 +1,107 @@
1
+ module Merb
2
+ module ResourceController
3
+
4
+
5
+ FLASH_SUPPORT_MODULE = "FlashSupport"
6
+
7
+ def self.action_module(action)
8
+ Actions.const_get(Extlib::Inflection.classify(action))
9
+ end
10
+
11
+
12
+ class ActionDescriptor
13
+
14
+ SUPPORTED_SCENARIOS = [ :success, :failure ]
15
+ FORMAT_RESTRICTION_APIS = [ :provides, :only_provides, :does_not_provide ]
16
+
17
+ attr_reader :action_name, :provided_formats, :options
18
+
19
+ def initialize(name, provided_formats, options = {})
20
+ raise unless valid_format_restriction?(options)
21
+ @action_name, @provided_formats, @options = name.to_sym, provided_formats, options
22
+ @content_type_handlers = { :success => {}, :failure => {} }
23
+ handle_default_content_types if options[:default_formats]
24
+ end
25
+
26
+
27
+ def action_module
28
+ Merb::ResourceController.action_module(@action_name)
29
+ end
30
+
31
+
32
+ def supports_flash_messages?
33
+ !!@options[:flash] && has_flash_module?
34
+ end
35
+
36
+ def has_flash_module?
37
+ !flash_module.nil?
38
+ end
39
+
40
+ def flash_module
41
+ action_module.const_get Merb::ResourceController::FLASH_SUPPORT_MODULE
42
+ rescue
43
+ nil
44
+ end
45
+
46
+
47
+ def handle_default_content_types
48
+ handle
49
+ end
50
+
51
+ def handle(format = nil, scenario = nil)
52
+ raise "#{scenario} is not supported" unless SUPPORTED_SCENARIOS.include?(scenario) || scenario.nil?
53
+ (format ? format.is_a?(Array) ? format : [ format ] : @provided_formats).each do |f|
54
+ (scenario ? [ scenario ] : SUPPORTED_SCENARIOS).each do |s|
55
+ @content_type_handlers[s][f] = content_type_handler_method(f, s)
56
+ end
57
+ end
58
+ end
59
+
60
+ def content_type_handler(format, scenario)
61
+ @content_type_handlers[scenario.to_sym][format.to_sym]
62
+ end
63
+
64
+ def content_type_handler_method(format, scenario)
65
+ case scenario
66
+ when :success then "#{format}_response_on_successful_#{@action_name}"
67
+ when :failure then "#{format}_response_on_failed_#{@action_name}"
68
+ else
69
+ raise "default_content_type_handler doesn't support #{scenario.inspect} (only :on_success and :on_failure)"
70
+ end
71
+ end
72
+
73
+
74
+ def valid_format_restriction?(options = nil)
75
+ format_restriction(options || @options).size <= 1 # empty is valid too
76
+ end
77
+
78
+ def has_format_restriction?(options = nil)
79
+ format_restriction(options).size > 0
80
+ end
81
+
82
+ def format_restrictor_method(options = nil)
83
+ o = options || @options
84
+ lambda { send(format_restriction_api(o), restricted_formats(o)) }
85
+ end
86
+
87
+
88
+ def format_restriction_api(options = nil)
89
+ format_restriction(options || @options).map { |kv| kv[0] }.first
90
+ end
91
+
92
+ def restricted_formats(options = nil)
93
+ format_restriction(options || @options).map { |kv| kv[1] }.flatten
94
+ end
95
+
96
+ def format_restriction(options = nil)
97
+ (options || @options).select { |k,v| format_restriction_apis.include?(k) }
98
+ end
99
+
100
+ def format_restriction_apis
101
+ FORMAT_RESTRICTION_APIS
102
+ end
103
+
104
+ end
105
+
106
+ end
107
+ end
@@ -11,6 +11,7 @@ module Merb
11
11
  # end
12
12
 
13
13
  def index
14
+ set_action_specific_provides(:index)
14
15
  load_resource
15
16
  display requested_resource
16
17
  end
@@ -26,6 +27,7 @@ module Merb
26
27
  # end
27
28
 
28
29
  def show
30
+ set_action_specific_provides(:show)
29
31
  load_resource
30
32
  raise Merb::ControllerExceptions::NotFound unless requested_resource
31
33
  display requested_resource
@@ -42,7 +44,7 @@ module Merb
42
44
  # end
43
45
 
44
46
  def new
45
- only_provides :html
47
+ set_action_specific_provides(:new)
46
48
  load_resource
47
49
  set_member(new_member)
48
50
  display member
@@ -60,7 +62,7 @@ module Merb
60
62
  # end
61
63
 
62
64
  def edit
63
- only_provides :html
65
+ set_action_specific_provides(:edit)
64
66
  load_resource
65
67
  raise Merb::ControllerExceptions::NotFound unless requested_resource
66
68
  display requested_resource
@@ -81,22 +83,75 @@ module Merb
81
83
  # end
82
84
 
83
85
  def create
86
+ set_action_specific_provides(:create)
84
87
  load_resource
85
88
  set_member(new_member)
86
89
  if member.save
87
- options = flash_supported? ? { :message => successful_create_messages } : {}
88
- redirect redirect_on_successful_create, options
90
+ handle_successful_create
89
91
  else
90
- message.merge!(failed_create_messages) if flash_supported?
91
- render :new, :status => 406
92
+ handle_failed_create
92
93
  end
93
94
  end
94
95
 
96
+ protected
97
+
98
+ def handle_successful_create
99
+ handle_content_type(:create, content_type, :success)
100
+ end
101
+
102
+ def handle_failed_create
103
+ handle_content_type(:create, content_type, :failure)
104
+ end
105
+
106
+
107
+ def html_response_on_successful_create
108
+ options = flash_messages_for?(:create) ? { :message => successful_create_messages } : {}
109
+ redirect redirect_on_successful_create, options
110
+ end
111
+
112
+ def html_response_on_failed_create
113
+ message.merge!(failed_create_messages) if flash_messages_for?(:create)
114
+ render :new, :status => 406
115
+ end
116
+
117
+
118
+ def xml_response_on_successful_create
119
+ display member, :status => 201, :location => resource(member)
120
+ end
121
+
122
+ def xml_response_on_failed_create
123
+ display member.errors, :status => 422
124
+ end
125
+
126
+
127
+ def json_response_on_successful_create
128
+ display member, :status => 201, :location => resource(member)
129
+ end
130
+
131
+ def json_response_on_failed_create
132
+ display member.errors, :status => 422
133
+ end
134
+
135
+
95
136
  def redirect_on_successful_create
96
137
  target = singleton_controller? ? member_name : member
97
138
  resource(*(has_parent? ? parents + [ target ] : [ target ]))
98
139
  end
99
140
 
141
+ module FlashSupport
142
+
143
+ protected
144
+
145
+ def successful_create_messages
146
+ { :notice => "#{member.class.name} was successfully created" }
147
+ end
148
+
149
+ def failed_create_messages
150
+ { :error => "Failed to create new #{member.class.name}" }
151
+ end
152
+
153
+ end
154
+
100
155
  end
101
156
 
102
157
  module Update
@@ -112,22 +167,74 @@ module Merb
112
167
  # end
113
168
 
114
169
  def update
170
+ set_action_specific_provides(:update)
115
171
  load_resource
116
172
  raise Merb::ControllerExceptions::NotFound unless requested_resource
117
173
  if requested_resource.update_attributes(params[member_name])
118
- options = flash_supported? ? { :message => successful_update_messages } : {}
119
- redirect redirect_on_successful_update, options
174
+ handle_successful_update
120
175
  else
121
- message.merge!(failed_update_messages) if flash_supported?
122
- display requested_resource, :edit, :status => 406
176
+ handle_failed_update
123
177
  end
124
178
  end
125
179
 
180
+ protected
181
+
182
+ def handle_successful_update
183
+ handle_content_type(:update, content_type, :success)
184
+ end
185
+
186
+ def handle_failed_update
187
+ handle_content_type(:update, content_type, :failure)
188
+ end
189
+
190
+
191
+ def html_response_on_successful_update
192
+ options = flash_messages_for?(:update) ? { :message => successful_update_messages } : {}
193
+ redirect redirect_on_successful_update, options
194
+ end
195
+
196
+ def html_response_on_failed_update
197
+ message.merge!(failed_update_messages) if flash_messages_for?(:update)
198
+ display requested_resource, :edit, :status => 406
199
+ end
200
+
201
+
202
+ def xml_response_on_successful_update
203
+ "" # render no content, just 200 (OK) status.
204
+ end
205
+
206
+ def xml_response_on_failed_update
207
+ display member.errors, :status => 422
208
+ end
209
+
210
+
211
+ def json_response_on_successful_update
212
+ "" # render no content, just 200 (OK) status.
213
+ end
214
+
215
+ def json_response_on_failed_update
216
+ display member.errors, :status => 422
217
+ end
218
+
126
219
  def redirect_on_successful_update
127
220
  target = singleton_controller? ? member_name : member
128
221
  resource(*(has_parent? ? parents + [ target ] : [ target ]))
129
222
  end
130
223
 
224
+ module FlashSupport
225
+
226
+ protected
227
+
228
+ def successful_update_messages
229
+ { :notice => "#{member.class.name} was successfully updated" }
230
+ end
231
+
232
+ def failed_update_messages
233
+ { :error => "Failed to update #{member.class.name}" }
234
+ end
235
+
236
+ end
237
+
131
238
  end
132
239
 
133
240
  module Destroy
@@ -143,16 +250,41 @@ module Merb
143
250
  # end
144
251
 
145
252
  def destroy
253
+ set_action_specific_provides(:destroy)
146
254
  load_resource
147
255
  raise Merb::ControllerExceptions::NotFound unless requested_resource
148
256
  if requested_resource.destroy
149
- options = flash_supported? ? { :message => successful_destroy_messages } : {}
150
- redirect redirect_on_successful_destroy, options
257
+ handle_successful_destroy
151
258
  else
152
- raise Merb::ControllerExceptions::InternalServerError
259
+ handle_failed_destroy
153
260
  end
154
261
  end
155
262
 
263
+ protected
264
+
265
+ def handle_successful_destroy
266
+ handle_content_type(:destroy, content_type, :success)
267
+ end
268
+
269
+ def handle_failed_destroy
270
+ raise Merb::ControllerExceptions::InternalServerError
271
+ end
272
+
273
+
274
+ def html_response_on_successful_destroy
275
+ options = flash_messages_for?(:destroy) ? { :message => successful_destroy_messages } : {}
276
+ redirect redirect_on_successful_destroy, options
277
+ end
278
+
279
+ def xml_response_on_successful_destroy
280
+ "" # render no content, just 200 (OK) status.
281
+ end
282
+
283
+ def json_response_on_successful_destroy
284
+ "" # render no content, just 200 (OK) status.
285
+ end
286
+
287
+
156
288
  def redirect_on_successful_destroy
157
289
  if singleton_controller?
158
290
  has_parent? ? resource(parent) : '/'
@@ -161,6 +293,20 @@ module Merb
161
293
  end
162
294
  end
163
295
 
296
+ module FlashSupport
297
+
298
+ protected
299
+
300
+ def successful_destroy_messages
301
+ { :notice => "#{member.class.name} was successfully destroyed" }
302
+ end
303
+
304
+ def failed_destroy_messages
305
+ { :error => "Failed to destroy #{member.class.name}" }
306
+ end
307
+
308
+ end
309
+
164
310
  end
165
311
 
166
312
  end