actionpack 3.0.0.beta → 3.0.0.beta2
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.
- data/CHANGELOG +291 -260
- data/lib/abstract_controller.rb +5 -2
- data/lib/abstract_controller/assigns.rb +21 -0
- data/lib/abstract_controller/base.rb +13 -5
- data/lib/abstract_controller/collector.rb +2 -0
- data/lib/abstract_controller/helpers.rb +4 -14
- data/lib/abstract_controller/layouts.rb +50 -99
- data/lib/abstract_controller/logger.rb +2 -2
- data/lib/abstract_controller/rendering.rb +105 -173
- data/lib/abstract_controller/view_paths.rb +69 -0
- data/lib/action_controller.rb +1 -2
- data/lib/action_controller/base.rb +10 -32
- data/lib/action_controller/caching.rb +19 -18
- data/lib/action_controller/caching/actions.rb +17 -11
- data/lib/action_controller/caching/fragments.rb +5 -17
- data/lib/action_controller/caching/pages.rb +24 -24
- data/lib/action_controller/caching/sweeping.rb +1 -3
- data/lib/action_controller/deprecated.rb +0 -2
- data/lib/action_controller/deprecated/base.rb +143 -0
- data/lib/action_controller/metal.rb +29 -26
- data/lib/action_controller/metal/compatibility.rb +18 -87
- data/lib/action_controller/metal/cookies.rb +0 -1
- data/lib/action_controller/metal/head.rb +1 -0
- data/lib/action_controller/metal/helpers.rb +2 -2
- data/lib/action_controller/metal/hide_actions.rb +4 -6
- data/lib/action_controller/metal/http_authentication.rb +18 -33
- data/lib/action_controller/metal/implicit_render.rb +21 -0
- data/lib/action_controller/metal/instrumentation.rb +1 -1
- data/lib/action_controller/metal/mime_responds.rb +2 -1
- data/lib/action_controller/metal/rack_delegation.rb +3 -8
- data/lib/action_controller/metal/redirecting.rb +2 -1
- data/lib/action_controller/metal/renderers.rb +4 -2
- data/lib/action_controller/metal/rendering.rb +31 -44
- data/lib/action_controller/metal/request_forgery_protection.rb +41 -4
- data/lib/action_controller/metal/responder.rb +2 -0
- data/lib/action_controller/metal/session_management.rb +0 -36
- data/lib/action_controller/metal/streaming.rb +20 -47
- data/lib/action_controller/metal/testing.rb +0 -1
- data/lib/action_controller/metal/url_for.rb +11 -148
- data/lib/action_controller/middleware.rb +2 -1
- data/lib/action_controller/polymorphic_routes.rb +1 -2
- data/lib/action_controller/railtie.rb +63 -10
- data/lib/action_controller/railties/{subscriber.rb → log_subscriber.rb} +5 -12
- data/lib/action_controller/railties/url_helpers.rb +14 -0
- data/lib/action_controller/record_identifier.rb +20 -1
- data/lib/action_controller/test_case.rb +123 -12
- data/lib/action_dispatch.rb +1 -0
- data/lib/action_dispatch/http/cache.rb +20 -3
- data/lib/action_dispatch/http/filter_parameters.rb +40 -25
- data/lib/action_dispatch/http/mime_negotiation.rb +6 -17
- data/lib/action_dispatch/http/mime_type.rb +2 -7
- data/lib/action_dispatch/http/request.rb +12 -33
- data/lib/action_dispatch/http/response.rb +35 -15
- data/lib/action_dispatch/http/upload.rb +2 -0
- data/lib/action_dispatch/http/url.rb +5 -32
- data/lib/action_dispatch/middleware/callbacks.rb +1 -1
- data/lib/action_dispatch/middleware/cookies.rb +4 -3
- data/lib/action_dispatch/middleware/params_parser.rb +4 -3
- data/lib/action_dispatch/middleware/remote_ip.rb +51 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +1 -0
- data/lib/action_dispatch/middleware/session/cookie_store.rb +6 -8
- data/lib/action_dispatch/middleware/show_exceptions.rb +0 -14
- data/lib/action_dispatch/middleware/stack.rb +6 -2
- data/lib/action_dispatch/railtie.rb +3 -1
- data/lib/action_dispatch/routing.rb +2 -0
- data/lib/action_dispatch/routing/deprecated_mapper.rb +35 -7
- data/lib/action_dispatch/routing/mapper.rb +134 -48
- data/lib/action_dispatch/routing/route.rb +2 -2
- data/lib/action_dispatch/routing/route_set.rb +217 -158
- data/lib/action_dispatch/routing/url_for.rb +139 -0
- data/lib/action_dispatch/testing/assertions/response.rb +14 -61
- data/lib/action_dispatch/testing/assertions/routing.rb +25 -14
- data/lib/action_dispatch/testing/integration.rb +32 -50
- data/lib/action_dispatch/testing/performance_test.rb +3 -1
- data/lib/action_dispatch/testing/test_process.rb +2 -0
- data/lib/action_dispatch/testing/test_request.rb +2 -0
- data/lib/action_pack/version.rb +4 -3
- data/lib/action_view.rb +11 -6
- data/lib/action_view/base.rb +33 -121
- data/lib/action_view/context.rb +0 -2
- data/lib/action_view/helpers.rb +26 -23
- data/lib/action_view/helpers/active_model_helper.rb +28 -18
- data/lib/action_view/helpers/asset_tag_helper.rb +109 -54
- data/lib/action_view/helpers/atom_feed_helper.rb +2 -2
- data/lib/action_view/helpers/cache_helper.rb +22 -1
- data/lib/action_view/helpers/capture_helper.rb +22 -22
- data/lib/action_view/helpers/date_helper.rb +6 -5
- data/lib/action_view/helpers/form_helper.rb +78 -63
- data/lib/action_view/helpers/form_options_helper.rb +6 -4
- data/lib/action_view/helpers/form_tag_helper.rb +26 -15
- data/lib/action_view/helpers/javascript_helper.rb +90 -10
- data/lib/action_view/helpers/number_helper.rb +315 -118
- data/lib/action_view/helpers/prototype_helper.rb +19 -46
- data/lib/action_view/helpers/record_tag_helper.rb +4 -4
- data/lib/action_view/helpers/tag_helper.rb +7 -24
- data/lib/action_view/helpers/text_helper.rb +8 -7
- data/lib/action_view/helpers/translation_helper.rb +7 -5
- data/lib/action_view/helpers/url_helper.rb +19 -16
- data/lib/action_view/locale/en.yml +45 -6
- data/lib/action_view/lookup_context.rb +190 -0
- data/lib/action_view/paths.rb +22 -63
- data/lib/action_view/railtie.rb +14 -4
- data/lib/action_view/railties/{subscriber.rb → log_subscriber.rb} +1 -1
- data/lib/action_view/render/layouts.rb +73 -0
- data/lib/action_view/render/partials.rb +15 -41
- data/lib/action_view/render/rendering.rb +27 -78
- data/lib/action_view/template.rb +20 -24
- data/lib/action_view/template/error.rb +22 -2
- data/lib/action_view/template/handlers/erb.rb +33 -9
- data/lib/action_view/template/handlers/rjs.rb +1 -2
- data/lib/action_view/template/resolver.rb +46 -104
- data/lib/action_view/template/text.rb +5 -12
- data/lib/action_view/test_case.rb +14 -23
- metadata +83 -40
- data/lib/abstract_controller/compatibility.rb +0 -18
- data/lib/abstract_controller/localized_cache.rb +0 -49
- data/lib/action_controller/metal/configuration.rb +0 -28
- data/lib/action_controller/url_rewriter.rb +0 -76
@@ -4,7 +4,7 @@ module ActionDispatch
|
|
4
4
|
attr_reader :app, :conditions, :defaults, :name
|
5
5
|
attr_reader :path, :requirements
|
6
6
|
|
7
|
-
def initialize(app, conditions
|
7
|
+
def initialize(app, conditions, requirements, defaults, name, anchor)
|
8
8
|
@app = app
|
9
9
|
@defaults = defaults
|
10
10
|
@name = name
|
@@ -17,7 +17,7 @@ module ActionDispatch
|
|
17
17
|
|
18
18
|
if path = conditions[:path_info]
|
19
19
|
@path = path
|
20
|
-
conditions[:path_info] = ::Rack::Mount::Strexp.compile(path, requirements, SEPARATORS)
|
20
|
+
conditions[:path_info] = ::Rack::Mount::Strexp.compile(path, requirements, SEPARATORS, anchor)
|
21
21
|
end
|
22
22
|
|
23
23
|
@conditions = conditions.inject({}) { |h, (k, v)|
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'rack/mount'
|
2
2
|
require 'forwardable'
|
3
|
+
require 'action_dispatch/routing/deprecated_mapper'
|
3
4
|
|
4
5
|
module ActionDispatch
|
5
6
|
module Routing
|
@@ -11,8 +12,8 @@ module ActionDispatch
|
|
11
12
|
PARAMETERS_KEY = 'action_dispatch.request.path_parameters'
|
12
13
|
|
13
14
|
class Dispatcher
|
14
|
-
def initialize(options
|
15
|
-
defaults = options[:defaults]
|
15
|
+
def initialize(options={})
|
16
|
+
@defaults = options[:defaults]
|
16
17
|
@glob_param = options.delete(:glob)
|
17
18
|
end
|
18
19
|
|
@@ -20,7 +21,8 @@ module ActionDispatch
|
|
20
21
|
params = env[PARAMETERS_KEY]
|
21
22
|
prepare_params!(params)
|
22
23
|
|
23
|
-
|
24
|
+
# Just raise undefined constant errors if a controller was specified as default.
|
25
|
+
unless controller = controller(params, @defaults.key?(:controller))
|
24
26
|
return [404, {'X-Cascade' => 'pass'}, []]
|
25
27
|
end
|
26
28
|
|
@@ -39,13 +41,13 @@ module ActionDispatch
|
|
39
41
|
end
|
40
42
|
end
|
41
43
|
|
42
|
-
def controller(params)
|
44
|
+
def controller(params, raise_error=true)
|
43
45
|
if params && params.has_key?(:controller)
|
44
46
|
controller = "#{params[:controller].camelize}Controller"
|
45
47
|
ActiveSupport::Inflector.constantize(controller)
|
46
48
|
end
|
47
|
-
rescue NameError
|
48
|
-
|
49
|
+
rescue NameError => e
|
50
|
+
raise ActionController::RoutingError, e.message, e.backtrace if raise_error
|
49
51
|
end
|
50
52
|
|
51
53
|
private
|
@@ -58,13 +60,12 @@ module ActionDispatch
|
|
58
60
|
end
|
59
61
|
end
|
60
62
|
|
61
|
-
|
62
63
|
# A NamedRouteCollection instance is a collection of named routes, and also
|
63
64
|
# maintains an anonymous module that can be used to install helpers for the
|
64
65
|
# named routes.
|
65
66
|
class NamedRouteCollection #:nodoc:
|
66
67
|
include Enumerable
|
67
|
-
attr_reader :routes, :helpers
|
68
|
+
attr_reader :routes, :helpers, :module
|
68
69
|
|
69
70
|
def initialize
|
70
71
|
clear!
|
@@ -167,51 +168,13 @@ module ActionDispatch
|
|
167
168
|
selector = url_helper_name(name, kind)
|
168
169
|
hash_access_method = hash_access_name(name, kind)
|
169
170
|
|
170
|
-
# We use module_eval to avoid leaks.
|
171
|
-
#
|
172
|
-
# def users_url(*args)
|
173
|
-
# if args.empty? || Hash === args.first
|
174
|
-
# options = hash_for_users_url(args.first || {})
|
175
|
-
# else
|
176
|
-
# options = hash_for_users_url(args.extract_options!)
|
177
|
-
# default = default_url_options(options) if self.respond_to?(:default_url_options, true)
|
178
|
-
# options = (default ||= {}).merge(options)
|
179
|
-
#
|
180
|
-
# keys = []
|
181
|
-
# keys -= options.keys if args.size < keys.size - 1
|
182
|
-
#
|
183
|
-
# args = args.zip(keys).inject({}) do |h, (v, k)|
|
184
|
-
# h[k] = v
|
185
|
-
# h
|
186
|
-
# end
|
187
|
-
#
|
188
|
-
# # Tell url_for to skip default_url_options
|
189
|
-
# options[:use_defaults] = false
|
190
|
-
# options.merge!(args)
|
191
|
-
# end
|
192
|
-
#
|
193
|
-
# url_for(options)
|
194
|
-
# end
|
195
171
|
@module.module_eval <<-END_EVAL, __FILE__, __LINE__ + 1
|
196
172
|
def #{selector}(*args)
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
options =
|
201
|
-
|
202
|
-
options = (default ||= {}).merge(options)
|
203
|
-
|
204
|
-
keys = #{route.segment_keys.inspect}
|
205
|
-
keys -= options.keys if args.size < keys.size - 1 # take format into account
|
206
|
-
|
207
|
-
args = args.zip(keys).inject({}) do |h, (v, k)|
|
208
|
-
h[k] = v
|
209
|
-
h
|
210
|
-
end
|
211
|
-
|
212
|
-
# Tell url_for to skip default_url_options
|
213
|
-
options[:use_defaults] = false
|
214
|
-
options.merge!(args)
|
173
|
+
options = #{hash_access_method}(args.extract_options!)
|
174
|
+
|
175
|
+
if args.any?
|
176
|
+
options[:_positional_args] = args
|
177
|
+
options[:_positional_keys] = #{route.segment_keys.inspect}
|
215
178
|
end
|
216
179
|
|
217
180
|
url_for(options)
|
@@ -222,8 +185,9 @@ module ActionDispatch
|
|
222
185
|
end
|
223
186
|
end
|
224
187
|
|
225
|
-
attr_accessor :routes, :named_routes
|
188
|
+
attr_accessor :routes, :named_routes
|
226
189
|
attr_accessor :disable_clear_and_finalize, :resources_path_names
|
190
|
+
attr_accessor :default_url_options
|
227
191
|
|
228
192
|
def self.default_resources_path_names
|
229
193
|
{ :new => 'new', :edit => 'edit' }
|
@@ -234,8 +198,10 @@ module ActionDispatch
|
|
234
198
|
self.named_routes = NamedRouteCollection.new
|
235
199
|
self.resources_path_names = self.class.default_resources_path_names.dup
|
236
200
|
self.controller_namespaces = Set.new
|
201
|
+
self.default_url_options = {}
|
237
202
|
|
238
203
|
@disable_clear_and_finalize = false
|
204
|
+
clear!
|
239
205
|
end
|
240
206
|
|
241
207
|
def draw(&block)
|
@@ -254,14 +220,16 @@ module ActionDispatch
|
|
254
220
|
end
|
255
221
|
|
256
222
|
def finalize!
|
223
|
+
return if @finalized
|
224
|
+
@finalized = true
|
257
225
|
@set.add_route(NotFound)
|
258
|
-
install_helpers
|
259
226
|
@set.freeze
|
260
227
|
end
|
261
228
|
|
262
229
|
def clear!
|
263
230
|
# Clear the controller cache so we may discover new ones
|
264
231
|
@controller_constraints = nil
|
232
|
+
@finalized = false
|
265
233
|
routes.clear
|
266
234
|
named_routes.clear
|
267
235
|
@set = ::Rack::Mount::RouteSet.new(:parameters_key => PARAMETERS_KEY)
|
@@ -272,61 +240,164 @@ module ActionDispatch
|
|
272
240
|
named_routes.install(destinations, regenerate_code)
|
273
241
|
end
|
274
242
|
|
275
|
-
def
|
276
|
-
|
277
|
-
|
243
|
+
def url_helpers
|
244
|
+
@url_helpers ||= begin
|
245
|
+
routes = self
|
278
246
|
|
279
|
-
|
247
|
+
helpers = Module.new do
|
248
|
+
extend ActiveSupport::Concern
|
249
|
+
include UrlFor
|
250
|
+
|
251
|
+
@routes = routes
|
252
|
+
class << self
|
253
|
+
delegate :url_for, :to => '@routes'
|
254
|
+
end
|
255
|
+
extend routes.named_routes.module
|
256
|
+
|
257
|
+
# ROUTES TODO: install_helpers isn't great... can we make a module with the stuff that
|
258
|
+
# we can include?
|
259
|
+
# Yes plz - JP
|
260
|
+
included do
|
261
|
+
routes.install_helpers(self)
|
262
|
+
singleton_class.send(:define_method, :_router) { routes }
|
263
|
+
end
|
264
|
+
|
265
|
+
define_method(:_router) { routes }
|
266
|
+
end
|
280
267
|
|
281
|
-
|
282
|
-
@controller_constraints ||= begin
|
283
|
-
namespaces = controller_namespaces + in_memory_controller_namespaces
|
284
|
-
source = namespaces.map { |ns| "#{Regexp.escape(ns)}/#{CONTROLLER_REGEXP.source}" }
|
285
|
-
source << CONTROLLER_REGEXP.source
|
286
|
-
Regexp.compile(source.sort.reverse.join('|'))
|
268
|
+
helpers
|
287
269
|
end
|
288
270
|
end
|
289
271
|
|
290
|
-
def
|
291
|
-
|
292
|
-
ActionController::Base.subclasses.each do |klass|
|
293
|
-
controller_name = klass.underscore
|
294
|
-
namespaces << controller_name.split('/')[0...-1].join('/')
|
295
|
-
end
|
296
|
-
namespaces.delete('')
|
297
|
-
namespaces
|
272
|
+
def empty?
|
273
|
+
routes.empty?
|
298
274
|
end
|
299
275
|
|
300
|
-
def add_route(app, conditions = {}, requirements = {}, defaults = {}, name = nil)
|
301
|
-
route = Route.new(app, conditions, requirements, defaults, name)
|
276
|
+
def add_route(app, conditions = {}, requirements = {}, defaults = {}, name = nil, anchor = true)
|
277
|
+
route = Route.new(app, conditions, requirements, defaults, name, anchor)
|
302
278
|
@set.add_route(*route)
|
303
279
|
named_routes[name] = route if name
|
304
280
|
routes << route
|
305
281
|
route
|
306
282
|
end
|
307
283
|
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
284
|
+
class Generator
|
285
|
+
attr_reader :options, :recall, :set, :script_name, :named_route
|
286
|
+
|
287
|
+
def initialize(options, recall, set, extras = false)
|
288
|
+
@script_name = options.delete(:script_name)
|
289
|
+
@named_route = options.delete(:use_route)
|
290
|
+
@options = options.dup
|
291
|
+
@recall = recall.dup
|
292
|
+
@set = set
|
293
|
+
@extras = extras
|
294
|
+
|
295
|
+
normalize_options!
|
296
|
+
normalize_controller_action_id!
|
297
|
+
use_relative_controller!
|
298
|
+
controller.sub!(%r{^/}, '') if controller
|
299
|
+
handle_nil_action!
|
300
|
+
end
|
301
|
+
|
302
|
+
def controller
|
303
|
+
@controller ||= @options[:controller]
|
304
|
+
end
|
305
|
+
|
306
|
+
def current_controller
|
307
|
+
@recall[:controller]
|
308
|
+
end
|
309
|
+
|
310
|
+
def use_recall_for(key)
|
311
|
+
if @recall[key] && (!@options.key?(key) || @options[key] == @recall[key])
|
312
|
+
@options[key] = @recall.delete(key)
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
def normalize_options!
|
317
|
+
# If an explicit :controller was given, always make :action explicit
|
318
|
+
# too, so that action expiry works as expected for things like
|
319
|
+
#
|
320
|
+
# generate({:controller => 'content'}, {:controller => 'content', :action => 'show'})
|
321
|
+
#
|
322
|
+
# (the above is from the unit tests). In the above case, because the
|
323
|
+
# controller was explicitly given, but no action, the action is implied to
|
324
|
+
# be "index", not the recalled action of "show".
|
325
|
+
|
326
|
+
if options[:controller]
|
327
|
+
options[:action] ||= 'index'
|
328
|
+
options[:controller] = options[:controller].to_s
|
329
|
+
end
|
330
|
+
|
331
|
+
if options[:action]
|
332
|
+
options[:action] = options[:action].to_s
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
# This pulls :controller, :action, and :id out of the recall.
|
337
|
+
# The recall key is only used if there is no key in the options
|
338
|
+
# or if the key in the options is identical. If any of
|
339
|
+
# :controller, :action or :id is not found, don't pull any
|
340
|
+
# more keys from the recall.
|
341
|
+
def normalize_controller_action_id!
|
342
|
+
@recall[:action] ||= 'index' if current_controller
|
343
|
+
|
344
|
+
use_recall_for(:controller) or return
|
345
|
+
use_recall_for(:action) or return
|
346
|
+
use_recall_for(:id)
|
347
|
+
end
|
348
|
+
|
349
|
+
# if the current controller is "foo/bar/baz" and :controller => "baz/bat"
|
350
|
+
# is specified, the controller becomes "foo/baz/bat"
|
351
|
+
def use_relative_controller!
|
352
|
+
if !named_route && different_controller?
|
353
|
+
old_parts = current_controller.split('/')
|
354
|
+
size = controller.count("/") + 1
|
355
|
+
parts = old_parts[0...-size] << controller
|
356
|
+
@controller = @options[:controller] = parts.join("/")
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
# This handles the case of :action => nil being explicitly passed.
|
361
|
+
# It is identical to :action => "index"
|
362
|
+
def handle_nil_action!
|
363
|
+
if options.has_key?(:action) && options[:action].nil?
|
364
|
+
options[:action] = 'index'
|
365
|
+
end
|
366
|
+
recall[:action] = options.delete(:action) if options[:action] == 'index'
|
367
|
+
end
|
368
|
+
|
369
|
+
def generate
|
370
|
+
error = ActionController::RoutingError.new("No route matches #{options.inspect}")
|
371
|
+
path, params = @set.generate(:path_info, named_route, options, recall, opts)
|
372
|
+
|
373
|
+
raise error unless path
|
374
|
+
|
375
|
+
params.reject! {|k,v| !v }
|
376
|
+
|
377
|
+
return [path, params.keys] if @extras
|
325
378
|
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
379
|
+
path << "?#{params.to_query}" if params.any?
|
380
|
+
"#{script_name}#{path}"
|
381
|
+
rescue Rack::Mount::RoutingError
|
382
|
+
raise error
|
383
|
+
end
|
384
|
+
|
385
|
+
def opts
|
386
|
+
parameterize = lambda do |name, value|
|
387
|
+
if name == :controller
|
388
|
+
value
|
389
|
+
elsif value.is_a?(Array)
|
390
|
+
value.map { |v| Rack::Mount::Utils.escape_uri(v.to_param) }.join('/')
|
391
|
+
else
|
392
|
+
Rack::Mount::Utils.escape_uri(value.to_param)
|
393
|
+
end
|
394
|
+
end
|
395
|
+
{:parameterize => parameterize}
|
396
|
+
end
|
397
|
+
|
398
|
+
def different_controller?
|
399
|
+
return false unless current_controller
|
400
|
+
controller.to_param != current_controller.to_param
|
330
401
|
end
|
331
402
|
end
|
332
403
|
|
@@ -337,85 +408,49 @@ module ActionDispatch
|
|
337
408
|
end
|
338
409
|
|
339
410
|
def generate_extras(options, recall={})
|
340
|
-
generate(options, recall,
|
411
|
+
generate(options, recall, true)
|
341
412
|
end
|
342
413
|
|
343
|
-
def generate(options, recall = {},
|
344
|
-
options, recall
|
345
|
-
|
414
|
+
def generate(options, recall = {}, extras = false)
|
415
|
+
Generator.new(options, recall, @set, extras).generate
|
416
|
+
end
|
346
417
|
|
347
|
-
|
348
|
-
expire_on = build_expiry(options, recall)
|
418
|
+
RESERVED_OPTIONS = [:anchor, :params, :only_path, :host, :protocol, :port, :trailing_slash]
|
349
419
|
|
350
|
-
|
420
|
+
def url_for(options)
|
421
|
+
finalize!
|
422
|
+
options = default_url_options.merge(options || {})
|
351
423
|
|
352
|
-
|
353
|
-
options[:controller] = recall.delete(:controller)
|
424
|
+
handle_positional_args(options)
|
354
425
|
|
355
|
-
|
356
|
-
options[:action] = recall.delete(:action)
|
426
|
+
rewritten_url = ""
|
357
427
|
|
358
|
-
|
359
|
-
options[:id] = recall.delete(:id)
|
360
|
-
end
|
361
|
-
end
|
362
|
-
end
|
363
|
-
|
364
|
-
options[:controller] = options[:controller].to_s if options[:controller]
|
428
|
+
path_segments = options.delete(:_path_segments)
|
365
429
|
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
options[:controller] = parts.join('/')
|
371
|
-
end
|
430
|
+
unless options[:only_path]
|
431
|
+
rewritten_url << (options[:protocol] || "http")
|
432
|
+
rewritten_url << "://" unless rewritten_url.match("://")
|
433
|
+
rewritten_url << rewrite_authentication(options)
|
372
434
|
|
373
|
-
|
435
|
+
raise "Missing host to link to! Please provide :host parameter or set default_url_options[:host]" unless options[:host]
|
374
436
|
|
375
|
-
|
376
|
-
|
377
|
-
options.delete(:action)
|
378
|
-
recall[:action] = 'index'
|
437
|
+
rewritten_url << options[:host]
|
438
|
+
rewritten_url << ":#{options.delete(:port)}" if options.key?(:port)
|
379
439
|
end
|
380
|
-
recall[:action] = options.delete(:action) if options[:action] == 'index'
|
381
|
-
|
382
|
-
opts = {}
|
383
|
-
opts[:parameterize] = lambda { |name, value|
|
384
|
-
if name == :controller
|
385
|
-
value
|
386
|
-
elsif value.is_a?(Array)
|
387
|
-
value.map { |v| Rack::Mount::Utils.escape_uri(v.to_param) }.join('/')
|
388
|
-
else
|
389
|
-
Rack::Mount::Utils.escape_uri(value.to_param)
|
390
|
-
end
|
391
|
-
}
|
392
440
|
|
393
|
-
|
394
|
-
|
395
|
-
|
441
|
+
path_options = options.except(*RESERVED_OPTIONS)
|
442
|
+
path_options = yield(path_options) if block_given?
|
443
|
+
path = generate(path_options, path_segments || {})
|
396
444
|
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
params[k] = v
|
401
|
-
else
|
402
|
-
params.delete(k)
|
403
|
-
end
|
404
|
-
end
|
445
|
+
# ROUTES TODO: This can be called directly, so script_name should probably be set in the router
|
446
|
+
rewritten_url << (options[:trailing_slash] ? path.sub(/\?|\z/) { "/" + $& } : path)
|
447
|
+
rewritten_url << "##{Rack::Utils.escape(options[:anchor].to_param.to_s)}" if options[:anchor]
|
405
448
|
|
406
|
-
|
407
|
-
[path, params.keys]
|
408
|
-
elsif path
|
409
|
-
path << "?#{params.to_query}" if params.any?
|
410
|
-
path
|
411
|
-
else
|
412
|
-
raise ActionController::RoutingError, "No route matches #{options.inspect}"
|
413
|
-
end
|
414
|
-
rescue Rack::Mount::RoutingError
|
415
|
-
raise ActionController::RoutingError, "No route matches #{options.inspect}"
|
449
|
+
rewritten_url
|
416
450
|
end
|
417
451
|
|
418
452
|
def call(env)
|
453
|
+
finalize!
|
419
454
|
@set.call(env)
|
420
455
|
end
|
421
456
|
|
@@ -430,9 +465,9 @@ module ActionDispatch
|
|
430
465
|
end
|
431
466
|
|
432
467
|
req = Rack::Request.new(env)
|
433
|
-
@set.recognize(req) do |route, params|
|
468
|
+
@set.recognize(req) do |route, matches, params|
|
434
469
|
dispatcher = route.app
|
435
|
-
if dispatcher.is_a?(Dispatcher) && dispatcher.controller(params)
|
470
|
+
if dispatcher.is_a?(Dispatcher) && dispatcher.controller(params, false)
|
436
471
|
dispatcher.prepare_params!(params)
|
437
472
|
return params
|
438
473
|
end
|
@@ -440,6 +475,30 @@ module ActionDispatch
|
|
440
475
|
|
441
476
|
raise ActionController::RoutingError, "No route matches #{path.inspect}"
|
442
477
|
end
|
478
|
+
|
479
|
+
private
|
480
|
+
def handle_positional_args(options)
|
481
|
+
return unless args = options.delete(:_positional_args)
|
482
|
+
|
483
|
+
keys = options.delete(:_positional_keys)
|
484
|
+
keys -= options.keys if args.size < keys.size - 1 # take format into account
|
485
|
+
|
486
|
+
args = args.zip(keys).inject({}) do |h, (v, k)|
|
487
|
+
h[k] = v
|
488
|
+
h
|
489
|
+
end
|
490
|
+
|
491
|
+
# Tell url_for to skip default_url_options
|
492
|
+
options.merge!(args)
|
493
|
+
end
|
494
|
+
|
495
|
+
def rewrite_authentication(options)
|
496
|
+
if options[:user] && options[:password]
|
497
|
+
"#{Rack::Utils.escape(options.delete(:user))}:#{Rack::Utils.escape(options.delete(:password))}@"
|
498
|
+
else
|
499
|
+
""
|
500
|
+
end
|
501
|
+
end
|
443
502
|
end
|
444
503
|
end
|
445
504
|
end
|