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
data/lib/abstract_controller.rb
CHANGED
@@ -3,20 +3,23 @@ $:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.inc
|
|
3
3
|
|
4
4
|
require 'active_support/ruby/shim'
|
5
5
|
require 'active_support/dependencies/autoload'
|
6
|
+
require 'active_support/core_ext/class/attribute'
|
6
7
|
require 'active_support/core_ext/module/attr_internal'
|
7
8
|
require 'active_support/core_ext/module/delegation'
|
9
|
+
require 'active_support/core_ext/module/anonymous'
|
10
|
+
require 'active_support/i18n'
|
8
11
|
|
9
12
|
module AbstractController
|
10
13
|
extend ActiveSupport::Autoload
|
11
14
|
|
15
|
+
autoload :Assigns
|
12
16
|
autoload :Base
|
13
17
|
autoload :Callbacks
|
14
18
|
autoload :Collector
|
15
|
-
autoload :Compatibility
|
16
19
|
autoload :Helpers
|
17
20
|
autoload :Layouts
|
18
|
-
autoload :LocalizedCache
|
19
21
|
autoload :Logger
|
20
22
|
autoload :Rendering
|
21
23
|
autoload :Translation
|
24
|
+
autoload :ViewPaths
|
22
25
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module AbstractController
|
2
|
+
module Assigns
|
3
|
+
# This method should return a hash with assigns.
|
4
|
+
# You can overwrite this configuration per controller.
|
5
|
+
# :api: public
|
6
|
+
def view_assigns
|
7
|
+
hash = {}
|
8
|
+
variables = instance_variable_names
|
9
|
+
variables -= protected_instance_variables if respond_to?(:protected_instance_variables)
|
10
|
+
variables.each { |name| hash[name] = instance_variable_get(name) }
|
11
|
+
hash
|
12
|
+
end
|
13
|
+
|
14
|
+
# This method assigns the hash specified in _assigns_hash to the given object.
|
15
|
+
# :api: private
|
16
|
+
# TODO Ideally, this should be done on AV::Base.new initialization.
|
17
|
+
def _evaluate_assigns(object)
|
18
|
+
view_assigns.each { |k,v| object.instance_variable_set(k, v) }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_support/ordered_options'
|
2
|
+
|
1
3
|
module AbstractController
|
2
4
|
class Error < StandardError; end
|
3
5
|
class ActionNotFound < StandardError; end
|
@@ -5,7 +7,6 @@ module AbstractController
|
|
5
7
|
class Base
|
6
8
|
attr_internal :response_body
|
7
9
|
attr_internal :action_name
|
8
|
-
attr_internal :formats
|
9
10
|
|
10
11
|
class << self
|
11
12
|
attr_reader :abstract
|
@@ -28,6 +29,14 @@ module AbstractController
|
|
28
29
|
@descendants ||= []
|
29
30
|
end
|
30
31
|
|
32
|
+
def config
|
33
|
+
@config ||= ActiveSupport::InheritableOptions.new(superclass < Base ? superclass.config : {})
|
34
|
+
end
|
35
|
+
|
36
|
+
def configure
|
37
|
+
yield config
|
38
|
+
end
|
39
|
+
|
31
40
|
# A list of all internal methods for a controller. This finds the first
|
32
41
|
# abstract superclass of a controller, and gets a list of all public
|
33
42
|
# instance methods on that abstract class. Public instance methods of
|
@@ -84,15 +93,14 @@ module AbstractController
|
|
84
93
|
# ==== Returns
|
85
94
|
# String
|
86
95
|
def controller_path
|
87
|
-
@controller_path ||= name
|
96
|
+
@controller_path ||= name.sub(/Controller$/, '').underscore unless anonymous?
|
88
97
|
end
|
89
98
|
end
|
90
99
|
|
91
100
|
abstract!
|
92
101
|
|
93
|
-
|
94
|
-
|
95
|
-
@_formats = nil
|
102
|
+
def config
|
103
|
+
@config ||= ActiveSupport::InheritableOptions.new(self.class.config)
|
96
104
|
end
|
97
105
|
|
98
106
|
# Calls the action going through the entire action dispatch stack.
|
@@ -1,6 +1,4 @@
|
|
1
1
|
require 'active_support/dependencies'
|
2
|
-
require 'active_support/core_ext/class/attribute'
|
3
|
-
require 'active_support/core_ext/module/delegation'
|
4
2
|
|
5
3
|
module AbstractController
|
6
4
|
module Helpers
|
@@ -8,16 +6,10 @@ module AbstractController
|
|
8
6
|
|
9
7
|
include Rendering
|
10
8
|
|
11
|
-
def self.next_serial
|
12
|
-
@helper_serial ||= 0
|
13
|
-
@helper_serial += 1
|
14
|
-
end
|
15
|
-
|
16
9
|
included do
|
17
|
-
class_attribute :_helpers
|
10
|
+
class_attribute :_helpers
|
18
11
|
delegate :_helpers, :to => :'self.class'
|
19
12
|
self._helpers = Module.new
|
20
|
-
self._helper_serial = ::AbstractController::Helpers.next_serial
|
21
13
|
end
|
22
14
|
|
23
15
|
module ClassMethods
|
@@ -27,7 +19,7 @@ module AbstractController
|
|
27
19
|
def inherited(klass)
|
28
20
|
helpers = _helpers
|
29
21
|
klass._helpers = Module.new { include helpers }
|
30
|
-
klass.class_eval { default_helper_module! unless
|
22
|
+
klass.class_eval { default_helper_module! unless anonymous? }
|
31
23
|
super
|
32
24
|
end
|
33
25
|
|
@@ -97,9 +89,7 @@ module AbstractController
|
|
97
89
|
# helper(:three, BlindHelper) { def mice() 'mice' end }
|
98
90
|
#
|
99
91
|
def helper(*args, &block)
|
100
|
-
|
101
|
-
|
102
|
-
_modules_for_helpers(args).each do |mod|
|
92
|
+
modules_for_helpers(args).each do |mod|
|
103
93
|
add_template_helper(mod)
|
104
94
|
end
|
105
95
|
|
@@ -134,7 +124,7 @@ module AbstractController
|
|
134
124
|
# ==== Returns
|
135
125
|
# Array[Module]:: A normalized list of modules for the list of
|
136
126
|
# helpers provided.
|
137
|
-
def
|
127
|
+
def modules_for_helpers(args)
|
138
128
|
args.flatten.map! do |arg|
|
139
129
|
case arg
|
140
130
|
when String, Symbol
|
@@ -1,5 +1,4 @@
|
|
1
|
-
require
|
2
|
-
require 'active_support/core_ext/module/delegation'
|
1
|
+
require "active_support/core_ext/module/remove_method"
|
3
2
|
|
4
3
|
module AbstractController
|
5
4
|
# Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in
|
@@ -173,27 +172,7 @@ module AbstractController
|
|
173
172
|
module ClassMethods
|
174
173
|
def inherited(klass)
|
175
174
|
super
|
176
|
-
klass.
|
177
|
-
_write_layout_method
|
178
|
-
@found_layouts = {}
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
def clear_template_caches!
|
183
|
-
@found_layouts.clear if defined? @found_layouts
|
184
|
-
super
|
185
|
-
end
|
186
|
-
|
187
|
-
def cache_layout(details)
|
188
|
-
layout = @found_layouts
|
189
|
-
key = Thread.current[:format_locale_key]
|
190
|
-
|
191
|
-
# Cache nil
|
192
|
-
if layout.key?(key)
|
193
|
-
return layout[key]
|
194
|
-
else
|
195
|
-
layout[key] = yield
|
196
|
-
end
|
175
|
+
klass._write_layout_method
|
197
176
|
end
|
198
177
|
|
199
178
|
# This module is mixed in if layout conditions are provided. This means
|
@@ -205,7 +184,9 @@ module AbstractController
|
|
205
184
|
#
|
206
185
|
# ==== Returns
|
207
186
|
# Boolean:: True if the action has a layout, false otherwise.
|
208
|
-
def
|
187
|
+
def action_has_layout?
|
188
|
+
return unless super
|
189
|
+
|
209
190
|
conditions = _layout_conditions
|
210
191
|
|
211
192
|
if only = conditions[:only]
|
@@ -260,12 +241,14 @@ module AbstractController
|
|
260
241
|
# name, return that string. Otherwise, use the superclass'
|
261
242
|
# layout (which might also be implied)
|
262
243
|
def _write_layout_method
|
244
|
+
remove_possible_method(:_layout)
|
245
|
+
|
263
246
|
case defined?(@_layout) ? @_layout : nil
|
264
247
|
when String
|
265
|
-
self.class_eval %{def _layout
|
248
|
+
self.class_eval %{def _layout; #{@_layout.inspect} end}
|
266
249
|
when Symbol
|
267
250
|
self.class_eval <<-ruby_eval, __FILE__, __LINE__ + 1
|
268
|
-
def _layout
|
251
|
+
def _layout
|
269
252
|
#{@_layout}.tap do |layout|
|
270
253
|
unless layout.is_a?(String) || !layout
|
271
254
|
raise ArgumentError, "Your layout method :#{@_layout} returned \#{layout}. It " \
|
@@ -276,21 +259,21 @@ module AbstractController
|
|
276
259
|
ruby_eval
|
277
260
|
when Proc
|
278
261
|
define_method :_layout_from_proc, &@_layout
|
279
|
-
self.class_eval %{def _layout
|
262
|
+
self.class_eval %{def _layout; _layout_from_proc(self) end}
|
280
263
|
when false
|
281
|
-
self.class_eval %{def _layout
|
264
|
+
self.class_eval %{def _layout; end}
|
282
265
|
when true
|
283
266
|
raise ArgumentError, "Layouts must be specified as a String, Symbol, false, or nil"
|
284
267
|
when nil
|
285
268
|
if name
|
269
|
+
_prefix = "layouts" unless _implied_layout_name =~ /\blayouts/
|
270
|
+
|
286
271
|
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
287
|
-
def _layout
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
super
|
293
|
-
end
|
272
|
+
def _layout
|
273
|
+
if template_exists?("#{_implied_layout_name}", #{_prefix.inspect})
|
274
|
+
"#{_implied_layout_name}"
|
275
|
+
else
|
276
|
+
super
|
294
277
|
end
|
295
278
|
end
|
296
279
|
RUBY
|
@@ -300,42 +283,31 @@ module AbstractController
|
|
300
283
|
end
|
301
284
|
end
|
302
285
|
|
303
|
-
def
|
304
|
-
|
305
|
-
# here, and make sure the view does not try to handle it
|
306
|
-
layout = options.delete(:layout) if options.key?(:partial)
|
307
|
-
|
308
|
-
response = super
|
286
|
+
def _normalize_options(options)
|
287
|
+
super
|
309
288
|
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
# TODO: An easier way to handle this would probably be to override
|
315
|
-
# render_template
|
316
|
-
if layout
|
317
|
-
layout = _layout_for_option(layout, options[:_template].details)
|
318
|
-
response = layout.render(view_context, options[:locals] || {}) { response }
|
289
|
+
if _include_layout?(options)
|
290
|
+
layout = options.key?(:layout) ? options.delete(:layout) : :default
|
291
|
+
value = _layout_for_option(layout)
|
292
|
+
options[:layout] = (value =~ /\blayouts/ ? value : "layouts/#{value}") if value
|
319
293
|
end
|
294
|
+
end
|
295
|
+
|
296
|
+
attr_writer :action_has_layout
|
297
|
+
|
298
|
+
def initialize(*)
|
299
|
+
@action_has_layout = true
|
300
|
+
super
|
301
|
+
end
|
320
302
|
|
321
|
-
|
303
|
+
def action_has_layout?
|
304
|
+
@action_has_layout
|
322
305
|
end
|
323
306
|
|
324
307
|
private
|
325
308
|
|
326
309
|
# This will be overwritten by _write_layout_method
|
327
|
-
def _layout
|
328
|
-
|
329
|
-
# Determine the layout for a given name and details.
|
330
|
-
#
|
331
|
-
# ==== Parameters
|
332
|
-
# name<String>:: The name of the template
|
333
|
-
# details<Hash{Symbol => Object}>:: A list of details to restrict
|
334
|
-
# the lookup to. By default, layout lookup is limited to the
|
335
|
-
# formats specified for the current request.
|
336
|
-
def _layout_for_name(name, details)
|
337
|
-
name && _find_layout(name, details)
|
338
|
-
end
|
310
|
+
def _layout; end
|
339
311
|
|
340
312
|
# Determine the layout for a given name and details, taking into account
|
341
313
|
# the name type.
|
@@ -345,11 +317,11 @@ module AbstractController
|
|
345
317
|
# details<Hash{Symbol => Object}>:: A list of details to restrict
|
346
318
|
# the lookup to. By default, layout lookup is limited to the
|
347
319
|
# formats specified for the current request.
|
348
|
-
def _layout_for_option(name
|
320
|
+
def _layout_for_option(name)
|
349
321
|
case name
|
350
|
-
when String then
|
351
|
-
when true then _default_layout(
|
352
|
-
when :default then _default_layout(
|
322
|
+
when String then name
|
323
|
+
when true then _default_layout(true)
|
324
|
+
when :default then _default_layout(false)
|
353
325
|
when false, nil then nil
|
354
326
|
else
|
355
327
|
raise ArgumentError,
|
@@ -357,29 +329,6 @@ module AbstractController
|
|
357
329
|
end
|
358
330
|
end
|
359
331
|
|
360
|
-
def _determine_template(options)
|
361
|
-
super
|
362
|
-
|
363
|
-
return unless (options.keys & [:text, :inline, :partial]).empty? || options.key?(:layout)
|
364
|
-
layout = options.key?(:layout) ? options[:layout] : :default
|
365
|
-
options[:_layout] = _layout_for_option(layout, options[:_template].details)
|
366
|
-
end
|
367
|
-
|
368
|
-
# Take in the name and details and find a Template.
|
369
|
-
#
|
370
|
-
# ==== Parameters
|
371
|
-
# name<String>:: The name of the template to retrieve
|
372
|
-
# details<Hash>:: A list of details to restrict the search by. This
|
373
|
-
# might include details like the format or locale of the template.
|
374
|
-
#
|
375
|
-
# ==== Returns
|
376
|
-
# Template:: A template object matching the name and details
|
377
|
-
def _find_layout(name, details)
|
378
|
-
# TODO: Make prefix actually part of details in ViewPath#find_by_parts
|
379
|
-
prefix = details.key?(:prefix) ? details.delete(:prefix) : "layouts"
|
380
|
-
find_template(name, details, :_prefix => prefix)
|
381
|
-
end
|
382
|
-
|
383
332
|
# Returns the default layout for this controller and a given set of details.
|
384
333
|
# Optionally raises an exception if the layout could not be found.
|
385
334
|
#
|
@@ -392,22 +341,24 @@ module AbstractController
|
|
392
341
|
#
|
393
342
|
# ==== Returns
|
394
343
|
# Template:: The template object for the default layout (or nil)
|
395
|
-
def _default_layout(
|
396
|
-
if require_layout && _action_has_layout? && !_layout(details)
|
397
|
-
raise ArgumentError,
|
398
|
-
"There was no default layout for #{self.class} in #{view_paths.inspect}"
|
399
|
-
end
|
400
|
-
|
344
|
+
def _default_layout(require_layout = false)
|
401
345
|
begin
|
402
|
-
|
346
|
+
layout_name = _layout if action_has_layout?
|
403
347
|
rescue NameError => e
|
404
348
|
raise NoMethodError,
|
405
349
|
"You specified #{@_layout.inspect} as the layout, but no such method was found"
|
406
350
|
end
|
351
|
+
|
352
|
+
if require_layout && action_has_layout? && !layout_name
|
353
|
+
raise ArgumentError,
|
354
|
+
"There was no default layout for #{self.class} in #{view_paths.inspect}"
|
355
|
+
end
|
356
|
+
|
357
|
+
layout_name
|
407
358
|
end
|
408
359
|
|
409
|
-
def
|
410
|
-
|
360
|
+
def _include_layout?(options)
|
361
|
+
(options.keys & [:text, :inline, :partial]).empty? || options.key?(:layout)
|
411
362
|
end
|
412
363
|
end
|
413
364
|
end
|
@@ -1,7 +1,4 @@
|
|
1
1
|
require "abstract_controller/base"
|
2
|
-
require 'active_support/core_ext/class/attribute'
|
3
|
-
require 'active_support/core_ext/module/delegation'
|
4
|
-
require 'active_support/core_ext/array/wrap'
|
5
2
|
|
6
3
|
module AbstractController
|
7
4
|
class DoubleRenderError < Error
|
@@ -12,90 +9,110 @@ module AbstractController
|
|
12
9
|
end
|
13
10
|
end
|
14
11
|
|
12
|
+
# This is a class to fix I18n global state. Whenever you provide I18n.locale during a request,
|
13
|
+
# it will trigger the lookup_context and consequently expire the cache.
|
14
|
+
# TODO Add some deprecation warnings to remove I18n.locale from controllers
|
15
|
+
class I18nProxy < ::I18n::Config #:nodoc:
|
16
|
+
attr_reader :i18n_config, :lookup_context
|
17
|
+
|
18
|
+
def initialize(i18n_config, lookup_context)
|
19
|
+
@i18n_config, @lookup_context = i18n_config, lookup_context
|
20
|
+
end
|
21
|
+
|
22
|
+
def locale
|
23
|
+
@i18n_config.locale
|
24
|
+
end
|
25
|
+
|
26
|
+
def locale=(value)
|
27
|
+
@i18n_config.locale = value
|
28
|
+
@lookup_context.update_details(:locale => @i18n_config.locale)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
15
32
|
module Rendering
|
16
33
|
extend ActiveSupport::Concern
|
17
34
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
35
|
+
include AbstractController::ViewPaths
|
36
|
+
|
37
|
+
# Overwrite process to setup I18n proxy.
|
38
|
+
def process(*) #:nodoc:
|
39
|
+
old_config, I18n.config = I18n.config, I18nProxy.new(I18n.config, lookup_context)
|
40
|
+
super
|
41
|
+
ensure
|
42
|
+
I18n.config = old_config
|
43
|
+
end
|
44
|
+
|
45
|
+
module ClassMethods
|
46
|
+
def view_context_class
|
47
|
+
@view_context_class ||= begin
|
48
|
+
controller = self
|
49
|
+
Class.new(ActionView::Base) do
|
50
|
+
if controller.respond_to?(:_helpers)
|
51
|
+
include controller._helpers
|
52
|
+
|
53
|
+
if controller.respond_to?(:_router)
|
54
|
+
include controller._router.url_helpers
|
55
|
+
end
|
56
|
+
|
57
|
+
# TODO: Fix RJS to not require this
|
58
|
+
self.helpers = controller._helpers
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
attr_writer :view_context_class
|
66
|
+
|
67
|
+
def view_context_class
|
68
|
+
@view_context_class || self.class.view_context_class
|
69
|
+
end
|
70
|
+
|
71
|
+
def initialize(*)
|
72
|
+
@view_context_class = nil
|
73
|
+
super
|
22
74
|
end
|
23
75
|
|
24
76
|
# An instance of a view class. The default view class is ActionView::Base
|
25
77
|
#
|
26
78
|
# The view class must have the following methods:
|
27
|
-
# View.
|
28
|
-
# controller
|
29
|
-
# View#
|
30
|
-
#
|
31
|
-
# - Returns String with the rendered partial
|
32
|
-
# options<Hash>:: see _render_partial in ActionView::Base
|
33
|
-
# View#render_template[template, layout, options, partial]
|
34
|
-
# - Returns String with the rendered template
|
35
|
-
# template<ActionView::Template>:: The template to render
|
36
|
-
# layout<ActionView::Template>:: The layout to render around the template
|
37
|
-
# options<Hash>:: See _render_template_with_layout in ActionView::Base
|
38
|
-
# partial<Boolean>:: Whether or not the template to render is a partial
|
79
|
+
# View.new[lookup_context, assigns, controller]
|
80
|
+
# Create a new ActionView instance for a controller
|
81
|
+
# View#render[options]
|
82
|
+
# Returns String with the rendered template
|
39
83
|
#
|
40
|
-
# Override this method in a to change the default behavior.
|
84
|
+
# Override this method in a module to change the default behavior.
|
41
85
|
def view_context
|
42
|
-
|
86
|
+
view_context_class.new(lookup_context, view_assigns, self)
|
43
87
|
end
|
44
88
|
|
45
|
-
#
|
46
|
-
#
|
89
|
+
# Normalize arguments, options and then delegates render_to_body and
|
90
|
+
# sticks the result in self.response_body.
|
47
91
|
def render(*args, &block)
|
48
|
-
options =
|
92
|
+
options = _normalize_args(*args, &block)
|
93
|
+
_normalize_options(options)
|
49
94
|
self.response_body = render_to_body(options)
|
50
95
|
end
|
51
96
|
|
52
97
|
# Raw rendering of a template to a Rack-compatible body.
|
53
|
-
#
|
54
|
-
# ==== Options
|
55
|
-
# _partial_object<Object>:: The object that is being rendered. If this
|
56
|
-
# exists, we are in the special case of rendering an object as a partial.
|
57
|
-
#
|
58
98
|
# :api: plugin
|
59
99
|
def render_to_body(options = {})
|
60
|
-
|
61
|
-
|
62
|
-
_render_partial(options)
|
63
|
-
else
|
64
|
-
_determine_template(options)
|
65
|
-
_render_template(options)
|
66
|
-
end
|
100
|
+
_process_options(options)
|
101
|
+
_render_template(options)
|
67
102
|
end
|
68
103
|
|
69
104
|
# Raw rendering of a template to a string. Just convert the results of
|
70
105
|
# render_to_body into a String.
|
71
|
-
#
|
72
106
|
# :api: plugin
|
73
|
-
def render_to_string(
|
74
|
-
|
75
|
-
|
76
|
-
end
|
77
|
-
|
78
|
-
# Renders the template from an object.
|
79
|
-
#
|
80
|
-
# ==== Options
|
81
|
-
# _template<ActionView::Template>:: The template to render
|
82
|
-
# _layout<ActionView::Template>:: The layout to wrap the template in (optional)
|
83
|
-
def _render_template(options)
|
84
|
-
view_context.render_template(options)
|
85
|
-
end
|
86
|
-
|
87
|
-
# Renders the given partial.
|
88
|
-
#
|
89
|
-
# ==== Options
|
90
|
-
# partial<String|Object>:: The partial name or the object to be rendered
|
91
|
-
def _render_partial(options)
|
92
|
-
view_context.render_partial(options)
|
107
|
+
def render_to_string(options={})
|
108
|
+
_normalize_options(options)
|
109
|
+
render_to_body(options)
|
93
110
|
end
|
94
111
|
|
95
|
-
#
|
96
|
-
#
|
97
|
-
def
|
98
|
-
|
112
|
+
# Find and renders a template based on the options given.
|
113
|
+
# :api: private
|
114
|
+
def _render_template(options) #:nodoc:
|
115
|
+
view_context.render(options)
|
99
116
|
end
|
100
117
|
|
101
118
|
# The prefix used in render "foo" shortcuts.
|
@@ -103,136 +120,51 @@ module AbstractController
|
|
103
120
|
controller_path
|
104
121
|
end
|
105
122
|
|
106
|
-
# Return a string representation of a Rack-compatible response body.
|
107
|
-
def self.body_to_s(body)
|
108
|
-
if body.respond_to?(:to_str)
|
109
|
-
body
|
110
|
-
else
|
111
|
-
strings = []
|
112
|
-
body.each { |part| strings << part.to_s }
|
113
|
-
body.close if body.respond_to?(:close)
|
114
|
-
strings.join
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
123
|
private
|
119
124
|
|
120
|
-
#
|
121
|
-
#
|
122
|
-
|
125
|
+
# This method should return a hash with assigns.
|
126
|
+
# You can overwrite this configuration per controller.
|
127
|
+
# :api: public
|
128
|
+
def view_assigns
|
129
|
+
hash = {}
|
130
|
+
variables = instance_variable_names
|
131
|
+
variables -= protected_instance_variables if respond_to?(:protected_instance_variables)
|
132
|
+
variables.each { |name| hash[name.to_s[1..-1]] = instance_variable_get(name) }
|
133
|
+
hash
|
134
|
+
end
|
135
|
+
|
136
|
+
# Normalize options by converting render "foo" to render :action => "foo" and
|
137
|
+
# render "foo/bar" to render :file => "foo/bar".
|
138
|
+
def _normalize_args(action=nil, options={})
|
123
139
|
case action
|
140
|
+
when NilClass
|
124
141
|
when Hash
|
125
142
|
options, action = action, nil
|
126
143
|
when String, Symbol
|
127
144
|
action = action.to_s
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
when 0
|
133
|
-
options[:file] = action
|
134
|
-
else
|
135
|
-
options[:template] = action
|
136
|
-
end
|
145
|
+
key = action.include?(?/) ? :file : :action
|
146
|
+
options[key] = action
|
147
|
+
else
|
148
|
+
options.merge!(:partial => action)
|
137
149
|
end
|
138
150
|
|
139
151
|
options
|
140
152
|
end
|
141
153
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
# _template<ActionView::Template>:: If this is provided, the search is over
|
146
|
-
# _template_name<#to_s>:: The name of the template to look up. Otherwise,
|
147
|
-
# use the current action name.
|
148
|
-
# _prefix<String>:: The prefix to look inside of. In a file system, this corresponds
|
149
|
-
# to a directory.
|
150
|
-
# _partial<TrueClass, FalseClass>:: Whether or not the file to look up is a partial
|
151
|
-
def _determine_template(options)
|
152
|
-
if options.key?(:text)
|
153
|
-
options[:_template] = ActionView::Template::Text.new(options[:text], format_for_text)
|
154
|
-
elsif options.key?(:inline)
|
155
|
-
handler = ActionView::Template.handler_class_for_extension(options[:type] || "erb")
|
156
|
-
template = ActionView::Template.new(options[:inline], "inline template", handler, {})
|
157
|
-
options[:_template] = template
|
158
|
-
elsif options.key?(:template)
|
159
|
-
options[:_template_name] = options[:template]
|
160
|
-
elsif options.key?(:file)
|
161
|
-
options[:_template_name] = options[:file]
|
154
|
+
def _normalize_options(options)
|
155
|
+
if options[:partial] == true
|
156
|
+
options[:partial] = action_name
|
162
157
|
end
|
163
|
-
name = (options[:_template_name] || options[:action] || action_name).to_s
|
164
|
-
options[:_prefix] ||= _prefix if (options.keys & [:partial, :file, :template]).empty?
|
165
|
-
|
166
|
-
details = _normalize_details(options)
|
167
158
|
|
168
|
-
options[:
|
169
|
-
|
159
|
+
if (options.keys & [:partial, :file, :template]).empty?
|
160
|
+
options[:prefix] ||= _prefix
|
170
161
|
end
|
171
|
-
end
|
172
|
-
|
173
|
-
def _normalize_details(options)
|
174
|
-
details = { :formats => formats }
|
175
|
-
details[:formats] = Array(options[:format]) if options[:format]
|
176
|
-
details[:locale] = Array(options[:locale]) if options[:locale]
|
177
|
-
details
|
178
|
-
end
|
179
|
-
|
180
|
-
def find_template(name, details, options)
|
181
|
-
view_paths.find(name, details, options[:_prefix], options[:_partial])
|
182
|
-
end
|
183
162
|
|
184
|
-
|
185
|
-
|
186
|
-
end
|
187
|
-
|
188
|
-
def with_template_cache(name)
|
189
|
-
yield
|
190
|
-
end
|
191
|
-
|
192
|
-
def format_for_text
|
193
|
-
Mime[:text]
|
163
|
+
options[:template] ||= (options[:action] || action_name).to_s
|
164
|
+
options
|
194
165
|
end
|
195
166
|
|
196
|
-
|
197
|
-
def clear_template_caches!
|
198
|
-
end
|
199
|
-
|
200
|
-
# Append a path to the list of view paths for this controller.
|
201
|
-
#
|
202
|
-
# ==== Parameters
|
203
|
-
# path<String, ViewPath>:: If a String is provided, it gets converted into
|
204
|
-
# the default view path. You may also provide a custom view path
|
205
|
-
# (see ActionView::ViewPathSet for more information)
|
206
|
-
def append_view_path(path)
|
207
|
-
self.view_paths = view_paths.dup + Array.wrap(path)
|
208
|
-
end
|
209
|
-
|
210
|
-
# Prepend a path to the list of view paths for this controller.
|
211
|
-
#
|
212
|
-
# ==== Parameters
|
213
|
-
# path<String, ViewPath>:: If a String is provided, it gets converted into
|
214
|
-
# the default view path. You may also provide a custom view path
|
215
|
-
# (see ActionView::ViewPathSet for more information)
|
216
|
-
def prepend_view_path(path)
|
217
|
-
clear_template_caches!
|
218
|
-
self.view_paths = Array.wrap(path) + view_paths.dup
|
219
|
-
end
|
220
|
-
|
221
|
-
# A list of all of the default view paths for this controller.
|
222
|
-
def view_paths
|
223
|
-
_view_paths
|
224
|
-
end
|
225
|
-
|
226
|
-
# Set the view paths.
|
227
|
-
#
|
228
|
-
# ==== Parameters
|
229
|
-
# paths<ViewPathSet, Object>:: If a ViewPathSet is provided, use that;
|
230
|
-
# otherwise, process the parameter into a ViewPathSet.
|
231
|
-
def view_paths=(paths)
|
232
|
-
clear_template_caches!
|
233
|
-
self._view_paths = paths.is_a?(ActionView::PathSet) ? paths : ActionView::Base.process_view_paths(paths)
|
234
|
-
_view_paths.freeze
|
235
|
-
end
|
167
|
+
def _process_options(options)
|
236
168
|
end
|
237
169
|
end
|
238
170
|
end
|