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
@@ -5,20 +5,6 @@ require 'action_dispatch/http/request'
|
|
5
5
|
module ActionDispatch
|
6
6
|
# This middleware rescues any exception returned by the application and renders
|
7
7
|
# nice exception pages if it's being rescued locally.
|
8
|
-
#
|
9
|
-
# Every time an exception is caught, a notification is published, becoming a good API
|
10
|
-
# to deal with exceptions. So, if you want send an e-mail through ActionMailer
|
11
|
-
# everytime this notification is published, you just need to do the following:
|
12
|
-
#
|
13
|
-
# ActiveSupport::Notifications.subscribe "action_dispatch.show_exception" do |name, start, end, instrumentation_id, payload|
|
14
|
-
# ExceptionNotifier.deliver_exception(start, payload)
|
15
|
-
# end
|
16
|
-
#
|
17
|
-
# The payload is a hash which has two pairs:
|
18
|
-
#
|
19
|
-
# * :env - Contains the rack env for the given request;
|
20
|
-
# * :exception - The exception raised;
|
21
|
-
#
|
22
8
|
class ShowExceptions
|
23
9
|
LOCALHOST = ['127.0.0.1', '::1'].freeze
|
24
10
|
|
@@ -58,7 +58,7 @@ module ActionDispatch
|
|
58
58
|
if lazy_compare?(@klass) && lazy_compare?(middleware)
|
59
59
|
normalize(@klass) == normalize(middleware)
|
60
60
|
else
|
61
|
-
klass ==
|
61
|
+
klass.name == middleware.to_s
|
62
62
|
end
|
63
63
|
end
|
64
64
|
end
|
@@ -122,7 +122,11 @@ module ActionDispatch
|
|
122
122
|
find_all { |middleware| middleware.active? }
|
123
123
|
end
|
124
124
|
|
125
|
-
def build(app)
|
125
|
+
def build(app = nil, &blk)
|
126
|
+
app ||= blk
|
127
|
+
|
128
|
+
raise "MiddlewareStack#build requires an app" unless app
|
129
|
+
|
126
130
|
active.reverse.inject(app) { |a, e| e.build(a) }
|
127
131
|
end
|
128
132
|
end
|
@@ -3,7 +3,9 @@ require "rails"
|
|
3
3
|
|
4
4
|
module ActionDispatch
|
5
5
|
class Railtie < Rails::Railtie
|
6
|
-
|
6
|
+
config.action_dispatch = ActiveSupport::OrderedOptions.new
|
7
|
+
config.action_dispatch.x_sendfile_header = ""
|
8
|
+
config.action_dispatch.ip_spoofing_check = true
|
7
9
|
|
8
10
|
# Prepare dispatcher callbacks and run 'prepare' callbacks
|
9
11
|
initializer "action_dispatch.prepare_dispatcher" do |app|
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'active_support/core_ext/object/to_param'
|
2
2
|
require 'active_support/core_ext/regexp'
|
3
|
+
require 'action_controller/polymorphic_routes'
|
3
4
|
|
4
5
|
module ActionDispatch
|
5
6
|
# == Routing
|
@@ -205,6 +206,7 @@ module ActionDispatch
|
|
205
206
|
autoload :Mapper, 'action_dispatch/routing/mapper'
|
206
207
|
autoload :Route, 'action_dispatch/routing/route'
|
207
208
|
autoload :RouteSet, 'action_dispatch/routing/route_set'
|
209
|
+
autoload :UrlFor, 'action_dispatch/routing/url_for'
|
208
210
|
|
209
211
|
SEPARATORS = %w( / . ? )
|
210
212
|
HTTP_METHODS = [:get, :head, :post, :put, :delete, :options]
|
@@ -1,5 +1,32 @@
|
|
1
|
+
require 'active_support/core_ext/object/blank'
|
2
|
+
|
1
3
|
module ActionDispatch
|
2
4
|
module Routing
|
5
|
+
class RouteSet
|
6
|
+
attr_accessor :controller_namespaces
|
7
|
+
|
8
|
+
CONTROLLER_REGEXP = /[_a-zA-Z0-9]+/
|
9
|
+
|
10
|
+
def controller_constraints
|
11
|
+
@controller_constraints ||= begin
|
12
|
+
namespaces = controller_namespaces + in_memory_controller_namespaces
|
13
|
+
source = namespaces.map { |ns| "#{Regexp.escape(ns)}/#{CONTROLLER_REGEXP.source}" }
|
14
|
+
source << CONTROLLER_REGEXP.source
|
15
|
+
Regexp.compile(source.sort.reverse.join('|'))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def in_memory_controller_namespaces
|
20
|
+
namespaces = Set.new
|
21
|
+
ActionController::Base.subclasses.each do |klass|
|
22
|
+
controller_name = klass.underscore
|
23
|
+
namespaces << controller_name.split('/')[0...-1].join('/')
|
24
|
+
end
|
25
|
+
namespaces.delete('')
|
26
|
+
namespaces
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
3
30
|
# Mapper instances are used to build routes. The object passed to the draw
|
4
31
|
# block in config/routes.rb is a Mapper instance.
|
5
32
|
#
|
@@ -244,14 +271,15 @@ module ActionDispatch
|
|
244
271
|
attr_reader :collection_methods, :member_methods, :new_methods
|
245
272
|
attr_reader :path_prefix, :name_prefix, :path_segment
|
246
273
|
attr_reader :plural, :singular
|
247
|
-
attr_reader :options
|
274
|
+
attr_reader :options, :defaults
|
248
275
|
|
249
|
-
def initialize(entities, options)
|
276
|
+
def initialize(entities, options, defaults)
|
250
277
|
@plural ||= entities
|
251
278
|
@singular ||= options[:singular] || plural.to_s.singularize
|
252
279
|
@path_segment = options.delete(:as) || @plural
|
253
280
|
|
254
281
|
@options = options
|
282
|
+
@defaults = defaults
|
255
283
|
|
256
284
|
arrange_actions
|
257
285
|
add_default_actions
|
@@ -280,7 +308,7 @@ module ActionDispatch
|
|
280
308
|
|
281
309
|
def new_path
|
282
310
|
new_action = self.options[:path_names][:new] if self.options[:path_names]
|
283
|
-
new_action ||=
|
311
|
+
new_action ||= self.defaults[:path_names][:new]
|
284
312
|
@new_path ||= "#{path}/#{new_action}"
|
285
313
|
end
|
286
314
|
|
@@ -370,7 +398,7 @@ module ActionDispatch
|
|
370
398
|
end
|
371
399
|
|
372
400
|
class SingletonResource < Resource #:nodoc:
|
373
|
-
def initialize(entity, options)
|
401
|
+
def initialize(entity, options, defaults)
|
374
402
|
@singular = @plural = entity
|
375
403
|
options[:controller] ||= @singular.to_s.pluralize
|
376
404
|
super
|
@@ -717,7 +745,7 @@ module ActionDispatch
|
|
717
745
|
|
718
746
|
private
|
719
747
|
def map_resource(entities, options = {}, &block)
|
720
|
-
resource = Resource.new(entities, options)
|
748
|
+
resource = Resource.new(entities, options, :path_names => @set.resources_path_names)
|
721
749
|
|
722
750
|
with_options :controller => resource.controller do |map|
|
723
751
|
map_associations(resource, options)
|
@@ -734,7 +762,7 @@ module ActionDispatch
|
|
734
762
|
end
|
735
763
|
|
736
764
|
def map_singleton_resource(entities, options = {}, &block)
|
737
|
-
resource = SingletonResource.new(entities, options)
|
765
|
+
resource = SingletonResource.new(entities, options, :path_names => @set.resources_path_names)
|
738
766
|
|
739
767
|
with_options :controller => resource.controller do |map|
|
740
768
|
map_associations(resource, options)
|
@@ -826,7 +854,7 @@ module ActionDispatch
|
|
826
854
|
actions.each do |action|
|
827
855
|
[method].flatten.each do |m|
|
828
856
|
action_path = resource.options[:path_names][action] if resource.options[:path_names].is_a?(Hash)
|
829
|
-
action_path ||=
|
857
|
+
action_path ||= @set.resources_path_names[action] || action
|
830
858
|
|
831
859
|
map_resource_routes(map, resource, action, "#{resource.member_path}#{resource.action_separator}#{action_path}", "#{action}_#{resource.shallow_name_prefix}#{resource.singular}", m, { :force_id => true })
|
832
860
|
end
|
@@ -1,3 +1,6 @@
|
|
1
|
+
require 'active_support/core_ext/hash/except'
|
2
|
+
require 'active_support/core_ext/object/blank'
|
3
|
+
|
1
4
|
module ActionDispatch
|
2
5
|
module Routing
|
3
6
|
class Mapper
|
@@ -30,31 +33,36 @@ module ActionDispatch
|
|
30
33
|
end
|
31
34
|
|
32
35
|
class Mapping
|
36
|
+
IGNORE_OPTIONS = [:to, :as, :controller, :action, :via, :on, :constraints, :defaults, :only, :except, :anchor]
|
37
|
+
|
33
38
|
def initialize(set, scope, args)
|
34
39
|
@set, @scope = set, scope
|
35
40
|
@path, @options = extract_path_and_options(args)
|
36
41
|
end
|
37
42
|
|
38
43
|
def to_route
|
39
|
-
[ app, conditions, requirements, defaults, @options[:as] ]
|
44
|
+
[ app, conditions, requirements, defaults, @options[:as], @options[:anchor] ]
|
40
45
|
end
|
41
46
|
|
42
47
|
private
|
43
48
|
def extract_path_and_options(args)
|
44
49
|
options = args.extract_options!
|
45
50
|
|
46
|
-
|
47
|
-
when using_to_shorthand?(args, options)
|
51
|
+
if using_to_shorthand?(args, options)
|
48
52
|
path, to = options.find { |name, value| name.is_a?(String) }
|
49
53
|
options.merge!(:to => to).delete(path) if path
|
50
|
-
when using_match_shorthand?(args, options)
|
51
|
-
path = args.first
|
52
|
-
options = { :to => path.gsub("/", "#"), :as => path.gsub("/", "_") }
|
53
54
|
else
|
54
55
|
path = args.first
|
55
56
|
end
|
56
57
|
|
57
|
-
|
58
|
+
path = normalize_path(path)
|
59
|
+
|
60
|
+
if using_match_shorthand?(path, options)
|
61
|
+
options[:to] ||= path[1..-1].sub(%r{/([^/]*)$}, '#\1')
|
62
|
+
options[:as] ||= path[1..-1].gsub("/", "_")
|
63
|
+
end
|
64
|
+
|
65
|
+
[ path, options ]
|
58
66
|
end
|
59
67
|
|
60
68
|
# match "account" => "account#index"
|
@@ -63,14 +71,13 @@ module ActionDispatch
|
|
63
71
|
end
|
64
72
|
|
65
73
|
# match "account/overview"
|
66
|
-
def using_match_shorthand?(
|
67
|
-
|
74
|
+
def using_match_shorthand?(path, options)
|
75
|
+
path && options.except(:via, :anchor, :to, :as).empty? && path =~ %r{^/[\w\/]+$}
|
68
76
|
end
|
69
77
|
|
70
78
|
def normalize_path(path)
|
71
|
-
path
|
72
|
-
|
73
|
-
Mapper.normalize_path(path)
|
79
|
+
raise ArgumentError, "path is required" if @scope[:path].blank? && path.blank?
|
80
|
+
Mapper.normalize_path("#{@scope[:path]}/#{path}")
|
74
81
|
end
|
75
82
|
|
76
83
|
def app
|
@@ -85,15 +92,22 @@ module ActionDispatch
|
|
85
92
|
end
|
86
93
|
|
87
94
|
def requirements
|
88
|
-
@requirements ||=
|
95
|
+
@requirements ||= (@options[:constraints] || {}).tap do |requirements|
|
89
96
|
requirements.reverse_merge!(@scope[:constraints]) if @scope[:constraints]
|
90
97
|
@options.each { |k, v| requirements[k] = v if v.is_a?(Regexp) }
|
91
|
-
requirements[:controller] ||= @set.controller_constraints
|
92
98
|
end
|
93
99
|
end
|
94
100
|
|
95
101
|
def defaults
|
96
|
-
@defaults ||=
|
102
|
+
@defaults ||= (@options[:defaults] || {}).tap do |defaults|
|
103
|
+
defaults.merge!(default_controller_and_action)
|
104
|
+
defaults.reverse_merge!(@scope[:defaults]) if @scope[:defaults]
|
105
|
+
@options.each { |k, v| defaults[k] = v unless v.is_a?(Regexp) || IGNORE_OPTIONS.include?(k.to_sym) }
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def default_controller_and_action
|
110
|
+
if to.respond_to?(:call)
|
97
111
|
{ }
|
98
112
|
else
|
99
113
|
defaults = case to
|
@@ -143,8 +157,8 @@ module ActionDispatch
|
|
143
157
|
|
144
158
|
def segment_keys
|
145
159
|
@segment_keys ||= Rack::Mount::RegexpWithNamedGroups.new(
|
146
|
-
|
147
|
-
|
160
|
+
Rack::Mount::Strexp.compile(@path, requirements, SEPARATORS)
|
161
|
+
).names
|
148
162
|
end
|
149
163
|
|
150
164
|
def to
|
@@ -175,9 +189,15 @@ module ActionDispatch
|
|
175
189
|
end
|
176
190
|
|
177
191
|
def match(*args)
|
178
|
-
|
192
|
+
mapping = Mapping.new(@set, @scope, args).to_route
|
193
|
+
@set.add_route(*mapping)
|
179
194
|
self
|
180
195
|
end
|
196
|
+
|
197
|
+
def default_url_options=(options)
|
198
|
+
@set.default_url_options = options
|
199
|
+
end
|
200
|
+
alias_method :default_url_options, :default_url_options=
|
181
201
|
end
|
182
202
|
|
183
203
|
module HttpHelpers
|
@@ -239,6 +259,7 @@ module ActionDispatch
|
|
239
259
|
|
240
260
|
def scope(*args)
|
241
261
|
options = args.extract_options!
|
262
|
+
options = options.dup
|
242
263
|
|
243
264
|
case args.first
|
244
265
|
when String
|
@@ -283,13 +304,17 @@ module ActionDispatch
|
|
283
304
|
end
|
284
305
|
|
285
306
|
def namespace(path)
|
286
|
-
scope(path.to_s, :name_prefix => path.to_s, :
|
307
|
+
scope(path.to_s, :name_prefix => path.to_s, :controller_namespace => path.to_s) { yield }
|
287
308
|
end
|
288
309
|
|
289
310
|
def constraints(constraints = {})
|
290
311
|
scope(:constraints => constraints) { yield }
|
291
312
|
end
|
292
313
|
|
314
|
+
def defaults(defaults = {})
|
315
|
+
scope(:defaults => defaults) { yield }
|
316
|
+
end
|
317
|
+
|
293
318
|
def match(*args)
|
294
319
|
options = args.extract_options!
|
295
320
|
|
@@ -318,12 +343,12 @@ module ActionDispatch
|
|
318
343
|
parent ? "#{parent}_#{child}" : child
|
319
344
|
end
|
320
345
|
|
321
|
-
def
|
346
|
+
def merge_controller_namespace_scope(parent, child)
|
322
347
|
parent ? "#{parent}/#{child}" : child
|
323
348
|
end
|
324
349
|
|
325
350
|
def merge_controller_scope(parent, child)
|
326
|
-
@scope[:
|
351
|
+
@scope[:controller_namespace] ? "#{@scope[:controller_namespace]}/#{child}" : child
|
327
352
|
end
|
328
353
|
|
329
354
|
def merge_resources_path_names_scope(parent, child)
|
@@ -334,6 +359,10 @@ module ActionDispatch
|
|
334
359
|
merge_options_scope(parent, child)
|
335
360
|
end
|
336
361
|
|
362
|
+
def merge_defaults_scope(parent, child)
|
363
|
+
merge_options_scope(parent, child)
|
364
|
+
end
|
365
|
+
|
337
366
|
def merge_blocks_scope(parent, child)
|
338
367
|
(parent || []) + [child]
|
339
368
|
end
|
@@ -354,11 +383,11 @@ module ActionDispatch
|
|
354
383
|
attr_reader :plural, :singular, :options
|
355
384
|
|
356
385
|
def initialize(entities, options = {})
|
357
|
-
|
386
|
+
@name = entities.to_s
|
358
387
|
@options = options
|
359
388
|
|
360
|
-
@plural =
|
361
|
-
@singular =
|
389
|
+
@plural = @name.pluralize
|
390
|
+
@singular = @name.singularize
|
362
391
|
end
|
363
392
|
|
364
393
|
def default_actions
|
@@ -367,9 +396,9 @@ module ActionDispatch
|
|
367
396
|
|
368
397
|
def actions
|
369
398
|
if only = options[:only]
|
370
|
-
only.map(&:to_sym)
|
399
|
+
Array(only).map(&:to_sym)
|
371
400
|
elsif except = options[:except]
|
372
|
-
default_actions - except.map(&:to_sym)
|
401
|
+
default_actions - Array(except).map(&:to_sym)
|
373
402
|
else
|
374
403
|
default_actions
|
375
404
|
end
|
@@ -385,7 +414,7 @@ module ActionDispatch
|
|
385
414
|
end
|
386
415
|
|
387
416
|
def name
|
388
|
-
options[:as] ||
|
417
|
+
options[:as] || @name
|
389
418
|
end
|
390
419
|
|
391
420
|
def controller
|
@@ -396,8 +425,13 @@ module ActionDispatch
|
|
396
425
|
singular
|
397
426
|
end
|
398
427
|
|
428
|
+
# Checks for uncountable plurals, and appends "_index" if they're.
|
399
429
|
def collection_name
|
400
|
-
plural
|
430
|
+
uncountable? ? "#{plural}_index" : plural
|
431
|
+
end
|
432
|
+
|
433
|
+
def uncountable?
|
434
|
+
singular == plural
|
401
435
|
end
|
402
436
|
|
403
437
|
def name_for_action(action)
|
@@ -412,6 +446,32 @@ module ActionDispatch
|
|
412
446
|
def id_segment
|
413
447
|
":#{singular}_id"
|
414
448
|
end
|
449
|
+
|
450
|
+
def constraints
|
451
|
+
options[:constraints] || {}
|
452
|
+
end
|
453
|
+
|
454
|
+
def id_constraint?
|
455
|
+
options[:id] && options[:id].is_a?(Regexp) || constraints[:id] && constraints[:id].is_a?(Regexp)
|
456
|
+
end
|
457
|
+
|
458
|
+
def id_constraint
|
459
|
+
options[:id] || constraints[:id]
|
460
|
+
end
|
461
|
+
|
462
|
+
def collection_options
|
463
|
+
(options || {}).dup.tap do |options|
|
464
|
+
options.delete(:id)
|
465
|
+
options[:constraints] = options[:constraints].dup if options[:constraints]
|
466
|
+
options[:constraints].delete(:id) if options[:constraints].is_a?(Hash)
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
def nested_options
|
471
|
+
options = { :name_prefix => member_name }
|
472
|
+
options["#{singular}_id".to_sym] = id_constraint if id_constraint?
|
473
|
+
options
|
474
|
+
end
|
415
475
|
end
|
416
476
|
|
417
477
|
class SingletonResource < Resource #:nodoc:
|
@@ -430,8 +490,8 @@ module ActionDispatch
|
|
430
490
|
end
|
431
491
|
end
|
432
492
|
|
433
|
-
def
|
434
|
-
|
493
|
+
def member_name
|
494
|
+
name
|
435
495
|
end
|
436
496
|
end
|
437
497
|
|
@@ -443,7 +503,7 @@ module ActionDispatch
|
|
443
503
|
def resource(*resources, &block)
|
444
504
|
options = resources.extract_options!
|
445
505
|
|
446
|
-
if
|
506
|
+
if apply_common_behavior_for(:resource, resources, options, &block)
|
447
507
|
return self
|
448
508
|
end
|
449
509
|
|
@@ -451,14 +511,19 @@ module ActionDispatch
|
|
451
511
|
|
452
512
|
scope(:path => resource.name.to_s, :controller => resource.controller) do
|
453
513
|
with_scope_level(:resource, resource) do
|
454
|
-
yield if block_given?
|
455
514
|
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
515
|
+
scope(:name_prefix => resource.name.to_s, :as => "") do
|
516
|
+
yield if block_given?
|
517
|
+
end
|
518
|
+
|
519
|
+
scope(resource.options) do
|
520
|
+
get :show if resource.actions.include?(:show)
|
521
|
+
post :create if resource.actions.include?(:create)
|
522
|
+
put :update if resource.actions.include?(:update)
|
523
|
+
delete :destroy if resource.actions.include?(:destroy)
|
524
|
+
get :new, :as => resource.name if resource.actions.include?(:new)
|
525
|
+
get :edit, :as => resource.name if resource.actions.include?(:edit)
|
526
|
+
end
|
462
527
|
end
|
463
528
|
end
|
464
529
|
|
@@ -468,7 +533,7 @@ module ActionDispatch
|
|
468
533
|
def resources(*resources, &block)
|
469
534
|
options = resources.extract_options!
|
470
535
|
|
471
|
-
if
|
536
|
+
if apply_common_behavior_for(:resources, resources, options, &block)
|
472
537
|
return self
|
473
538
|
end
|
474
539
|
|
@@ -479,17 +544,21 @@ module ActionDispatch
|
|
479
544
|
yield if block_given?
|
480
545
|
|
481
546
|
with_scope_level(:collection) do
|
482
|
-
|
483
|
-
|
484
|
-
|
547
|
+
scope(resource.collection_options) do
|
548
|
+
get :index if resource.actions.include?(:index)
|
549
|
+
post :create if resource.actions.include?(:create)
|
550
|
+
get :new, :as => resource.singular if resource.actions.include?(:new)
|
551
|
+
end
|
485
552
|
end
|
486
553
|
|
487
554
|
with_scope_level(:member) do
|
488
555
|
scope(':id') do
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
556
|
+
scope(resource.options) do
|
557
|
+
get :show if resource.actions.include?(:show)
|
558
|
+
put :update if resource.actions.include?(:update)
|
559
|
+
delete :destroy if resource.actions.include?(:destroy)
|
560
|
+
get :edit, :as => resource.singular if resource.actions.include?(:edit)
|
561
|
+
end
|
493
562
|
end
|
494
563
|
end
|
495
564
|
end
|
@@ -528,15 +597,32 @@ module ActionDispatch
|
|
528
597
|
end
|
529
598
|
|
530
599
|
with_scope_level(:nested) do
|
531
|
-
scope(parent_resource.id_segment,
|
600
|
+
scope(parent_resource.id_segment, parent_resource.nested_options) do
|
532
601
|
yield
|
533
602
|
end
|
534
603
|
end
|
535
604
|
end
|
536
605
|
|
606
|
+
def mount(app, options = nil)
|
607
|
+
if options
|
608
|
+
path = options.delete(:at)
|
609
|
+
else
|
610
|
+
options = app
|
611
|
+
app, path = options.find { |k, v| k.respond_to?(:call) }
|
612
|
+
options.delete(app) if app
|
613
|
+
end
|
614
|
+
|
615
|
+
raise "A rack application must be specified" unless path
|
616
|
+
|
617
|
+
match(path, options.merge(:to => app, :anchor => false))
|
618
|
+
self
|
619
|
+
end
|
620
|
+
|
537
621
|
def match(*args)
|
538
622
|
options = args.extract_options!
|
539
623
|
|
624
|
+
options[:anchor] = true unless options.key?(:anchor)
|
625
|
+
|
540
626
|
if args.length > 1
|
541
627
|
args.each { |path| match(path, options) }
|
542
628
|
return self
|
@@ -591,7 +677,7 @@ module ActionDispatch
|
|
591
677
|
path_names[name.to_sym] || name.to_s
|
592
678
|
end
|
593
679
|
|
594
|
-
def
|
680
|
+
def apply_common_behavior_for(method, resources, options, &block)
|
595
681
|
if resources.length > 1
|
596
682
|
resources.each { |r| send(method, r, options, &block) }
|
597
683
|
return true
|