actionpack 1.8.1 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

Files changed (101) hide show
  1. data/CHANGELOG +309 -16
  2. data/README +1 -1
  3. data/lib/action_controller.rb +5 -0
  4. data/lib/action_controller/assertions.rb +57 -12
  5. data/lib/action_controller/auto_complete.rb +47 -0
  6. data/lib/action_controller/base.rb +288 -258
  7. data/lib/action_controller/benchmarking.rb +8 -3
  8. data/lib/action_controller/caching.rb +88 -42
  9. data/lib/action_controller/cgi_ext/cgi_ext.rb +1 -1
  10. data/lib/action_controller/cgi_ext/cgi_methods.rb +41 -11
  11. data/lib/action_controller/cgi_ext/multipart_progress.rb +169 -0
  12. data/lib/action_controller/cgi_ext/raw_post_data_fix.rb +30 -12
  13. data/lib/action_controller/cgi_process.rb +39 -11
  14. data/lib/action_controller/code_generation.rb +235 -0
  15. data/lib/action_controller/cookies.rb +14 -8
  16. data/lib/action_controller/deprecated_renders_and_redirects.rb +76 -0
  17. data/lib/action_controller/filters.rb +8 -7
  18. data/lib/action_controller/helpers.rb +41 -6
  19. data/lib/action_controller/layout.rb +45 -16
  20. data/lib/action_controller/request.rb +86 -23
  21. data/lib/action_controller/rescue.rb +1 -0
  22. data/lib/action_controller/response.rb +1 -1
  23. data/lib/action_controller/routing.rb +536 -272
  24. data/lib/action_controller/scaffolding.rb +30 -25
  25. data/lib/action_controller/session/active_record_store.rb +251 -50
  26. data/lib/action_controller/streaming.rb +133 -0
  27. data/lib/action_controller/templates/rescues/_request_and_response.rhtml +0 -7
  28. data/lib/action_controller/templates/scaffolds/edit.rhtml +2 -2
  29. data/lib/action_controller/templates/scaffolds/layout.rhtml +22 -18
  30. data/lib/action_controller/templates/scaffolds/list.rhtml +3 -3
  31. data/lib/action_controller/templates/scaffolds/new.rhtml +2 -2
  32. data/lib/action_controller/templates/scaffolds/show.rhtml +1 -1
  33. data/lib/action_controller/test_process.rb +68 -47
  34. data/lib/action_controller/upload_progress.rb +421 -0
  35. data/lib/action_controller/url_rewriter.rb +8 -11
  36. data/lib/action_controller/vendor/html-scanner/html/document.rb +6 -5
  37. data/lib/action_controller/vendor/html-scanner/html/node.rb +70 -14
  38. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +17 -10
  39. data/lib/action_controller/vendor/html-scanner/html/version.rb +3 -3
  40. data/lib/action_controller/vendor/xml_simple.rb +1019 -0
  41. data/lib/action_controller/verification.rb +36 -30
  42. data/lib/action_view/base.rb +21 -14
  43. data/lib/action_view/helpers/active_record_helper.rb +15 -13
  44. data/lib/action_view/helpers/asset_tag_helper.rb +26 -9
  45. data/lib/action_view/helpers/benchmark_helper.rb +24 -0
  46. data/lib/action_view/helpers/capture_helper.rb +7 -5
  47. data/lib/action_view/helpers/date_helper.rb +63 -46
  48. data/lib/action_view/helpers/form_helper.rb +7 -1
  49. data/lib/action_view/helpers/form_options_helper.rb +19 -11
  50. data/lib/action_view/helpers/form_tag_helper.rb +5 -1
  51. data/lib/action_view/helpers/javascript_helper.rb +403 -35
  52. data/lib/action_view/helpers/javascripts/controls.js +261 -0
  53. data/lib/action_view/helpers/javascripts/dragdrop.js +476 -0
  54. data/lib/action_view/helpers/javascripts/effects.js +570 -0
  55. data/lib/action_view/helpers/javascripts/prototype.js +633 -371
  56. data/lib/action_view/helpers/number_helper.rb +11 -13
  57. data/lib/action_view/helpers/tag_helper.rb +1 -2
  58. data/lib/action_view/helpers/text_helper.rb +69 -6
  59. data/lib/action_view/helpers/upload_progress_helper.rb +433 -0
  60. data/lib/action_view/helpers/url_helper.rb +98 -3
  61. data/lib/action_view/partials.rb +14 -8
  62. data/lib/action_view/vendor/builder/xmlmarkup.rb +11 -0
  63. data/rakefile +13 -5
  64. data/test/abstract_unit.rb +1 -1
  65. data/test/controller/action_pack_assertions_test.rb +52 -9
  66. data/test/controller/active_record_assertions_test.rb +119 -120
  67. data/test/controller/active_record_store_test.rb +111 -0
  68. data/test/controller/addresses_render_test.rb +45 -0
  69. data/test/controller/caching_filestore.rb +92 -0
  70. data/test/controller/capture_test.rb +39 -0
  71. data/test/controller/cgi_test.rb +40 -3
  72. data/test/controller/helper_test.rb +65 -13
  73. data/test/controller/multipart_progress_testx.rb +365 -0
  74. data/test/controller/new_render_test.rb +263 -0
  75. data/test/controller/redirect_test.rb +64 -0
  76. data/test/controller/render_test.rb +20 -21
  77. data/test/controller/request_test.rb +83 -3
  78. data/test/controller/routing_test.rb +702 -0
  79. data/test/controller/send_file_test.rb +2 -0
  80. data/test/controller/test_test.rb +44 -8
  81. data/test/controller/upload_progress_testx.rb +89 -0
  82. data/test/controller/verification_test.rb +94 -29
  83. data/test/fixtures/addresses/list.rhtml +1 -0
  84. data/test/fixtures/test/capturing.rhtml +4 -0
  85. data/test/fixtures/test/list.rhtml +1 -1
  86. data/test/fixtures/test/update_element_with_capture.rhtml +9 -0
  87. data/test/template/active_record_helper_test.rb +30 -15
  88. data/test/template/asset_tag_helper_test.rb +12 -5
  89. data/test/template/benchmark_helper_test.rb +72 -0
  90. data/test/template/date_helper_test.rb +69 -0
  91. data/test/template/form_helper_test.rb +18 -10
  92. data/test/template/form_options_helper_test.rb +40 -5
  93. data/test/template/javascript_helper.rb +149 -2
  94. data/test/template/number_helper_test.rb +2 -0
  95. data/test/template/tag_helper_test.rb +4 -0
  96. data/test/template/text_helper_test.rb +36 -0
  97. data/test/template/upload_progress_helper_testx.rb +272 -0
  98. data/test/template/url_helper_test.rb +30 -0
  99. metadata +30 -6
  100. data/test/controller/layout_test.rb +0 -49
  101. data/test/controller/routing_tests.rb +0 -543
@@ -0,0 +1,421 @@
1
+ # Unfortunately we need to require multipart_progress here and not in
2
+ # uplaod_status_for because if the upload happens to hit a fresh FCGI instance
3
+ # the upload_status_for method will be called after the CGI object is created
4
+ # Requiring here means that multipart progress will be enabled for all multipart
5
+ # postings.
6
+ require 'action_controller/cgi_ext/multipart_progress'
7
+
8
+ module ActionController #:nodoc:
9
+ # == THIS IS AN EXPERIMENTAL FEATURE
10
+ #
11
+ # Which means that it doesn't yet work on all systems. We're still working on full
12
+ # compatibility. It's thus not advised to use this unless you've verified it to work
13
+ # fully on all the systems that is a part of your environment. Consider this an extended
14
+ # preview.
15
+ #
16
+ # == Action Pack Upload Progress for multipart uploads
17
+ #
18
+ # The UploadProgress module aids in the process of viewing an Ajax driven
19
+ # upload status when working with multipart forms. It offers a macro that
20
+ # will prepare an action for handling the cleanup of the Ajax updating including
21
+ # passing the redirect URL and custom parameters to the Javascript finish handler.
22
+ #
23
+ # UploadProgress is available for all multipart uploads when the +upload_status_for+
24
+ # macro is called in one of your controllers.
25
+ #
26
+ # The progress is stored as an UploadProgress::Progress object in the session and
27
+ # is accessible in the controller and view with the +upload_progress+ method.
28
+ #
29
+ # For help rendering the UploadProgress enabled form and supported elements, see
30
+ # ActionView::Helpers::UploadProgressHelper.
31
+ #
32
+ # === Automatic updating on upload actions
33
+ #
34
+ # class DocumentController < ApplicationController
35
+ # upload_status_for :create
36
+ #
37
+ # def create
38
+ # # ... Your document creation action
39
+ # end
40
+ # end
41
+ #
42
+ # The +upload_status_for+ macro will override the rendering of the action passed
43
+ # if +upload_id+ is found in the query string. This allows for default
44
+ # behavior if Javascript is disabled. If you are tracking the upload progress
45
+ # then +create+ will now return the cleanup scripts that will terminate the polling
46
+ # of the upload status.
47
+ #
48
+ # === Customized status rendering
49
+ #
50
+ # class DocumentController < ApplicationController
51
+ # upload_status_for :create, :status => :custom_status
52
+ #
53
+ # def create
54
+ # # ... Your document creation action
55
+ # end
56
+ #
57
+ # def custom_status
58
+ # # ... Override this action to return content to be replaced in
59
+ # # the status container
60
+ # render :inline => "<%= upload_progress.completed_percent rescue 0 %> % complete", :layout => false
61
+ # end
62
+ #
63
+ # The default status action is +upload_status+. The results of this action
64
+ # are added used to replace the contents of the HTML elements defined in
65
+ # +upload_status_tag+. Within +upload_status+, you can load the Progress
66
+ # object from the session with the +upload_progress+ method and display your own
67
+ # results.
68
+ #
69
+ # Completion of the upload status updating occurs automatically with an +after_filter+ call to
70
+ # +finish_upload_status+. Because the upload must be posted into a hidden IFRAME to enable
71
+ # Ajax updates during the upload, +finish_upload_status+ overwrites the results of any previous
72
+ # +render+ or +redirect_to+ so it can render the necessary Javascript that will properly terminate
73
+ # the status updating loop, trigger the completion callback or redirect to the appropriate URL.
74
+ #
75
+ # ==== Basic Example (View):
76
+ #
77
+ # <%= form_tag_with_upload_progress({:action => 'create'}, {:finish => 'alert("Document Uploaded")'}) %>
78
+ # <%= upload_status_tag %>
79
+ # <%= file_field 'document', 'file' %>
80
+ # <%= end_form_tag %>
81
+ #
82
+ # ==== Basic Example (Controller):
83
+ #
84
+ # class DocumentController < ApplicationController
85
+ # upload_status_for :create
86
+ #
87
+ # def create
88
+ # @document = Document.create(params[:document])
89
+ # end
90
+ # end
91
+ #
92
+ # ==== Extended Example (View):
93
+ #
94
+ # <%= form_tag_with_upload_progress({:action => 'create'}, {}, {:action => :custom_status}) %>
95
+ # <%= upload_status_tag %>
96
+ # <%= file_field 'document', 'file' %>
97
+ # <%= submit_tag "Upload" %>
98
+ # <%= end_form_tag %>
99
+ #
100
+ # <%= form_tag_with_upload_progress({:action => 'add_preview'}, {:finish => 'alert(arguments[0])'}, {:action => :custom_status}) %>
101
+ # <%= upload_status_tag %>
102
+ # <%= submit_tag "Upload" %>
103
+ # <%= file_field 'preview', 'file' %>
104
+ # <%= end_form_tag %>
105
+ #
106
+ # ==== Extended Example (Controller):
107
+ #
108
+ # class DocumentController < ApplicationController
109
+ # upload_status_for :add_preview, :create, {:status => :custom_status}
110
+ #
111
+ # def add_preview
112
+ # @document = Document.find(params[:id])
113
+ # @document.preview = Preview.create(params[:preview])
114
+ # if @document.save
115
+ # finish_upload_status "'Preview added'"
116
+ # else
117
+ # finish_upload_status "'Preview not added'"
118
+ # end
119
+ # end
120
+ #
121
+ # def create
122
+ # @document = Document.new(params[:document])
123
+ #
124
+ # upload_progress.message = "Processing document..."
125
+ # session.update
126
+ #
127
+ # @document.save
128
+ # redirect_to :action => 'show', :id => @document.id
129
+ # end
130
+ #
131
+ # def custom_status
132
+ # render :inline => '<%= upload_progress_status %> <div>Updated at <%= Time.now %></div>', :layout => false
133
+ # end
134
+ module UploadProgress
135
+ def self.append_features(base) #:nodoc:
136
+ super
137
+ base.extend(ClassMethods)
138
+ base.helper_method :upload_progress, :next_upload_id, :last_upload_id, :current_upload_id
139
+ end
140
+
141
+ module ClassMethods #:nodoc:
142
+ # Creates an +after_filter+ which will call +finish_upload_status+
143
+ # creating the document that will be loaded into the hidden IFRAME, terminating
144
+ # the status polling forms created with +form_with_upload_progress+.
145
+ #
146
+ # Also defines an action +upload_status+ or a action name passed as
147
+ # the <tt>:status</tt> option. This status action must match the one expected
148
+ # in the +form_tag_with_upload_progress+ helper.
149
+ #
150
+ def upload_status_for(*actions)
151
+ after_filter :finish_upload_status, :only => actions
152
+
153
+ define_method(actions.last.is_a?(Hash) && actions.last[:status] || :upload_status) do
154
+ render(:inline => '<%= upload_progress_status %>', :layout => false)
155
+ end
156
+ end
157
+ end
158
+
159
+ # Overwrites the body rendered if the upload comes from a form that tracks
160
+ # the progress of the upload. After clearing the body and any redirects, this
161
+ # method then renders the helper +finish_upload_status+
162
+ #
163
+ # This method only needs to be called if you wish to pass a
164
+ # javascript parameter to your finish event handler that you optionally
165
+ # define in +form_with_upload_progress+
166
+ #
167
+ # === Parameter:
168
+ #
169
+ # client_js_argument:: a string containing a Javascript expression that will
170
+ # be evaluated and passed to your +finish+ handler of
171
+ # +form_tag_with_upload_progress+.
172
+ #
173
+ # You can pass a String, Number or Boolean.
174
+ #
175
+ # === Strings
176
+ #
177
+ # Strings contain Javascript code that will be evaluated on the client. If you
178
+ # wish to pass a string to the client finish callback, you will need to include
179
+ # quotes in the +client_js_argument+ you pass to this method.
180
+ #
181
+ # ==== Example
182
+ #
183
+ # finish_upload_status("\"Finished\"")
184
+ # finish_upload_status("'Finished #{@document.title}'")
185
+ # finish_upload_status("{success: true, message: 'Done!'}")
186
+ # finish_upload_status("function() { alert('Uploaded!'); }")
187
+ #
188
+ # === Numbers / Booleans
189
+ #
190
+ # Numbers and Booleans can either be passed as Number objects or string versions
191
+ # of number objects as they are evaluated by Javascript the same way as in Ruby.
192
+ #
193
+ # ==== Example
194
+ #
195
+ # finish_upload_status(0)
196
+ # finish_upload_status(@document.file.size)
197
+ # finish_upload_status("10")
198
+ #
199
+ # === Nil
200
+ #
201
+ # To pass +nil+ to the finish callback, use a string "undefined"
202
+ #
203
+ # ==== Example
204
+ #
205
+ # finish_upload_status(@message || "undefined")
206
+ #
207
+ # == Redirection
208
+ #
209
+ # If you action performs a redirection then +finish_upload_status+ will recognize
210
+ # the redirection and properly create the Javascript to perform the redirection in
211
+ # the proper location.
212
+ #
213
+ # It is possible to redirect and pass a parameter to the finish callback.
214
+ #
215
+ # ==== Example
216
+ #
217
+ # redirect_to :action => 'show', :id => @document.id
218
+ # finish_upload_status("'Redirecting you to your new file'")
219
+ #
220
+ #
221
+ def finish_upload_status(client_js_argument='')
222
+ if not @rendered_finish_upload_status and params[:upload_id]
223
+ @rendered_finish_upload_status = true
224
+
225
+ erase_render_results
226
+ location = erase_redirect_results || ''
227
+
228
+ ## TODO determine if #inspect is the appropriate way to marshall values
229
+ ## in inline templates
230
+
231
+ template = "<%= finish_upload_status({"
232
+ template << ":client_js_argument => #{client_js_argument.inspect}, "
233
+ template << ":redirect_to => #{location.to_s.inspect}, "
234
+ template << "}) %>"
235
+
236
+ render({ :inline => template, :layout => false })
237
+ end
238
+ end
239
+
240
+ # Returns and saves the next unique +upload_id+ in the instance variable
241
+ # <tt>@upload_id</tt>
242
+ def next_upload_id
243
+ @upload_id = last_upload_id.succ
244
+ end
245
+
246
+ # Either returns the last saved +upload_id+ or looks in the session
247
+ # for the last used +upload_id+ and saves it as the intance variable
248
+ # <tt>@upload_id</tt>
249
+ def last_upload_id
250
+ @upload_id ||= ((session[:uploads] || {}).keys.map{|k| k.to_i}.sort.last || 0).to_s
251
+ end
252
+
253
+ # Returns the +upload_id+ from the query parameters or if it cannot be found
254
+ # in the query parameters, then return the +last_upload_id+
255
+ def current_upload_id
256
+ params[:upload_id] or last_upload_id
257
+ end
258
+
259
+ # Get the UploadProgress::Progress object for the supplied +upload_id+ from the
260
+ # session. If no +upload_id+ is given, then use the +current_upload_id+
261
+ #
262
+ # If an UploadProgress::Progress object cannot be found, a new instance will be
263
+ # returned with <code>total_bytes == 0</code>, <code>started? == false</code>,
264
+ # and <code>finished? == true</code>.
265
+ def upload_progress(upload_id = nil)
266
+ upload_id ||= current_upload_id
267
+ session[:uploads] && session[:uploads][upload_id] || UploadProgress::Progress.new(0)
268
+ end
269
+
270
+ # == THIS IS AN EXPERIMENTAL FEATURE
271
+ #
272
+ # Which means that it doesn't yet work on all systems. We're still working on full
273
+ # compatibility. It's thus not advised to use this unless you've verified it to work
274
+ # fully on all the systems that is a part of your environment. Consider this an extended
275
+ # preview.
276
+ #
277
+ # Upload Progress abstracts the progress of an upload. It's used by the
278
+ # multipart progress IO that keeps track of the upload progress and creating
279
+ # the application depends on. It contians methods to update the progress
280
+ # during an upload and read the statistics such as +received_bytes+,
281
+ # +total_bytes+, +completed_percent+, +bitrate+, and
282
+ # +remaining_seconds+
283
+ #
284
+ # You can get the current +Progress+ object by calling +upload_progress+ instance
285
+ # method in your controller or view.
286
+ #
287
+ class Progress
288
+ unless const_defined? :MIN_SAMPLE_TIME
289
+ # Number of seconds between bitrate samples. Updates that occur more
290
+ # frequently than +MIN_SAMPLE_TIME+ will not be queued until this
291
+ # time passes. This behavior gives a good balance of accuracy and load
292
+ # for both fast and slow transfers.
293
+ MIN_SAMPLE_TIME = 0.150
294
+
295
+ # Number of seconds between updates before giving up to try and calculate
296
+ # bitrate anymore
297
+ MIN_STALL_TIME = 10.0
298
+
299
+ # Number of samples used to calculate bitrate
300
+ MAX_SAMPLES = 20
301
+ end
302
+
303
+ # Number bytes received from the multipart post
304
+ attr_reader :received_bytes
305
+
306
+ # Total number of bytes expected from the mutlipart post
307
+ attr_reader :total_bytes
308
+
309
+ # The last time the upload history was updated
310
+ attr_reader :last_update_time
311
+
312
+ # A message you can set from your controller or view to be rendered in the
313
+ # +upload_status_text+ helper method. If you set a messagein a controller
314
+ # then call <code>session.update</code> to make that message available to
315
+ # your +upload_status+ action.
316
+ attr_accessor :message
317
+
318
+ # Create a new Progress object passing the expected number of bytes to receive
319
+ def initialize(total)
320
+ @total_bytes = total
321
+ reset!
322
+ end
323
+
324
+ # Resets the received_bytes, last_update_time, message and bitrate, but
325
+ # but maintains the total expected bytes
326
+ def reset!
327
+ @received_bytes, @last_update_time, @stalled, @message = 0, 0, false, ''
328
+ reset_history
329
+ end
330
+
331
+ # Number of bytes left for this upload
332
+ def remaining_bytes
333
+ @total_bytes - @received_bytes
334
+ end
335
+
336
+ # Completed percent in integer form from 0..100
337
+ def completed_percent
338
+ (@received_bytes * 100 / @total_bytes).to_i rescue 0
339
+ end
340
+
341
+ # Updates this UploadProgress object with the number of bytes received
342
+ # since last update time and the absolute number of seconds since the
343
+ # beginning of the upload.
344
+ #
345
+ # This method is used by the +MultipartProgress+ module and should
346
+ # not be called directly.
347
+ def update!(bytes, elapsed_seconds)#:nodoc:
348
+ if @received_bytes + bytes > @total_bytes
349
+ #warn "Progress#update received bytes exceeds expected bytes"
350
+ bytes = @total_bytes - @received_bytes
351
+ end
352
+
353
+ @received_bytes += bytes
354
+
355
+ # Age is the duration of time since the last update to the history
356
+ age = elapsed_seconds - @last_update_time
357
+
358
+ # Record the bytes received in the first element of the history
359
+ # in case the sample rate is exceeded and we shouldn't record at this
360
+ # time
361
+ @history.first[0] += bytes
362
+ @history.first[1] += age
363
+
364
+ history_age = @history.first[1]
365
+
366
+ @history.pop while @history.size > MAX_SAMPLES
367
+ @history.unshift([0,0]) if history_age > MIN_SAMPLE_TIME
368
+
369
+ if history_age > MIN_STALL_TIME
370
+ @stalled = true
371
+ reset_history
372
+ else
373
+ @stalled = false
374
+ end
375
+
376
+ @last_update_time = elapsed_seconds
377
+
378
+ self
379
+ end
380
+
381
+ # Calculates the bitrate in bytes/second. If the transfer is stalled or
382
+ # just started, the bitrate will be 0
383
+ def bitrate
384
+ history_bytes, history_time = @history.transpose.map { |vals| vals.inject { |sum, v| sum + v } }
385
+ history_bytes / history_time rescue 0
386
+ end
387
+
388
+ # Number of seconds elapsed since the start of the upload
389
+ def elapsed_seconds
390
+ @last_update_time
391
+ end
392
+
393
+ # Calculate the seconds remaining based on the current bitrate. Returns
394
+ # O seconds if stalled or if no bytes have been received
395
+ def remaining_seconds
396
+ remaining_bytes / bitrate rescue 0
397
+ end
398
+
399
+ # Returns true if there are bytes pending otherwise returns false
400
+ def finished?
401
+ remaining_bytes <= 0
402
+ end
403
+
404
+ # Returns true if some bytes have been received
405
+ def started?
406
+ @received_bytes > 0
407
+ end
408
+
409
+ # Returns true if there has been a delay in receiving bytes. The delay
410
+ # is set by the constant MIN_STALL_TIME
411
+ def stalled?
412
+ @stalled
413
+ end
414
+
415
+ private
416
+ def reset_history
417
+ @history = [[0,0]]
418
+ end
419
+ end
420
+ end
421
+ end
@@ -12,7 +12,7 @@ module ActionController
12
12
  end
13
13
 
14
14
  def to_str
15
- "#{@request.protocol}, #{@request.host_with_port}, #{@request.path}, #{@parameters[:controller]}, #{@parameters[:action]}, #{@request.parameters.inspect}"
15
+ "#{@request.protocol}, #{@request.host_with_port}, #{@request.path}, #{@parameters[:controller]}, #{@parameters[:action]}, #{@request.parameters.inspect}"
16
16
  end
17
17
 
18
18
  alias_method :to_s, :to_str
@@ -28,7 +28,7 @@ module ActionController
28
28
  rewritten_url << '/' if options[:trailing_slash]
29
29
  rewritten_url << "##{options[:anchor]}" if options[:anchor]
30
30
 
31
- return rewritten_url
31
+ rewritten_url
32
32
  end
33
33
 
34
34
  def rewrite_path(options)
@@ -38,17 +38,15 @@ module ActionController
38
38
  path, extras = Routing::Routes.generate(options, @request)
39
39
 
40
40
  if extras[:overwrite_params]
41
- params_copy = @request.parameters.reject { |k,v| ["controller","action"].include? k }
41
+ params_copy = @request.parameters.reject { |k,v| %w(controller action).include? k }
42
42
  params_copy.update extras[:overwrite_params]
43
43
  extras.delete(:overwrite_params)
44
44
  extras.update(params_copy)
45
45
  end
46
46
 
47
- path = "/#{path.join('/')}".chomp '/'
48
- path = '/' if path.empty?
49
- path += build_query_string(extras)
47
+ path << build_query_string(extras) unless extras.empty?
50
48
 
51
- return path
49
+ path
52
50
  end
53
51
 
54
52
  # Returns a query string with escaped keys and values from the passed hash. If the passed hash contains an "id" it'll
@@ -58,15 +56,14 @@ module ActionController
58
56
  query_string = ""
59
57
 
60
58
  hash.each do |key, value|
61
- key = key.to_s
62
- key = CGI.escape key
63
- key += '[]' if value.class == Array
59
+ key = CGI.escape key.to_s
60
+ key << '[]' if value.class == Array
64
61
  value = [ value ] unless value.class == Array
65
62
  value.each { |val| elements << "#{key}=#{Routing.extract_parameter_value(val)}" }
66
63
  end
67
64
 
68
65
  query_string << ("?" + elements.join("&")) unless elements.empty?
69
- return query_string
66
+ query_string
70
67
  end
71
68
  end
72
69
  end