josevalim-inherited_resources 0.5.2 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +12 -5
- data/README +13 -3
- data/lib/inherited_resources/base.rb +29 -19
- data/lib/inherited_resources/base_helpers.rb +17 -8
- data/lib/inherited_resources/respond_to.rb +26 -63
- data/test/aliases_test.rb +5 -11
- data/test/base_helpers_test.rb +5 -8
- data/test/base_test.rb +8 -11
- data/test/belongs_to_test.rb +9 -21
- data/test/class_methods_test.rb +20 -21
- data/test/defaults_test.rb +5 -4
- data/test/nested_belongs_to_test.rb +11 -41
- data/test/optional_belongs_to_test.rb +22 -48
- data/test/polymorphic_test.rb +98 -23
- data/test/redirect_to_test.rb +52 -0
- data/test/respond_to_test.rb +23 -26
- data/test/singleton_test.rb +4 -4
- data/test/test_helper.rb +0 -7
- metadata +3 -2
data/CHANGELOG
CHANGED
@@ -1,4 +1,11 @@
|
|
1
|
-
# Version 0.
|
1
|
+
# Version 0.6
|
2
|
+
|
3
|
+
* Cleaned up tests and responder structure. Whenever you pass a block to aliases
|
4
|
+
and this block responds to the request, the other blocks are not parsed improcing performance.
|
5
|
+
* [BACKWARDS INCOMPATIBLE] By default, Inherited Resources respond only :html requests
|
6
|
+
* Added a quick way to overwrite the redirect to url in :create, :update and :destroy
|
7
|
+
|
8
|
+
# Version 0.5
|
2
9
|
|
3
10
|
* Decoupled routes name from :instance_name and :collection_name. This way we
|
4
11
|
have more flexibility. Use route_instance_name and route_collection_name to
|
@@ -6,7 +13,7 @@
|
|
6
13
|
* Avoid calling human_name on nil when a resource class is not defined.
|
7
14
|
* Only call I18n if it's defined.
|
8
15
|
|
9
|
-
# Version 0.4
|
16
|
+
# Version 0.4
|
10
17
|
|
11
18
|
* Dealing with namespaced controllers out of the box.
|
12
19
|
* Added support to namespaced routes through :route_prefix.
|
@@ -24,7 +31,7 @@
|
|
24
31
|
categories/1/products/2 and /products/2 with just one controller.
|
25
32
|
* Cleaned up tests.
|
26
33
|
|
27
|
-
# Version 0.3
|
34
|
+
# Version 0.3
|
28
35
|
|
29
36
|
* Minor bump after three bug fixes.
|
30
37
|
* Bug fix when showing warning of constant redefinition.
|
@@ -33,13 +40,13 @@
|
|
33
40
|
raise "NoMethodError _url", not it will call root_url.
|
34
41
|
* More comments on UrlHelpers.
|
35
42
|
|
36
|
-
# Version 0.2
|
43
|
+
# Version 0.2
|
37
44
|
|
38
45
|
* Bug fix when ApplicationController is already loaded when we load respond_to.
|
39
46
|
* Added support success/failure blocks.
|
40
47
|
* Eager loading of files to work properly in multithreaded environments.
|
41
48
|
|
42
|
-
# Version 0.1
|
49
|
+
# Version 0.1
|
43
50
|
|
44
51
|
* Added more helper_methods.
|
45
52
|
* Added Rails 2.3.0 and changed tests to work with ActionController::TestCase.
|
data/README
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
Inherited Resources
|
2
2
|
License: MIT
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.6.0
|
4
4
|
|
5
5
|
You can also read this README in pretty html at the GitHub project Wiki page:
|
6
6
|
|
7
|
-
http://github.com/josevalim/inherited_resources
|
7
|
+
http://wiki.github.com/josevalim/inherited_resources
|
8
8
|
|
9
9
|
Description
|
10
10
|
-----------
|
@@ -199,11 +199,21 @@ equivalent:
|
|
199
199
|
class ProjectsController < InheritedResources::Base
|
200
200
|
def destroy
|
201
201
|
destroy! do |format|
|
202
|
-
format.html { redirect_to
|
202
|
+
format.html { redirect_to root_url }
|
203
203
|
end
|
204
204
|
end
|
205
205
|
end
|
206
206
|
|
207
|
+
Even more, since most of the times that you change a :create, :update or :destroy
|
208
|
+
action is because you want to to change to where it redirects, a shortcut is
|
209
|
+
provided. So you can do:
|
210
|
+
|
211
|
+
class ProjectsController < InheritedResources::Base
|
212
|
+
def destroy
|
213
|
+
destroy!(root_url)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
207
217
|
Now let's suppose that before create a project you have to do something special
|
208
218
|
but you don't want to create a before filter for it:
|
209
219
|
|
@@ -54,7 +54,7 @@
|
|
54
54
|
# class ProjectController < InheritedResources::Base
|
55
55
|
# def destroy
|
56
56
|
# super do |format|
|
57
|
-
# format.html { redirect_to
|
57
|
+
# format.html { redirect_to root_url }
|
58
58
|
# end
|
59
59
|
# end
|
60
60
|
# end
|
@@ -65,11 +65,21 @@
|
|
65
65
|
# class ProjectController < InheritedResources::Base
|
66
66
|
# def destroy
|
67
67
|
# destroy! do |format|
|
68
|
-
# format.html { redirect_to
|
68
|
+
# format.html { redirect_to root_url }
|
69
69
|
# end
|
70
70
|
# end
|
71
71
|
# end
|
72
72
|
#
|
73
|
+
# Even more, since most of the times that you change a :create, :update or :destroy
|
74
|
+
# action is because you want to to change to where it redirects, a shortcut is
|
75
|
+
# provided. So you can do:
|
76
|
+
#
|
77
|
+
# class ProjectsController < InheritedResources::Base
|
78
|
+
# def destroy
|
79
|
+
# destroy!(root_url)
|
80
|
+
# end
|
81
|
+
# end
|
82
|
+
#
|
73
83
|
# Since this is actually Ruby (and not a new DSL), if you want to do something
|
74
84
|
# before creating the project that is to small to deserve a before_filter, you
|
75
85
|
# could simply do:
|
@@ -231,22 +241,23 @@ module InheritedResources
|
|
231
241
|
alias :edit! :edit
|
232
242
|
|
233
243
|
# POST /resources
|
234
|
-
def create(&block)
|
244
|
+
def create(redirect_to=nil, &block)
|
235
245
|
object = build_resource(params[resource_instance_name])
|
236
246
|
|
237
247
|
if object.save
|
238
248
|
set_flash_message!(:notice, '{{resource_name}} was successfully created.')
|
239
|
-
location_url = resource_url rescue nil # Sometimes resource_url is undefined
|
240
249
|
|
241
|
-
|
242
|
-
|
243
|
-
|
250
|
+
options = { :with => object, :status => :created, :location => (resource_url rescue nil) }
|
251
|
+
|
252
|
+
respond_to_with_dual_blocks(true, block, options) do |format|
|
253
|
+
format.html { redirect_to(redirect_to || resource_url) }
|
244
254
|
end
|
245
255
|
else
|
246
256
|
set_flash_message!(:error)
|
247
257
|
|
248
|
-
|
249
|
-
|
258
|
+
options = { :with => object.errors, :status => :unprocessable_entity }
|
259
|
+
|
260
|
+
respond_to_with_dual_blocks(false, block, options) do |format|
|
250
261
|
format.html { render :action => 'new' }
|
251
262
|
end
|
252
263
|
end
|
@@ -254,22 +265,22 @@ module InheritedResources
|
|
254
265
|
alias :create! :create
|
255
266
|
|
256
267
|
# PUT /resources/1
|
257
|
-
def update(&block)
|
268
|
+
def update(redirect_to=nil, &block)
|
258
269
|
object = resource
|
259
270
|
|
260
271
|
if object.update_attributes(params[resource_instance_name])
|
261
272
|
set_flash_message!(:notice, '{{resource_name}} was successfully updated.')
|
262
273
|
|
263
|
-
|
264
|
-
|
265
|
-
format.html { redirect_to(resource_url) }
|
274
|
+
respond_to_with_dual_blocks(true, block) do |format|
|
275
|
+
format.html { redirect_to(redirect_to || resource_url) }
|
266
276
|
format.all { head :ok }
|
267
277
|
end
|
268
278
|
else
|
269
279
|
set_flash_message!(:error)
|
270
280
|
|
271
|
-
|
272
|
-
|
281
|
+
options = { :with => object.errors, :status => :unprocessable_entity }
|
282
|
+
|
283
|
+
respond_to_with_dual_blocks(false, block, options) do |format|
|
273
284
|
format.html { render :action => 'edit' }
|
274
285
|
end
|
275
286
|
end
|
@@ -277,14 +288,13 @@ module InheritedResources
|
|
277
288
|
alias :update! :update
|
278
289
|
|
279
290
|
# DELETE /resources/1
|
280
|
-
def destroy
|
291
|
+
def destroy(redirect_to=nil, &block)
|
281
292
|
resource.destroy
|
282
293
|
|
283
294
|
set_flash_message!(:notice, '{{resource_name}} was successfully destroyed.')
|
284
295
|
|
285
|
-
|
286
|
-
|
287
|
-
format.html { redirect_to(collection_url) }
|
296
|
+
respond_to_with_dual_blocks(nil, block) do |format|
|
297
|
+
format.html { redirect_to(redirect_to || collection_url) }
|
288
298
|
format.all { head :ok }
|
289
299
|
end
|
290
300
|
end
|
@@ -226,17 +226,26 @@ module InheritedResources #:nodoc:
|
|
226
226
|
# end
|
227
227
|
# end
|
228
228
|
#
|
229
|
-
def
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
229
|
+
def respond_to_with_dual_blocks(success, dual_block, options={}, &block)
|
230
|
+
responder = ActionController::MimeResponds::Responder.new(self)
|
231
|
+
|
232
|
+
if dual_block
|
233
|
+
if dual_block.arity == 2
|
234
|
+
dumb_responder = InheritedResources::DumbResponder.new
|
235
|
+
if success
|
236
|
+
dual_block.call(responder, dumb_responder)
|
237
|
+
else
|
238
|
+
dual_block.call(dumb_responder, responder)
|
239
|
+
end
|
234
240
|
else
|
235
|
-
|
241
|
+
dual_block.call(responder)
|
236
242
|
end
|
237
|
-
|
238
|
-
|
243
|
+
|
244
|
+
# Try to respond with the block given
|
245
|
+
responder.respond_except_any
|
239
246
|
end
|
247
|
+
|
248
|
+
respond_to(options.merge(:responder => responder), &block) unless performed?
|
240
249
|
end
|
241
250
|
|
242
251
|
end
|
@@ -59,9 +59,8 @@ module ActionController #:nodoc:
|
|
59
59
|
end
|
60
60
|
class_inheritable_reader :formats_for_respond_to
|
61
61
|
|
62
|
-
#
|
62
|
+
# By default, responds only to :html
|
63
63
|
respond_to :html
|
64
|
-
respond_to :xml, :except => [ :edit ]
|
65
64
|
|
66
65
|
# Method to clear all respond_to declared until the current controller.
|
67
66
|
# This is like freeing the controller from the inheritance chain. :)
|
@@ -119,20 +118,12 @@ module ActionController #:nodoc:
|
|
119
118
|
def respond_with(object, options = {})
|
120
119
|
attempt_to_respond = false
|
121
120
|
|
122
|
-
|
123
|
-
|
124
|
-
responder = options.delete(:responder) || Responder.new(self)
|
121
|
+
responder = options.delete(:responder) || Responder.new(self)
|
122
|
+
skip_not_acceptable = options.delete(:skip_not_acceptable)
|
125
123
|
|
126
|
-
# Check for given mime types
|
127
|
-
#
|
128
124
|
mime_types = Array(options.delete(:to))
|
129
125
|
mime_types.map!{ |mime| mime.to_sym }
|
130
126
|
|
131
|
-
# If :skip_not_acceptable is sent, it will not render :not_acceptable
|
132
|
-
# if the mime type sent by the client cannot be found.
|
133
|
-
#
|
134
|
-
skip_not_acceptable = options.delete(:skip_not_acceptable)
|
135
|
-
|
136
127
|
for priority in responder.mime_type_priority
|
137
128
|
if priority == Mime::ALL && template_exists?
|
138
129
|
render options.merge(:action => action_name)
|
@@ -206,58 +197,38 @@ module ActionController #:nodoc:
|
|
206
197
|
#
|
207
198
|
def respond_to(*types, &block)
|
208
199
|
options = types.extract_options!
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
200
|
+
|
201
|
+
object = options.delete(:with)
|
202
|
+
responder = options.delete(:responder) || Responder.new(self)
|
203
|
+
|
213
204
|
if object.nil?
|
214
205
|
block ||= lambda { |responder| types.each { |type| responder.send(type) } }
|
215
206
|
block.call(responder)
|
216
207
|
responder.respond
|
217
|
-
return true
|
218
|
-
|
208
|
+
return true
|
219
209
|
else
|
220
|
-
# If a block is given, it checks if we can perform the requested format.
|
221
|
-
#
|
222
210
|
# Even if Mime::ALL is sent by the client, we do not respond_to it now.
|
223
|
-
# This is done using calling :
|
224
|
-
#
|
225
|
-
# It's worth to remember that responder_to_block does not respond
|
226
|
-
# :not_acceptable also.
|
211
|
+
# This is done using calling :respond_except_any instead of :respond.
|
227
212
|
#
|
228
213
|
if block_given?
|
229
214
|
block.call(responder)
|
230
|
-
responder.
|
231
|
-
return true if responder.responded? || performed?
|
215
|
+
return true if responder.respond_except_any
|
232
216
|
end
|
233
217
|
|
234
|
-
|
235
|
-
# At the end, respond_with checks for Mime::ALL if any template exist.
|
236
|
-
#
|
237
|
-
# Notice that we are sending the responder (for performance gain) and
|
238
|
-
# sending :skip_not_acceptable because we don't want to respond
|
239
|
-
# :not_acceptable yet.
|
240
|
-
#
|
241
|
-
if respond_with(object, options.merge(:to => types, :responder => responder, :skip_not_acceptable => true))
|
242
|
-
return true
|
218
|
+
options.merge!(:to => types, :responder => responder, :skip_not_acceptable => true)
|
243
219
|
|
244
|
-
|
245
|
-
|
246
|
-
#
|
220
|
+
if respond_with(object, options)
|
221
|
+
return true
|
247
222
|
elsif block_given?
|
248
|
-
return true if responder.
|
223
|
+
return true if responder.respond_any
|
249
224
|
end
|
250
225
|
end
|
251
226
|
|
252
|
-
# If we get here it means that we could not satisfy our request.
|
253
|
-
# Now we finally return :not_acceptable.
|
254
|
-
#
|
255
227
|
head :not_acceptable
|
256
228
|
return false
|
257
229
|
end
|
258
230
|
|
259
231
|
private
|
260
|
-
|
261
232
|
# Define template_exists? for Rails 2.3
|
262
233
|
unless ActionController::Base.private_instance_methods.include?('template_exists?') ||
|
263
234
|
ActionController::Base.private_instance_methods.include?(:template_exists?)
|
@@ -282,43 +253,35 @@ module ActionController #:nodoc:
|
|
282
253
|
module MimeResponds #:nodoc:
|
283
254
|
class Responder #:nodoc:
|
284
255
|
|
285
|
-
# Create an attr_reader for @mime_type_priority
|
286
256
|
attr_reader :mime_type_priority
|
287
257
|
|
288
|
-
#
|
289
|
-
|
290
|
-
|
291
|
-
# Similar as respond but if we can't find a valid mime type,
|
292
|
-
# we do not send :not_acceptable message as head.
|
258
|
+
# Similar as respond but if we can't find a valid mime type, we do not
|
259
|
+
# send :not_acceptable message as head and it does not respond to
|
260
|
+
# Mime::ALL in any case.
|
293
261
|
#
|
294
|
-
|
295
|
-
#
|
296
|
-
def respond_to_block
|
262
|
+
def respond_except_any
|
297
263
|
for priority in @mime_type_priority
|
298
264
|
next if priority == Mime::ALL
|
299
265
|
|
300
266
|
if @responses[priority]
|
301
267
|
@responses[priority].call
|
302
|
-
return
|
268
|
+
return true
|
303
269
|
end
|
304
270
|
end
|
305
271
|
|
306
|
-
|
307
|
-
@responses[Mime::ALL].call
|
308
|
-
return (@responded = true)
|
309
|
-
else
|
310
|
-
return (@responded = false)
|
311
|
-
end
|
272
|
+
false
|
312
273
|
end
|
313
274
|
|
314
275
|
# Respond to the first format given if Mime::ALL is included in the
|
315
276
|
# mime type priorites. This is the behaviour expected when the client
|
316
277
|
# sends "*/*" as mime type.
|
317
278
|
#
|
318
|
-
def
|
319
|
-
|
320
|
-
|
321
|
-
|
279
|
+
def respond_any
|
280
|
+
any = @responses[@order.include?(Mime::ALL) ? Mime::ALL : @order.first]
|
281
|
+
|
282
|
+
if any && @mime_type_priority.include?(Mime::ALL)
|
283
|
+
any.call
|
284
|
+
return true
|
322
285
|
end
|
323
286
|
end
|
324
287
|
|
data/test/aliases_test.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# Now we are going to test aliases defined in base.rb and if overwriting
|
2
|
-
# methods works properly.
|
3
1
|
require File.dirname(__FILE__) + '/test_helper'
|
4
2
|
|
5
3
|
class Student;
|
@@ -40,13 +38,8 @@ class StudentsController < InheritedResources::Base
|
|
40
38
|
|
41
39
|
end
|
42
40
|
|
43
|
-
class
|
44
|
-
|
45
|
-
def setup
|
46
|
-
@controller = StudentsController.new
|
47
|
-
@controller.request = @request = ActionController::TestRequest.new
|
48
|
-
@controller.response = @response = ActionController::TestResponse.new
|
49
|
-
end
|
41
|
+
class AliasesTest < ActionController::TestCase
|
42
|
+
tests StudentsController
|
50
43
|
|
51
44
|
def test_assignments_before_calling_alias
|
52
45
|
Student.stubs(:new).returns(mock_student)
|
@@ -92,7 +85,7 @@ class AliasesBaseTest < TEST_CLASS
|
|
92
85
|
assert_equal "I won't redirect!", @response.body
|
93
86
|
end
|
94
87
|
|
95
|
-
def
|
88
|
+
def test_dumb_responder_quietly_receives_everything_on_failure
|
96
89
|
Student.stubs(:new).returns(mock_student(:save => false, :errors => []))
|
97
90
|
@controller.stubs(:resource_url).returns('http://test.host/')
|
98
91
|
post :create
|
@@ -107,8 +100,9 @@ class AliasesBaseTest < TEST_CLASS
|
|
107
100
|
assert_equal "I won't render!", @response.body
|
108
101
|
end
|
109
102
|
|
110
|
-
def
|
103
|
+
def test_dumb_responder_quietly_receives_everything_on_success
|
111
104
|
Student.stubs(:find).returns(mock_student(:update_attributes => true))
|
105
|
+
@controller.stubs(:resource_url).returns('http://test.host/')
|
112
106
|
put :update, :id => '42', :student => {:these => 'params'}
|
113
107
|
assert_equal mock_student, assigns(:student)
|
114
108
|
end
|
data/test/base_helpers_test.rb
CHANGED
@@ -19,12 +19,10 @@ class Admin::AddressesController < InheritedResources::Base
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
class FlashBaseHelpersTest <
|
22
|
+
class FlashBaseHelpersTest < ActionController::TestCase
|
23
|
+
tests AddressesController
|
23
24
|
|
24
25
|
def setup
|
25
|
-
@controller = AddressesController.new
|
26
|
-
@controller.request = @request = ActionController::TestRequest.new
|
27
|
-
@controller.response = @response = ActionController::TestResponse.new
|
28
26
|
@request.accept = 'application/xml'
|
29
27
|
end
|
30
28
|
|
@@ -90,6 +88,7 @@ class Pet
|
|
90
88
|
end
|
91
89
|
|
92
90
|
class PetsController < InheritedResources::Base
|
91
|
+
respond_to :xml
|
93
92
|
attr_accessor :current_user
|
94
93
|
|
95
94
|
def edit
|
@@ -107,12 +106,10 @@ class PetsController < InheritedResources::Base
|
|
107
106
|
end
|
108
107
|
end
|
109
108
|
|
110
|
-
class AssociationChainBaseHelpersTest <
|
109
|
+
class AssociationChainBaseHelpersTest < ActionController::TestCase
|
110
|
+
tests PetsController
|
111
111
|
|
112
112
|
def setup
|
113
|
-
@controller = PetsController.new
|
114
|
-
@controller.request = @request = ActionController::TestRequest.new
|
115
|
-
@controller.response = @response = ActionController::TestResponse.new
|
116
113
|
@controller.current_user = mock()
|
117
114
|
@request.accept = 'application/xml'
|
118
115
|
end
|