make_resourceful 1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/Rakefile +31 -0
  2. data/Readme.rdoc +229 -0
  3. data/VERSION +1 -0
  4. data/lib/make_resourceful.rb +11 -0
  5. data/lib/resourceful/base.rb +63 -0
  6. data/lib/resourceful/builder.rb +405 -0
  7. data/lib/resourceful/default/accessors.rb +418 -0
  8. data/lib/resourceful/default/actions.rb +101 -0
  9. data/lib/resourceful/default/callbacks.rb +51 -0
  10. data/lib/resourceful/default/responses.rb +118 -0
  11. data/lib/resourceful/default/urls.rb +136 -0
  12. data/lib/resourceful/generators/resourceful_scaffold/resourceful_scaffold_generator.rb +87 -0
  13. data/lib/resourceful/generators/resourceful_scaffold/templates/controller.rb +5 -0
  14. data/lib/resourceful/generators/resourceful_scaffold/templates/fixtures.yml +10 -0
  15. data/lib/resourceful/generators/resourceful_scaffold/templates/functional_test.rb +50 -0
  16. data/lib/resourceful/generators/resourceful_scaffold/templates/helper.rb +2 -0
  17. data/lib/resourceful/generators/resourceful_scaffold/templates/migration.rb +13 -0
  18. data/lib/resourceful/generators/resourceful_scaffold/templates/model.rb +2 -0
  19. data/lib/resourceful/generators/resourceful_scaffold/templates/unit_test.rb +7 -0
  20. data/lib/resourceful/generators/resourceful_scaffold/templates/view__form.haml +5 -0
  21. data/lib/resourceful/generators/resourceful_scaffold/templates/view_edit.haml +11 -0
  22. data/lib/resourceful/generators/resourceful_scaffold/templates/view_index.haml +5 -0
  23. data/lib/resourceful/generators/resourceful_scaffold/templates/view_new.haml +9 -0
  24. data/lib/resourceful/generators/resourceful_scaffold/templates/view_partial.haml +12 -0
  25. data/lib/resourceful/generators/resourceful_scaffold/templates/view_show.haml +14 -0
  26. data/lib/resourceful/maker.rb +92 -0
  27. data/lib/resourceful/response.rb +33 -0
  28. data/lib/resourceful/serialize.rb +185 -0
  29. data/spec/accessors_spec.rb +474 -0
  30. data/spec/actions_spec.rb +310 -0
  31. data/spec/base_spec.rb +12 -0
  32. data/spec/builder_spec.rb +332 -0
  33. data/spec/callbacks_spec.rb +71 -0
  34. data/spec/integration_spec.rb +394 -0
  35. data/spec/maker_spec.rb +91 -0
  36. data/spec/response_spec.rb +37 -0
  37. data/spec/responses_spec.rb +314 -0
  38. data/spec/serialize_spec.rb +133 -0
  39. data/spec/urls_spec.rb +282 -0
  40. metadata +97 -0
@@ -0,0 +1,418 @@
1
+ module Resourceful
2
+ # This module contains various methods
3
+ # that are available from actions and callbacks.
4
+ # Default::Accessors and Default::URLs are the most useful to users;
5
+ # the rest are mostly used internally.
6
+ #
7
+ # However, if you want to poke around the internals a little,
8
+ # check out Default::Actions, which has the default Action definitions,
9
+ # and Default::Responses.included, which defines the default response_for[link:classes/Resourceful/Builder.html#M000061] blocks.
10
+ module Default
11
+ # This module contains all sorts of useful methods
12
+ # that allow access to the resources being worked with,
13
+ # metadata about the controller and action,
14
+ # and so forth.
15
+ #
16
+ # Many of these accessors call other accessors
17
+ # and are called by the default make_resourceful actions[link:classes/Resourceful/Default/Actions.html].
18
+ # This means that overriding one method
19
+ # can affect everything else.
20
+ #
21
+ # This can be dangerous, but it can also be very powerful.
22
+ # make_resourceful is designed to take advantage of overriding,
23
+ # so as long as the new methods accomplish the same purpose as the old ones,
24
+ # everything will just work.
25
+ # Even if you make a small mistake,
26
+ # it's hard to break the controller in any unexpected ways.
27
+ #
28
+ # For example, suppose your controller is called TagsController,
29
+ # but your model is called PhotoTag.
30
+ # All you have to do is override current_model_name:
31
+ #
32
+ # def current_model_name
33
+ # "PhotoTag"
34
+ # end
35
+ #
36
+ # Then current_model will return the PhotoTag model,
37
+ # current_object will call <tt>PhotoTag.find</tt>,
38
+ # and so forth.
39
+ #
40
+ # Overriding current_objects and current_object is particularly useful
41
+ # for providing customized model lookup logic.
42
+ module Accessors
43
+ # Returns an array of all the objects of the model corresponding to the controller.
44
+ # For UsersController, it essentially runs <tt>User.find(:all)</tt>.
45
+ #
46
+ # However, there are a few important differences.
47
+ # First, this method caches is results in the <tt>@current_objects</tt> instance variable.
48
+ # That way, multiple calls won't run multiple queries.
49
+ #
50
+ # Second, this method uses the current_model accessor,
51
+ # which provides a lot of flexibility
52
+ # (see the documentation for current_model for details).
53
+ def current_objects
54
+ @current_objects ||= current_model.find(:all)
55
+ end
56
+
57
+ # Calls current_objects and stores
58
+ # the result in an instance variable
59
+ # named after the controller.
60
+ #
61
+ # This is called automatically by the default make_resourceful actions.
62
+ # You shouldn't need to use it directly unless you're creating a new action.
63
+ #
64
+ # For example, in UsersController,
65
+ # calling +load_objects+ sets <tt>@users = current_objects</tt>.
66
+ def load_objects
67
+ instance_variable_set("@#{instance_variable_name}", current_objects)
68
+ end
69
+
70
+ # Returns the object referenced by the id parameter
71
+ # (or the newly-created object for the +new+ and +create+ actions).
72
+ # For UsersController, it essentially runs <tt>User.find(params[:id])</tt>.
73
+ #
74
+ # However, there are a few important differences.
75
+ # First, this method caches is results in the <tt>@current_objects</tt> instance variable.
76
+ # That way, multiple calls won't run multiple queries.
77
+ #
78
+ # Second, this method uses the current_model accessor,
79
+ # which provides a lot of flexibility
80
+ # (see the documentation for current_model for details).
81
+ #
82
+ # Note that this is different for a singleton controller,
83
+ # where there's only one resource per parent resource.
84
+ # Then this just returns that resource.
85
+ # For example, if Person has_one Hat,
86
+ # then in HatsController current_object essentially runs <tt>Person.find(params[:person_id]).hat</tt>.
87
+ def current_object
88
+ @current_object ||= if !parent? || plural?
89
+ current_model.find(params[:id]) if params[:id]
90
+ else
91
+ parent_object.send(instance_variable_name.singularize)
92
+ end
93
+ end
94
+
95
+
96
+ # Calls current_object and stores
97
+ # the result in an instance variable
98
+ # named after the controller.
99
+ #
100
+ # This is called automatically by the default make_resourceful actions.
101
+ # You shouldn't need to use it directly unless you're creating a new action.
102
+ #
103
+ # For example, in UsersController,
104
+ # calling +load_object+ sets <tt>@user = current_object</tt>.
105
+ def load_object
106
+ instance_variable_set("@#{instance_variable_name.singularize}", current_object)
107
+ end
108
+
109
+ # Creates a new object of the type of the current model
110
+ # with the current object's parameters.
111
+ # +current_object+ then returns this object for this action
112
+ # instead of looking up a new object.
113
+ #
114
+ # This is called automatically by the default make_resourceful actions.
115
+ # You shouldn't need to use it directly unless you're creating a new action.
116
+ #
117
+ # Note that if a parent object exists,
118
+ # the newly created object will automatically be a child of the parent object.
119
+ # For example, on POST /people/4/things,
120
+ #
121
+ # build_object
122
+ # current_object.person.id #=> 4
123
+ #
124
+ def build_object
125
+ @current_object = if current_model.respond_to? :build
126
+ current_model.build(object_parameters)
127
+ else
128
+ current_model.new(object_parameters).tap do |obj|
129
+ if singular? && parent?
130
+ obj.send("#{parent_name}_id=", parent_object.id)
131
+ obj.send("#{parent_name}_type=", parent_object.class.to_s) if polymorphic_parent?
132
+ end
133
+ end
134
+ end
135
+ end
136
+
137
+ def namespaced_model_name
138
+ [self.class.model_namespace, current_model_name].compact.join('::')
139
+ end
140
+
141
+ # The string name of the current model.
142
+ # By default, this is derived from the name of the controller.
143
+ def current_model_name
144
+ controller_name.singularize.camelize
145
+ end
146
+
147
+ # An array of namespaces under which the current controller is.
148
+ # For example, in Admin::Content::PagesController:
149
+ #
150
+ # namespaces #=> [:admin, :content]
151
+ #
152
+ def namespaces
153
+ @namespaces ||= self.class.name.split('::').slice(0...-1).map(&:underscore).map(&:to_sym)
154
+ end
155
+
156
+ # The name of the instance variable that load_object and load_objects should assign to.
157
+ def instance_variable_name
158
+ controller_name
159
+ end
160
+
161
+ # The class of the current model.
162
+ # Note that if a parent object exists,
163
+ # this instead returns the association object.
164
+ # For example, in HatsController where Person has_many :hats,
165
+ #
166
+ # current_model #=> Person.find(params[:person_id]).hats
167
+ #
168
+ # This is useful because the association object uses duck typing
169
+ # to act like a model class.
170
+ # It supplies a find method that's automatically scoped
171
+ # to ensure that the object returned is actually a child of the parent,
172
+ # and so forth.
173
+ def current_model
174
+ if !parent? || singular?
175
+ namespaced_model_name.constantize
176
+ else
177
+ parent_object.send(instance_variable_name)
178
+ end
179
+ end
180
+
181
+ # Returns the hash passed as HTTP parameters
182
+ # that defines the new (or updated) attributes
183
+ # of the current object.
184
+ # This is only meaningful for +create+ or +update+.
185
+ def object_parameters
186
+ params[namespaced_model_name.underscore.tr('/', '_')]
187
+ end
188
+
189
+ # Returns a list of the names of all the potential parents of the current model.
190
+ # For a non-nested controller, this is <tt>[]</tt>.
191
+ # For example, in HatsController where Rack has_many :hats and Person has_many :hats,
192
+ #
193
+ # parents #=> ["rack", "person"]
194
+ #
195
+ # Note that the parents must be declared via Builder#belongs_to.
196
+ def parent_names
197
+ self.class.parents
198
+ end
199
+
200
+ # Returns true if an appropriate parent id parameter has been supplied.
201
+ # For example, in HatsController where Rack has_many :hats and Person has_many :hats,
202
+ # if <tt>params[:rack_id]</tt> or <tt>params[:person_id]</tt> is given,
203
+ #
204
+ # parent? #=> true
205
+ #
206
+ # Otherwise, if both <tt>params[:rack_id]</tt> and <tt>params[:rack_id]</tt> are nil,
207
+ #
208
+ # parent? #=> false
209
+ #
210
+ # Note that parents must be declared via Builder#belongs_to.
211
+ def parent?
212
+ !!parent_name
213
+ end
214
+
215
+ # Returns true if no parent id parameter can be found _and_ a belongs_to
216
+ # relationship on this controller was declared with a parent for shallow
217
+ # routing.
218
+ def shallow?
219
+ self.class.shallow_parent &&
220
+ (parent_name.nil? || parent_name == self.class.shallow_parent)
221
+ end
222
+
223
+ # Returns whether the parent (if it exists) is polymorphic
224
+ def polymorphic_parent?
225
+ !!polymorphic_parent_name
226
+ end
227
+
228
+ # Returns the name of the current parent object if a parent id is given,
229
+ # or nil otherwise. For example, in HatsController where Rack has_many
230
+ # :hats and Person has_many :hats, if <tt>params[:rack_id]</tt> is
231
+ # given,
232
+ #
233
+ # parent_name #=> "rack"
234
+ #
235
+ # If <tt>params[:person_id]</tt> is given,
236
+ #
237
+ # parent_name #=> "person"
238
+ #
239
+ # If both <tt>params[:rack_id]</tt> and <tt>params[:person_id]</tt> are
240
+ # nil,
241
+ #
242
+ # parent_name #=> nil
243
+ #
244
+ # There are several things to note about this method. First,
245
+ # make_resourceful only supports single-level model nesting. Thus, if
246
+ # neither <tt>params[:rack_id]</tt> nor <tt>params[:rack_id]</tt> are
247
+ # nil, the return value of +parent_name+ is undefined.
248
+ #
249
+ # Second, don't use parent_name to check whether a parent id is given.
250
+ # It's better to use the more semantic parent? method.
251
+ #
252
+ # Third, parent_name caches its return value in the
253
+ # <tt>@parent_name</tt> variable, which you should keep in mind if
254
+ # you're overriding it. However, because <tt>@parent_name == nil</tt>
255
+ # could mean that there is no parent _or_ that the method hasn't been
256
+ # run yet, it uses <tt>defined?(@parent_name)</tt> to do the caching
257
+ # rather than <tt>@parent_name ||=</tt>. See the source code.
258
+ #
259
+ # Finally, note that parents must be declared via Builder#belongs_to.
260
+ #
261
+ # FIXME - Perhaps this logic should be moved to parent?() or another
262
+ # init method
263
+ def parent_name
264
+ return @parent_name if defined?(@parent_name)
265
+ @parent_name = parent_names.find { |name| params["#{name}_id"] }
266
+ if @parent_name.nil?
267
+ # get any polymorphic parents through :as association inspection
268
+ names = params.keys.inject({}) do |hsh, key|
269
+ hsh[key] = key.chomp("_id") if key.to_s =~ /_id$/
270
+ hsh
271
+ end
272
+ names.each do |key, name|
273
+ begin
274
+ klass = name.camelize.constantize
275
+ if association = klass.reflect_on_all_associations.detect { |association| association.options[:as] && parent_names.include?(association.options[:as].to_s) }
276
+ @parent_name = name
277
+ @polymorphic_parent_name = association.options[:as].to_s
278
+ @parent_class_name = name.camelize
279
+ @parent_object = klass.find(params[key])
280
+ break
281
+ end
282
+ rescue
283
+ end
284
+ end
285
+ else
286
+ @parent_class_name = params["#{parent_name}_type"]
287
+ @polymorphic_parent = !@parent_class_name.nil? # NEVER USED
288
+ end
289
+ @parent_name
290
+ end
291
+
292
+ def polymorphic_parent_name
293
+ @polymorphic_parent_name
294
+ end
295
+
296
+ # Returns the class name of the current parent.
297
+ # For example, in HatsController where Person has_many :hats,
298
+ # if <tt>params[:person_id]</tt> is given,
299
+ #
300
+ # parent_class_name #=> 'Person'
301
+ #
302
+ # Note that parents must be declared via Builder#belongs_to.
303
+ def parent_class_name
304
+ parent_name # to init @parent_class_name
305
+ @parent_class_name ||= parent_name.nil? ? nil : parent_name.camelize
306
+ end
307
+
308
+ # Returns the model class of the current parent.
309
+ # For example, in HatsController where Person has_many :hats,
310
+ # if <tt>params[:person_id]</tt> is given,
311
+ #
312
+ # parent_models #=> Person
313
+ #
314
+ # Note that parents must be declared via Builder#belongs_to.
315
+ def parent_model
316
+ parent_class_name.nil? ? nil : parent_class_name.constantize
317
+ end
318
+
319
+ # Returns the current parent object for the current object.
320
+ # For example, in HatsController where Person has_many :hats,
321
+ # if <tt>params[:person_id]</tt> is given,
322
+ #
323
+ # parent_object #=> Person.find(params[:person_id])
324
+ #
325
+ # Note that parents must be declared via Builder#belongs_to.
326
+ #
327
+ # Note also that the results of this method are cached
328
+ # so that multiple calls don't result in multiple SQL queries.
329
+ def parent_object
330
+ @parent_object ||= parent_model.nil? ? nil : parent_model.find(params["#{parent_name}_id"])
331
+ end
332
+
333
+ # Assigns the current parent object, as given by parent_objects,
334
+ # to its proper instance variable, as given by parent_name.
335
+ #
336
+ # This is automatically added as a before_filter.
337
+ # You shouldn't need to use it directly unless you're creating a new action.
338
+ def load_parent_object
339
+ instance_variable_set("@#{parent_name}", parent_object) if parent?
340
+ instance_variable_set("@#{polymorphic_parent_name}", parent_object) if polymorphic_parent?
341
+ end
342
+
343
+ # Renders a 422 error if no parent id is given.
344
+ # This is meant to be used with before_filter
345
+ # to ensure that some actions are only called with a parent id.
346
+ # For example:
347
+ #
348
+ # before_filter :ensure_parent_exists, :only => [:create, :update]
349
+ #
350
+ def ensure_parent_exists
351
+ return true if parent?
352
+ render :text => 'No parent id given', :status => 422
353
+ return false
354
+ end
355
+
356
+ # Returns whether or not the database update in the +create+, +update+, and +destroy+
357
+ # was completed successfully.
358
+ def save_succeeded?
359
+ @save_succeeded
360
+ end
361
+
362
+ # Declares that the current databse update was completed successfully.
363
+ # Causes subsequent calls to <tt>save_succeeded?</tt> to return +true+.
364
+ #
365
+ # This is mostly meant to be used by the default actions,
366
+ # but it can be used by user-defined actions as well.
367
+ def save_succeeded!
368
+ @save_succeeded = true
369
+ end
370
+
371
+ # Declares that the current databse update was not completed successfully.
372
+ # Causes subsequent calls to <tt>save_succeeded?</tt> to return +false+.
373
+ #
374
+ # This is mostly meant to be used by the default actions,
375
+ # but it can be used by user-defined actions as well.
376
+ def save_failed!
377
+ @save_succeeded = false
378
+ end
379
+
380
+ # Returns whether or not the current action acts upon multiple objects.
381
+ # By default, the only such action is +index+.
382
+ def plural_action?
383
+ PLURAL_ACTIONS.include?(params[:action].to_sym)
384
+ end
385
+
386
+ # Returns whether or not the current action acts upon a single object.
387
+ # By default, this is the case for all actions but +index+.
388
+ def singular_action?
389
+ !plural_action?
390
+ end
391
+
392
+ # Returns whether the controller is a singleton,
393
+ # implying that there is only one such resource for each parent resource.
394
+ #
395
+ # Note that the way this is determined is based on the singularity of the controller name,
396
+ # so it may yield false positives for oddly-named controllers and need to be overridden.
397
+ #
398
+ # TODO: maybe we can define plural? and singular? as class_methods,
399
+ # so they are not visible to the world
400
+ def singular?
401
+ instance_variable_name.singularize == instance_variable_name
402
+ end
403
+
404
+ # Returns whether the controller is a normal plural controller,
405
+ # implying that there are multiple resources for each parent resource.
406
+ #
407
+ # Note that the way this is determined is based on the singularity of the controller name,
408
+ # so it may yield false negatives for oddly-named controllers.
409
+ # If this is the case, the singular? method should be overridden.
410
+ #
411
+ # TODO: maybe we can define plural? and singular? as class_methods,
412
+ # so they are not visible to the world
413
+ def plural?
414
+ !singular?
415
+ end
416
+ end
417
+ end
418
+ end
@@ -0,0 +1,101 @@
1
+ module Resourceful
2
+ module Default
3
+ # Contains the definitions of the default resourceful actions.
4
+ # These are made available with the Builder#actions method.
5
+ #
6
+ # These methods are very compact,
7
+ # so the best way to understand them is just to look at their source.
8
+ # Check out Resourceful::Accessors and Resourceful::Callbacks
9
+ # for the documentation of the methods called within the actions.
10
+ #
11
+ # Along with each action is listed the RESTful method
12
+ # which corresponds to the action.
13
+ # The controller in the examples is FoosController,
14
+ # and the id for single-object actions is 12.
15
+ module Actions
16
+ # GET /foos
17
+ def index
18
+ #load_objects
19
+ before :index
20
+ response_for :index
21
+ end
22
+
23
+ # GET /foos/12
24
+ def show
25
+ # NOTE - Moved this call to a more generic place
26
+ #load_object
27
+ before :show
28
+ response_for :show
29
+ rescue
30
+ response_for :show_fails
31
+ end
32
+
33
+ # POST /foos
34
+ def create
35
+ build_object
36
+ load_object
37
+ before :create
38
+ if current_object.save
39
+ save_succeeded!
40
+ after :create
41
+ response_for :create
42
+ else
43
+ save_failed!
44
+ after :create_fails
45
+ response_for :create_fails
46
+ end
47
+ end
48
+
49
+ # PUT /foos/12
50
+ def update
51
+ #load_object
52
+ before :update
53
+
54
+ begin
55
+ result = current_object.update_attributes object_parameters
56
+ rescue ActiveRecord::StaleObjectError
57
+ current_object.reload
58
+ result = false
59
+ end
60
+
61
+ if result
62
+ save_succeeded!
63
+ after :update
64
+ response_for :update
65
+ else
66
+ save_failed!
67
+ after :update_fails
68
+ response_for :update_fails
69
+ end
70
+ end
71
+
72
+ # GET /foos/new
73
+ def new
74
+ build_object
75
+ load_object
76
+ before :new
77
+ response_for :new
78
+ end
79
+
80
+ # GET /foos/12/edit
81
+ def edit
82
+ #load_object
83
+ before :edit
84
+ response_for :edit
85
+ end
86
+
87
+ # DELETE /foos/12
88
+ def destroy
89
+ #load_object
90
+ before :destroy
91
+ if current_object.destroy
92
+ after :destroy
93
+ response_for :destroy
94
+ else
95
+ after :destroy_fails
96
+ response_for :destroy_fails
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,51 @@
1
+ require 'resourceful/builder'
2
+
3
+ module Resourceful
4
+ module Default
5
+ # This module is mostly meant to be used by the make_resourceful default actions.
6
+ # It provides various methods that declare where callbacks set in the +make_resourceful+ block,
7
+ # like Builder#before and Builder#response_for,
8
+ # should be called.
9
+ module Callbacks
10
+ # Calls any +before+ callbacks set in the +make_resourceful+ block for the given event.
11
+ def before(event)
12
+ resourceful_fire(:before, event.to_sym)
13
+ end
14
+
15
+ # Calls any +after+ callbacks set in the +make_resourceful+ block for the given event.
16
+ def after(event)
17
+ resourceful_fire(:after, event.to_sym)
18
+ end
19
+
20
+ # Calls any +response_for+ callbacks set in the +make_resourceful+ block for the given event.
21
+ # Note that these aren't called directly,
22
+ # but instead passed along to Rails' respond_to method.
23
+ def response_for(event)
24
+ if responses = self.class.resourceful_responses[event.to_sym]
25
+ respond_to do |format|
26
+ responses.each do |key, value|
27
+ format.send(key, &scope(value))
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ # Returns a block identical to the given block,
34
+ # but in the context of the current controller.
35
+ # The returned block accepts no arguments,
36
+ # even if the given block accepted them.
37
+ def scope(block)
38
+ proc do
39
+ instance_eval(&(block || proc {}))
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def resourceful_fire(type, name)
46
+ callbacks = self.class.resourceful_callbacks[type][name] || []
47
+ callbacks.each { |callback| scope(callback).call }
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,118 @@
1
+ module Resourceful
2
+ module Default
3
+ module Responses
4
+ # Sets the default flash message.
5
+ # This message can be overridden by passing in
6
+ # an HTTP parameter of the form "_flash[type]" via POST or GET.
7
+ #
8
+ # You can use this to easily have multiple forms
9
+ # post to the same create/edit/destroy actions
10
+ # but display different flash notices -
11
+ # without modifying the controller code at all.
12
+ #
13
+ # By default, the flash types are +notice+ when the database operation completes successfully
14
+ # and +error+ when it fails.
15
+ #
16
+ #--
17
+ # TODO: Move this out of here
18
+ #++
19
+ def set_default_flash(type, message)
20
+ flash[type] ||= (params[:_flash] && params[:_flash][type]) || message
21
+ end
22
+
23
+ # Sets the default redirect
24
+ # (the argument passed to +redirect_to+).
25
+ # This message can be overridden by passing in
26
+ # an HTTP parameter of the form "_redirect_on[status]" via POST or GET.
27
+ #
28
+ # You can use this to easily have multiple forms
29
+ # post to the same create/edit/destroy actions
30
+ # but redirect to different URLs -
31
+ # without modifying the controller code at all.
32
+ #
33
+ # By default, the redirect statuses are +success+ when the database operation completes successfully
34
+ # and +failure+ when it fails.
35
+ # Use the <tt>:status</tt> option to specify which status to run the redirect for.
36
+ # For example:
37
+ #
38
+ # set_default_redirect "/posts", :status => :failure
39
+ #
40
+ # This will run <tt>redirect_to params[:_redirect_on][:failure]</tt> if the parameter exists,
41
+ # or <tt>redirect_to "/posts"</tt> otherwise.
42
+ #
43
+ #--
44
+ # TODO: Move this out of here
45
+ #++
46
+ def set_default_redirect(to, options = {})
47
+ status = options[:status] || :success
48
+ redirect_to (params[:_redirect_on] && params[:_redirect_on][status]) || to
49
+ end
50
+
51
+ # This method is automatically run when this module is included in Resourceful::Base.
52
+ # It sets up the default responses for the default actions.
53
+ def self.included(base)
54
+ base.made_resourceful do
55
+ response_for(:show, :index, :edit, :new) do |format|
56
+ format.html
57
+ format.js
58
+ end
59
+
60
+ response_for(:show_fails) do |format|
61
+ not_found = Proc.new { render :text => I18n.t('make_resourceful.show.fails', :default => "No item found"), :status => 404 }
62
+ format.html &not_found
63
+ format.js &not_found
64
+ format.xml &not_found
65
+ end
66
+
67
+ response_for(:create) do |format|
68
+ format.html do
69
+ set_default_flash :notice, I18n.t('make_resourceful.create.success', :default => "Create successful!")
70
+ set_default_redirect object_path
71
+ end
72
+ format.js
73
+ end
74
+
75
+ response_for(:create_fails) do |format|
76
+ format.html do
77
+ set_default_flash :error, I18n.t('make_resourceful.create.fails', :default => "There was a problem!")
78
+ render :action => :new, :status => 422
79
+ end
80
+ format.js
81
+ end
82
+
83
+ response_for(:update) do |format|
84
+ format.html do
85
+ set_default_flash :notice, I18n.t('make_resourceful.update.success', :default => "Save successful!")
86
+ set_default_redirect object_path
87
+ end
88
+ format.js
89
+ end
90
+
91
+ response_for(:update_fails) do |format|
92
+ format.html do
93
+ set_default_flash :error, I18n.t('make_resourceful.update.fails', :default => "There was a problem saving!")
94
+ render :action => :edit, :status => 422
95
+ end
96
+ format.js
97
+ end
98
+
99
+ response_for(:destroy) do |format|
100
+ format.html do
101
+ set_default_flash :notice, I18n.t('make_resourceful.destroy.success', :default => "Record deleted!")
102
+ set_default_redirect objects_path
103
+ end
104
+ format.js
105
+ end
106
+
107
+ response_for(:destroy_fails) do |format|
108
+ format.html do
109
+ set_default_flash :error, I18n.t('make_resourceful.destroy.fails', :default => "There was a problem deleting!")
110
+ set_default_redirect :back, :status => :failure
111
+ end
112
+ format.js
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end