actionpack 3.1.12 → 3.2.0.rc1
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.md +5503 -108
- data/README.rdoc +3 -3
- data/lib/abstract_controller/asset_paths.rb +1 -1
- data/lib/abstract_controller/base.rb +1 -1
- data/lib/abstract_controller/callbacks.rb +102 -18
- data/lib/abstract_controller/helpers.rb +1 -1
- data/lib/abstract_controller/layouts.rb +116 -50
- data/lib/abstract_controller/logger.rb +1 -1
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -2
- data/lib/abstract_controller/rendering.rb +1 -6
- data/lib/abstract_controller/view_paths.rb +6 -5
- data/lib/action_controller.rb +0 -15
- data/lib/action_controller/caching.rb +0 -1
- data/lib/action_controller/caching/actions.rb +5 -6
- data/lib/action_controller/caching/fragments.rb +18 -18
- data/lib/action_controller/caching/pages.rb +7 -6
- data/lib/action_controller/caching/sweeping.rb +1 -1
- data/lib/action_controller/log_subscriber.rb +8 -4
- data/lib/action_controller/metal.rb +7 -1
- data/lib/action_controller/metal/conditional_get.rb +49 -4
- data/lib/action_controller/metal/data_streaming.rb +17 -5
- data/lib/action_controller/metal/force_ssl.rb +8 -5
- data/lib/action_controller/metal/helpers.rb +7 -4
- data/lib/action_controller/metal/http_authentication.rb +9 -12
- data/lib/action_controller/metal/instrumentation.rb +9 -4
- data/lib/action_controller/metal/mime_responds.rb +4 -4
- data/lib/action_controller/metal/params_wrapper.rb +12 -8
- data/lib/action_controller/metal/redirecting.rb +7 -6
- data/lib/action_controller/metal/renderers.rb +9 -11
- data/lib/action_controller/metal/request_forgery_protection.rb +2 -1
- data/lib/action_controller/metal/rescue.rb +13 -0
- data/lib/action_controller/metal/responder.rb +11 -23
- data/lib/action_controller/metal/streaming.rb +0 -25
- data/lib/action_controller/railtie.rb +1 -0
- data/lib/action_controller/railties/paths.rb +4 -3
- data/lib/action_controller/record_identifier.rb +4 -4
- data/lib/action_controller/test_case.rb +60 -56
- data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +6 -6
- data/lib/action_dispatch.rb +5 -1
- data/lib/action_dispatch/http/cache.rb +27 -15
- data/lib/action_dispatch/http/filter_parameters.rb +3 -1
- data/lib/action_dispatch/http/headers.rb +3 -5
- data/lib/action_dispatch/http/mime_negotiation.rb +2 -1
- data/lib/action_dispatch/http/mime_type.rb +7 -3
- data/lib/action_dispatch/http/mime_types.rb +12 -0
- data/lib/action_dispatch/http/parameter_filter.rb +3 -1
- data/lib/action_dispatch/http/parameters.rb +0 -4
- data/lib/action_dispatch/http/request.rb +18 -68
- data/lib/action_dispatch/http/response.rb +11 -32
- data/lib/action_dispatch/http/upload.rb +3 -14
- data/lib/action_dispatch/http/url.rb +1 -1
- data/lib/action_dispatch/middleware/callbacks.rb +1 -2
- data/lib/action_dispatch/middleware/cookies.rb +20 -16
- data/lib/action_dispatch/middleware/debug_exceptions.rb +82 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +78 -0
- data/lib/action_dispatch/middleware/flash.rb +6 -9
- data/lib/action_dispatch/middleware/params_parser.rb +6 -11
- data/lib/action_dispatch/middleware/public_exceptions.rb +30 -0
- data/lib/action_dispatch/middleware/reloader.rb +38 -14
- data/lib/action_dispatch/middleware/remote_ip.rb +66 -36
- data/lib/action_dispatch/middleware/request_id.rb +39 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +4 -16
- data/lib/action_dispatch/middleware/session/cache_store.rb +50 -0
- data/lib/action_dispatch/middleware/session/cookie_store.rb +1 -1
- data/lib/action_dispatch/middleware/show_exceptions.rb +58 -142
- data/lib/action_dispatch/middleware/static.rb +2 -10
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +13 -8
- data/lib/action_dispatch/railtie.rb +15 -1
- data/lib/action_dispatch/routing.rb +1 -2
- data/lib/action_dispatch/routing/mapper.rb +108 -107
- data/lib/action_dispatch/routing/redirection.rb +63 -69
- data/lib/action_dispatch/routing/route_set.rb +75 -43
- data/lib/action_dispatch/routing/routes_proxy.rb +0 -4
- data/lib/action_dispatch/routing/url_for.rb +3 -3
- data/lib/action_dispatch/testing/assertions/response.rb +5 -7
- data/lib/action_dispatch/testing/assertions/routing.rb +10 -9
- data/lib/action_dispatch/testing/integration.rb +8 -25
- data/lib/action_dispatch/testing/test_process.rb +3 -2
- data/lib/action_dispatch/testing/test_request.rb +4 -23
- data/lib/action_pack/version.rb +3 -3
- data/lib/action_view.rb +1 -5
- data/lib/action_view/asset_paths.rb +7 -8
- data/lib/action_view/base.rb +7 -5
- data/lib/action_view/helpers/asset_paths.rb +1 -1
- data/lib/action_view/helpers/asset_tag_helper.rb +4 -8
- data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +3 -0
- data/lib/action_view/helpers/atom_feed_helper.rb +2 -2
- data/lib/action_view/helpers/capture_helper.rb +3 -3
- data/lib/action_view/helpers/controller_helper.rb +1 -1
- data/lib/action_view/helpers/date_helper.rb +26 -18
- data/lib/action_view/helpers/debug_helper.rb +1 -1
- data/lib/action_view/helpers/form_helper.rb +71 -13
- data/lib/action_view/helpers/form_options_helper.rb +65 -34
- data/lib/action_view/helpers/form_tag_helper.rb +24 -18
- data/lib/action_view/helpers/javascript_helper.rb +12 -3
- data/lib/action_view/helpers/number_helper.rb +3 -2
- data/lib/action_view/helpers/record_tag_helper.rb +51 -5
- data/lib/action_view/helpers/rendering_helper.rb +2 -2
- data/lib/action_view/helpers/sanitize_helper.rb +6 -7
- data/lib/action_view/helpers/tag_helper.rb +1 -1
- data/lib/action_view/helpers/text_helper.rb +5 -4
- data/lib/action_view/helpers/url_helper.rb +19 -11
- data/lib/action_view/locale/en.yml +6 -0
- data/lib/action_view/log_subscriber.rb +1 -1
- data/lib/action_view/lookup_context.rb +123 -125
- data/lib/action_view/path_set.rb +60 -13
- data/lib/action_view/renderer/abstract_renderer.rb +16 -11
- data/lib/action_view/renderer/partial_renderer.rb +59 -40
- data/lib/action_view/renderer/template_renderer.rb +29 -17
- data/lib/action_view/template.rb +0 -1
- data/lib/action_view/template/error.rb +6 -5
- data/lib/action_view/template/handlers.rb +0 -6
- data/lib/action_view/template/handlers/builder.rb +10 -1
- data/lib/action_view/template/handlers/erb.rb +2 -2
- data/lib/action_view/template/resolver.rb +20 -31
- data/lib/action_view/test_case.rb +7 -10
- data/lib/sprockets/assets.rake +1 -1
- data/lib/sprockets/bootstrap.rb +3 -31
- data/lib/sprockets/compressors.rb +69 -7
- data/lib/sprockets/helpers/rails_helper.rb +6 -11
- data/lib/sprockets/railtie.rb +1 -0
- data/lib/sprockets/static_compiler.rb +0 -3
- metadata +57 -86
- checksums.yaml +0 -7
- data/lib/action_dispatch/middleware/closed_error.rb +0 -7
- data/lib/action_dispatch/routing/route.rb +0 -67
- data/lib/action_view/template/handler.rb +0 -49
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'action_view/helpers/tag_helper'
|
2
|
+
require 'active_support/core_ext/string/encoding'
|
2
3
|
|
3
4
|
module ActionView
|
4
5
|
module Helpers
|
@@ -10,15 +11,23 @@ module ActionView
|
|
10
11
|
"\n" => '\n',
|
11
12
|
"\r" => '\n',
|
12
13
|
'"' => '\\"',
|
13
|
-
"'" => "\\'"
|
14
|
+
"'" => "\\'"
|
15
|
+
}
|
14
16
|
|
15
|
-
|
17
|
+
if "ruby".encoding_aware?
|
18
|
+
JS_ESCAPE_MAP["\342\200\250".force_encoding('UTF-8').encode!] = '
'
|
19
|
+
else
|
20
|
+
JS_ESCAPE_MAP["\342\200\250"] = '
'
|
21
|
+
end
|
22
|
+
|
23
|
+
# Escapes carriage returns and single and double quotes for JavaScript segments.
|
24
|
+
#
|
16
25
|
# Also available through the alias j(). This is particularly helpful in JavaScript responses, like:
|
17
26
|
#
|
18
27
|
# $('some_element').replaceWith('<%=j render 'some/element_template' %>');
|
19
28
|
def escape_javascript(javascript)
|
20
29
|
if javascript
|
21
|
-
result = javascript.gsub(/(\\|<\/|\r\n|[\n\r"'])/) {|match| JS_ESCAPE_MAP[match] }
|
30
|
+
result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|[\n\r"'])/u) {|match| JS_ESCAPE_MAP[match] }
|
22
31
|
javascript.html_safe? ? result.html_safe : result
|
23
32
|
else
|
24
33
|
''
|
@@ -69,7 +69,7 @@ module ActionView
|
|
69
69
|
number.gsub!(/(\d{1,3})(\d{3})(\d{4}$)/,"(\\1) \\2#{delimiter}\\3")
|
70
70
|
else
|
71
71
|
number.gsub!(/(\d{0,3})(\d{3})(\d{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3")
|
72
|
-
number.slice!(0, 1) if number.starts_with?(
|
72
|
+
number.slice!(0, 1) if number.starts_with?(delimiter) && !delimiter.blank?
|
73
73
|
end
|
74
74
|
|
75
75
|
str = []
|
@@ -193,7 +193,8 @@ module ActionView
|
|
193
193
|
# number_with_delimiter(12345678) # => 12,345,678
|
194
194
|
# number_with_delimiter(12345678.05) # => 12,345,678.05
|
195
195
|
# number_with_delimiter(12345678, :delimiter => ".") # => 12.345.678
|
196
|
-
# number_with_delimiter(12345678, :
|
196
|
+
# number_with_delimiter(12345678, :delimiter => ",") # => 12,345,678
|
197
|
+
# number_with_delimiter(12345678.05, :separator => " ") # => 12,345,678 05
|
197
198
|
# number_with_delimiter(12345678.05, :locale => :fr) # => 12 345 678,05
|
198
199
|
# number_with_delimiter(98765432.98, :delimiter => " ", :separator => ",")
|
199
200
|
# # => 98 765 432,98
|
@@ -17,6 +17,19 @@ module ActionView
|
|
17
17
|
#
|
18
18
|
# <div id="person_123" class="person foo"> Joe Bloggs </div>
|
19
19
|
#
|
20
|
+
# You can also pass an array of Active Record objects, which will then
|
21
|
+
# get iterated over and yield each record as an argument for the block.
|
22
|
+
# For example:
|
23
|
+
#
|
24
|
+
# <%= div_for(@people, :class => "foo") do |person| %>
|
25
|
+
# <%= person.name %>
|
26
|
+
# <% end %>
|
27
|
+
#
|
28
|
+
# produces:
|
29
|
+
#
|
30
|
+
# <div id="person_123" class="person foo"> Joe Bloggs </div>
|
31
|
+
# <div id="person_124" class="person foo"> Jane Bloggs </div>
|
32
|
+
#
|
20
33
|
def div_for(record, *args, &block)
|
21
34
|
content_tag_for(:div, record, *args, &block)
|
22
35
|
end
|
@@ -42,6 +55,21 @@ module ActionView
|
|
42
55
|
#
|
43
56
|
# <tr id="foo_person_123" class="person">...
|
44
57
|
#
|
58
|
+
# You can also pass an array of objects which this method will loop through
|
59
|
+
# and yield the current object to the supplied block, reducing the need for
|
60
|
+
# having to iterate through the object (using <tt>each</tt>) beforehand.
|
61
|
+
# For example (assuming @people is an array of Person objects):
|
62
|
+
#
|
63
|
+
# <%= content_tag_for(:tr, @people) do |person| %>
|
64
|
+
# <td><%= person.first_name %></td>
|
65
|
+
# <td><%= person.last_name %></td>
|
66
|
+
# <% end %>
|
67
|
+
#
|
68
|
+
# produces:
|
69
|
+
#
|
70
|
+
# <tr id="person_123" class="person">...</tr>
|
71
|
+
# <tr id="person_124" class="person">...</tr>
|
72
|
+
#
|
45
73
|
# content_tag_for also accepts a hash of options, which will be converted to
|
46
74
|
# additional HTML attributes. If you specify a <tt>:class</tt> value, it will be combined
|
47
75
|
# with the default class name for your object. For example:
|
@@ -52,12 +80,30 @@ module ActionView
|
|
52
80
|
#
|
53
81
|
# <li id="person_123" class="person bar">...
|
54
82
|
#
|
55
|
-
def content_tag_for(tag_name,
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
83
|
+
def content_tag_for(tag_name, single_or_multiple_records, prefix = nil, options = nil, &block)
|
84
|
+
if single_or_multiple_records.respond_to?(:to_ary)
|
85
|
+
single_or_multiple_records.to_ary.map do |single_record|
|
86
|
+
capture { content_tag_for_single_record(tag_name, single_record, prefix, options, &block) }
|
87
|
+
end.join("\n").html_safe
|
88
|
+
else
|
89
|
+
content_tag_for_single_record(tag_name, single_or_multiple_records, prefix, options, &block)
|
90
|
+
end
|
60
91
|
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
# Called by <tt>content_tag_for</tt> internally to render a content tag
|
96
|
+
# for each record.
|
97
|
+
def content_tag_for_single_record(tag_name, record, prefix, options, &block)
|
98
|
+
options, prefix = prefix, nil if prefix.is_a?(Hash)
|
99
|
+
options ||= {}
|
100
|
+
options.merge!({ :class => "#{dom_class(record, prefix)} #{options[:class]}".strip, :id => dom_id(record, prefix) })
|
101
|
+
if block.arity == 0
|
102
|
+
content_tag(tag_name, capture(&block), options)
|
103
|
+
else
|
104
|
+
content_tag(tag_name, capture(record, &block), options)
|
105
|
+
end
|
106
|
+
end
|
61
107
|
end
|
62
108
|
end
|
63
109
|
end
|
@@ -8,7 +8,7 @@ module ActionView
|
|
8
8
|
module RenderingHelper
|
9
9
|
# Returns the result of a render that's dictated by the options hash. The primary options are:
|
10
10
|
#
|
11
|
-
# * <tt>:partial</tt> - See ActionView::
|
11
|
+
# * <tt>:partial</tt> - See <tt>ActionView::PartialRenderer</tt>.
|
12
12
|
# * <tt>:file</tt> - Renders an explicit template file (this used to be the old default), add :locals to pass in those.
|
13
13
|
# * <tt>:inline</tt> - Renders an inline template similar to how it's done in the controller.
|
14
14
|
# * <tt>:text</tt> - Renders the text passed in out.
|
@@ -87,4 +87,4 @@ module ActionView
|
|
87
87
|
end
|
88
88
|
end
|
89
89
|
end
|
90
|
-
end
|
90
|
+
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'active_support/core_ext/object/try'
|
2
2
|
require 'action_controller/vendor/html-scanner'
|
3
|
-
require 'action_view/helpers/tag_helper'
|
4
3
|
|
5
4
|
module ActionView
|
6
5
|
# = Action View Sanitize Helpers
|
@@ -14,13 +13,13 @@ module ActionView
|
|
14
13
|
#
|
15
14
|
# It also strips href/src tags with invalid protocols, like javascript: especially.
|
16
15
|
# It does its best to counter any tricks that hackers may use, like throwing in
|
17
|
-
# unicode/ascii/hex values to get past the javascript: filters.
|
16
|
+
# unicode/ascii/hex values to get past the javascript: filters. Check out
|
18
17
|
# the extensive test suite.
|
19
18
|
#
|
20
19
|
# <%= sanitize @article.body %>
|
21
20
|
#
|
22
21
|
# You can add or remove tags/attributes if you want to customize it a bit.
|
23
|
-
# See ActionView::Base for full docs on the available options.
|
22
|
+
# See ActionView::Base for full docs on the available options. You can add
|
24
23
|
# tags/attributes for single uses of +sanitize+ by passing either the
|
25
24
|
# <tt>:attributes</tt> or <tt>:tags</tt> options:
|
26
25
|
#
|
@@ -66,7 +65,7 @@ module ActionView
|
|
66
65
|
self.class.white_list_sanitizer.sanitize_css(style)
|
67
66
|
end
|
68
67
|
|
69
|
-
# Strips all HTML tags from the +html+, including comments.
|
68
|
+
# Strips all HTML tags from the +html+, including comments. This uses the
|
70
69
|
# html-scanner tokenizer and so its HTML parsing ability is limited by
|
71
70
|
# that of html-scanner.
|
72
71
|
#
|
@@ -81,7 +80,7 @@ module ActionView
|
|
81
80
|
# strip_tags("<div id='top-bar'>Welcome to my website!</div>")
|
82
81
|
# # => Welcome to my website!
|
83
82
|
def strip_tags(html)
|
84
|
-
self.class.full_sanitizer.sanitize(html)
|
83
|
+
self.class.full_sanitizer.sanitize(html).try(:html_safe)
|
85
84
|
end
|
86
85
|
|
87
86
|
# Strips all link tags from +text+ leaving just the link text.
|
@@ -142,7 +141,7 @@ module ActionView
|
|
142
141
|
white_list_sanitizer.protocol_separator = value
|
143
142
|
end
|
144
143
|
|
145
|
-
# Gets the HTML::FullSanitizer instance used by +strip_tags+.
|
144
|
+
# Gets the HTML::FullSanitizer instance used by +strip_tags+. Replace with
|
146
145
|
# any object that responds to +sanitize+.
|
147
146
|
#
|
148
147
|
# class Application < Rails::Application
|
@@ -153,7 +152,7 @@ module ActionView
|
|
153
152
|
@full_sanitizer ||= HTML::FullSanitizer.new
|
154
153
|
end
|
155
154
|
|
156
|
-
# Gets the HTML::LinkSanitizer instance used by +strip_links+.
|
155
|
+
# Gets the HTML::LinkSanitizer instance used by +strip_links+. Replace with
|
157
156
|
# any object that responds to +sanitize+.
|
158
157
|
#
|
159
158
|
# class Application < Rails::Application
|
@@ -94,7 +94,7 @@ module ActionView
|
|
94
94
|
end
|
95
95
|
end
|
96
96
|
|
97
|
-
# Returns a CDATA section with the given +content+.
|
97
|
+
# Returns a CDATA section with the given +content+. CDATA sections
|
98
98
|
# are used to escape blocks of text containing characters which would
|
99
99
|
# otherwise be recognized as markup. CDATA sections begin with the string
|
100
100
|
# <tt><![CDATA[</tt> and end with (and may not contain) the string <tt>]]></tt>.
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'active_support/core_ext/object/blank'
|
2
2
|
require 'active_support/core_ext/string/filters'
|
3
|
-
require 'action_view/helpers/tag_helper'
|
4
3
|
|
5
4
|
module ActionView
|
6
5
|
# = Action View Text Helpers
|
@@ -31,6 +30,7 @@ module ActionView
|
|
31
30
|
extend ActiveSupport::Concern
|
32
31
|
|
33
32
|
include SanitizeHelper
|
33
|
+
include TagHelper
|
34
34
|
# The preferred method of outputting text in your views is to use the
|
35
35
|
# <%= "text" %> eRuby syntax. The regular _puts_ and _print_ methods
|
36
36
|
# do not operate as expected in an eRuby code block. If you absolutely must
|
@@ -120,7 +120,7 @@ module ActionView
|
|
120
120
|
text
|
121
121
|
else
|
122
122
|
match = Array(phrases).map { |p| Regexp.escape(p) }.join('|')
|
123
|
-
text.gsub(/(#{match})(?!
|
123
|
+
text.gsub(/(#{match})(?![^<]*?>)/i, options[:highlighter])
|
124
124
|
end.html_safe
|
125
125
|
end
|
126
126
|
|
@@ -232,7 +232,7 @@ module ActionView
|
|
232
232
|
# considered as a linebreak and a <tt><br /></tt> tag is appended. This
|
233
233
|
# method does not remove the newlines from the +text+.
|
234
234
|
#
|
235
|
-
# You can pass any HTML attributes into <tt>html_options</tt>.
|
235
|
+
# You can pass any HTML attributes into <tt>html_options</tt>. These
|
236
236
|
# will be added to all created paragraphs.
|
237
237
|
#
|
238
238
|
# ==== Options
|
@@ -256,6 +256,7 @@ module ActionView
|
|
256
256
|
# # => "<p><span>I'm allowed!</span> It's true.</p>"
|
257
257
|
def simple_format(text, html_options={}, options={})
|
258
258
|
text = '' if text.nil?
|
259
|
+
text = text.dup
|
259
260
|
start_tag = tag('p', html_options, true)
|
260
261
|
text = sanitize(text) unless options[:sanitize] == false
|
261
262
|
text = text.to_str
|
@@ -268,7 +269,7 @@ module ActionView
|
|
268
269
|
|
269
270
|
# Creates a Cycle object whose _to_s_ method cycles through elements of an
|
270
271
|
# array every time it is called. This can be used for example, to alternate
|
271
|
-
# classes for table rows.
|
272
|
+
# classes for table rows. You can use named cycles to allow nesting in loops.
|
272
273
|
# Passing a Hash as the last parameter with a <tt>:name</tt> key will create a
|
273
274
|
# named cycle. The default name for a cycle without a +:name+ key is
|
274
275
|
# <tt>"default"</tt>. You can manually reset a cycle by calling reset_cycle
|
@@ -160,7 +160,7 @@ module ActionView
|
|
160
160
|
#
|
161
161
|
# ==== Examples
|
162
162
|
# Because it relies on +url_for+, +link_to+ supports both older-style controller/action/id arguments
|
163
|
-
# and newer RESTful routes.
|
163
|
+
# and newer RESTful routes. Current Rails style favors RESTful routes whenever possible, so base
|
164
164
|
# your application on resources and use
|
165
165
|
#
|
166
166
|
# link_to "Profile", profile_path(@profile)
|
@@ -358,7 +358,7 @@ module ActionView
|
|
358
358
|
# Creates a link tag of the given +name+ using a URL created by the set of
|
359
359
|
# +options+ unless the current request URI is the same as the links, in
|
360
360
|
# which case only the name is returned (or the given block is yielded, if
|
361
|
-
# one exists).
|
361
|
+
# one exists). You can give +link_to_unless_current+ a block which will
|
362
362
|
# specialize the default behavior (e.g., show a "Start Here" link rather
|
363
363
|
# than the link's text).
|
364
364
|
#
|
@@ -385,7 +385,7 @@ module ActionView
|
|
385
385
|
# </ul>
|
386
386
|
#
|
387
387
|
# The implicit block given to +link_to_unless_current+ is evaluated if the current
|
388
|
-
# action is the action given.
|
388
|
+
# action is the action given. So, if we had a comments page and wanted to render a
|
389
389
|
# "Go Back" link instead of a link to the comments page, we could do something like this...
|
390
390
|
#
|
391
391
|
# <%=
|
@@ -579,6 +579,12 @@ module ActionView
|
|
579
579
|
#
|
580
580
|
# current_page?(:controller => 'library', :action => 'checkout')
|
581
581
|
# # => false
|
582
|
+
#
|
583
|
+
# Let's say we're in the <tt>/products</tt> action with method POST in case of invalid product.
|
584
|
+
#
|
585
|
+
# current_page?(:controller => 'product', :action => 'index')
|
586
|
+
# # => false
|
587
|
+
#
|
582
588
|
def current_page?(options)
|
583
589
|
unless request
|
584
590
|
raise "You cannot use helpers that need to determine the current " \
|
@@ -586,10 +592,12 @@ module ActionView
|
|
586
592
|
"in a #request method"
|
587
593
|
end
|
588
594
|
|
595
|
+
return false unless request.get?
|
596
|
+
|
589
597
|
url_string = url_for(options)
|
590
598
|
|
591
599
|
# We ignore any extra parameters in the request_uri if the
|
592
|
-
# submitted url doesn't have any either.
|
600
|
+
# submitted url doesn't have any either. This lets the function
|
593
601
|
# work with things like ?order=asc
|
594
602
|
if url_string.index("?")
|
595
603
|
request_uri = request.fullpath
|
@@ -606,9 +614,7 @@ module ActionView
|
|
606
614
|
|
607
615
|
private
|
608
616
|
def convert_options_to_data_attributes(options, html_options)
|
609
|
-
if html_options
|
610
|
-
link_to_remote_options?(options) ? {'data-remote' => 'true'} : {}
|
611
|
-
else
|
617
|
+
if html_options
|
612
618
|
html_options = html_options.stringify_keys
|
613
619
|
html_options['data-remote'] = 'true' if link_to_remote_options?(options) || link_to_remote_options?(html_options)
|
614
620
|
|
@@ -621,6 +627,8 @@ module ActionView
|
|
621
627
|
add_method_to_attributes!(html_options, method) if method
|
622
628
|
|
623
629
|
html_options
|
630
|
+
else
|
631
|
+
link_to_remote_options?(options) ? {'data-remote' => 'true'} : {}
|
624
632
|
end
|
625
633
|
end
|
626
634
|
|
@@ -629,8 +637,8 @@ module ActionView
|
|
629
637
|
end
|
630
638
|
|
631
639
|
def add_method_to_attributes!(html_options, method)
|
632
|
-
if method && method.to_s.downcase != "get"
|
633
|
-
html_options["rel"] = "#{html_options["rel"]
|
640
|
+
if method && method.to_s.downcase != "get" && html_options["rel"] !~ /nofollow/
|
641
|
+
html_options["rel"] = "#{html_options["rel"]} nofollow".strip
|
634
642
|
end
|
635
643
|
html_options["data-method"] = method
|
636
644
|
end
|
@@ -653,7 +661,7 @@ module ActionView
|
|
653
661
|
|
654
662
|
# Processes the +html_options+ hash, converting the boolean
|
655
663
|
# attributes from true/false form into the form required by
|
656
|
-
# HTML/XHTML.
|
664
|
+
# HTML/XHTML. (An attribute is considered to be boolean if
|
657
665
|
# its name is listed in the given +bool_attrs+ array.)
|
658
666
|
#
|
659
667
|
# More specifically, for each boolean attribute in +html_options+
|
@@ -663,7 +671,7 @@ module ActionView
|
|
663
671
|
#
|
664
672
|
# if the associated +bool_value+ evaluates to true, it is
|
665
673
|
# replaced with the attribute's name; otherwise the attribute is
|
666
|
-
# removed from the +html_options+ hash.
|
674
|
+
# removed from the +html_options+ hash. (See the XHTML 1.0 spec,
|
667
675
|
# section 4.5 "Attribute Minimization" for more:
|
668
676
|
# http://www.w3.org/TR/xhtml1/#h-4.5)
|
669
677
|
#
|
@@ -4,7 +4,7 @@ module ActionView
|
|
4
4
|
# Provides functionality so that Rails can output logs from Action View.
|
5
5
|
class LogSubscriber < ActiveSupport::LogSubscriber
|
6
6
|
def render_template(event)
|
7
|
-
message = "Rendered #{from_rails_root(event.payload[:identifier])}"
|
7
|
+
message = " Rendered #{from_rails_root(event.payload[:identifier])}"
|
8
8
|
message << " within #{from_rails_root(event.payload[:layout])}" if event.payload[:layout]
|
9
9
|
message << (" (%.1fms)" % event.duration)
|
10
10
|
info(message)
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'active_support/core_ext/array/wrap'
|
2
2
|
require 'active_support/core_ext/object/blank'
|
3
|
+
require 'active_support/core_ext/module/remove_method'
|
3
4
|
|
4
5
|
module ActionView
|
5
6
|
# = Action View Lookup Context
|
@@ -17,23 +18,25 @@ module ActionView
|
|
17
18
|
mattr_accessor :registered_details
|
18
19
|
self.registered_details = []
|
19
20
|
|
20
|
-
mattr_accessor :registered_detail_setters
|
21
|
-
self.registered_detail_setters = []
|
22
|
-
|
23
21
|
def self.register_detail(name, options = {}, &block)
|
24
22
|
self.registered_details << name
|
25
|
-
|
23
|
+
initialize = registered_details.map { |n| "@details[:#{n}] = details[:#{n}] || default_#{n}" }
|
26
24
|
|
27
|
-
Accessors.send :define_method, :"
|
25
|
+
Accessors.send :define_method, :"default_#{name}", &block
|
28
26
|
Accessors.module_eval <<-METHOD, __FILE__, __LINE__ + 1
|
29
27
|
def #{name}
|
30
28
|
@details[:#{name}]
|
31
29
|
end
|
32
30
|
|
33
31
|
def #{name}=(value)
|
34
|
-
value = Array.wrap(value
|
32
|
+
value = value.present? ? Array.wrap(value) : default_#{name}
|
35
33
|
_set_detail(:#{name}, value) if value != @details[:#{name}]
|
36
34
|
end
|
35
|
+
|
36
|
+
remove_possible_method :initialize_details
|
37
|
+
def initialize_details(details)
|
38
|
+
#{initialize.join("\n")}
|
39
|
+
end
|
37
40
|
METHOD
|
38
41
|
end
|
39
42
|
|
@@ -41,8 +44,9 @@ module ActionView
|
|
41
44
|
module Accessors #:nodoc:
|
42
45
|
end
|
43
46
|
|
47
|
+
register_detail(:locale) { [I18n.locale, I18n.default_locale].uniq }
|
44
48
|
register_detail(:formats) { Mime::SET.symbols }
|
45
|
-
register_detail(:
|
49
|
+
register_detail(:handlers){ Template::Handlers.extensions }
|
46
50
|
|
47
51
|
class DetailsKey #:nodoc:
|
48
52
|
alias :eql? :equal?
|
@@ -52,7 +56,11 @@ module ActionView
|
|
52
56
|
@details_keys = Hash.new
|
53
57
|
|
54
58
|
def self.get(details)
|
55
|
-
@details_keys[details
|
59
|
+
@details_keys[details] ||= new
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.clear
|
63
|
+
@details_keys.clear
|
56
64
|
end
|
57
65
|
|
58
66
|
def initialize
|
@@ -60,38 +68,54 @@ module ActionView
|
|
60
68
|
end
|
61
69
|
end
|
62
70
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
@cache = true
|
67
|
-
@prefixes = prefixes
|
71
|
+
# Add caching behavior on top of Details.
|
72
|
+
module DetailsCache
|
73
|
+
attr_accessor :cache
|
68
74
|
|
69
|
-
|
70
|
-
|
71
|
-
|
75
|
+
# Calculate the details key. Remove the handlers from calculation to improve performance
|
76
|
+
# since the user cannot modify it explicitly.
|
77
|
+
def details_key #:nodoc:
|
78
|
+
@details_key ||= DetailsKey.get(@details) if @cache
|
79
|
+
end
|
80
|
+
|
81
|
+
# Temporary skip passing the details_key forward.
|
82
|
+
def disable_cache
|
83
|
+
old_value, @cache = @cache, false
|
84
|
+
yield
|
85
|
+
ensure
|
86
|
+
@cache = old_value
|
87
|
+
end
|
88
|
+
|
89
|
+
protected
|
90
|
+
|
91
|
+
def _set_detail(key, value)
|
92
|
+
@details = @details.dup if @details_key
|
93
|
+
@details_key = nil
|
94
|
+
@details[key] = value
|
72
95
|
end
|
73
96
|
end
|
74
97
|
|
98
|
+
# Helpers related to template lookup using the lookup context information.
|
75
99
|
module ViewPaths
|
76
100
|
attr_reader :view_paths
|
77
101
|
|
78
102
|
# Whenever setting view paths, makes a copy so we can manipulate then in
|
79
103
|
# instance objects as we wish.
|
80
104
|
def view_paths=(paths)
|
81
|
-
@view_paths = ActionView::
|
105
|
+
@view_paths = ActionView::PathSet.new(Array.wrap(paths))
|
82
106
|
end
|
83
107
|
|
84
|
-
def find(name, prefixes = [], partial = false, keys = [])
|
85
|
-
@view_paths.find(*args_for_lookup(name, prefixes, partial, keys))
|
108
|
+
def find(name, prefixes = [], partial = false, keys = [], options = {})
|
109
|
+
@view_paths.find(*args_for_lookup(name, prefixes, partial, keys, options))
|
86
110
|
end
|
87
111
|
alias :find_template :find
|
88
112
|
|
89
|
-
def find_all(name, prefixes = [], partial = false, keys = [])
|
90
|
-
@view_paths.find_all(*args_for_lookup(name, prefixes, partial, keys))
|
113
|
+
def find_all(name, prefixes = [], partial = false, keys = [], options = {})
|
114
|
+
@view_paths.find_all(*args_for_lookup(name, prefixes, partial, keys, options))
|
91
115
|
end
|
92
116
|
|
93
|
-
def exists?(name, prefixes = [], partial = false, keys = [])
|
94
|
-
@view_paths.exists?(*args_for_lookup(name, prefixes, partial, keys))
|
117
|
+
def exists?(name, prefixes = [], partial = false, keys = [], options = {})
|
118
|
+
@view_paths.exists?(*args_for_lookup(name, prefixes, partial, keys, options))
|
95
119
|
end
|
96
120
|
alias :template_exists? :exists?
|
97
121
|
|
@@ -110,30 +134,39 @@ module ActionView
|
|
110
134
|
|
111
135
|
protected
|
112
136
|
|
113
|
-
def args_for_lookup(name, prefixes, partial, keys) #:nodoc:
|
137
|
+
def args_for_lookup(name, prefixes, partial, keys, details_options) #:nodoc:
|
114
138
|
name, prefixes = normalize_name(name, prefixes)
|
115
|
-
|
139
|
+
details, details_key = detail_args_for(details_options)
|
140
|
+
[name, prefixes, partial || false, details, details_key, keys]
|
141
|
+
end
|
142
|
+
|
143
|
+
# Compute details hash and key according to user options (e.g. passed from #render).
|
144
|
+
def detail_args_for(options)
|
145
|
+
return @details, details_key if options.empty? # most common path.
|
146
|
+
user_details = @details.merge(options)
|
147
|
+
[user_details, DetailsKey.get(user_details)]
|
116
148
|
end
|
117
149
|
|
118
150
|
# Support legacy foo.erb names even though we now ignore .erb
|
119
151
|
# as well as incorrectly putting part of the path in the template
|
120
152
|
# name instead of the prefix.
|
121
153
|
def normalize_name(name, prefixes) #:nodoc:
|
122
|
-
name = name.to_s.
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
prefixes = if prefixes.blank?
|
127
|
-
[parts.join('/')]
|
128
|
-
else
|
129
|
-
prefixes.map { |prefix| [prefix, *parts].compact.join('/') }
|
154
|
+
name = name.to_s.sub(handlers_regexp) do |match|
|
155
|
+
ActiveSupport::Deprecation.warn "Passing a template handler in the template name is deprecated. " \
|
156
|
+
"You can simply remove the handler name or pass render :handlers => [:#{match[1..-1]}] instead.", caller
|
157
|
+
""
|
130
158
|
end
|
131
159
|
|
132
|
-
|
133
|
-
|
160
|
+
prefixes = nil if prefixes.blank?
|
161
|
+
parts = name.split('/')
|
162
|
+
name = parts.pop
|
163
|
+
|
164
|
+
return name, prefixes || [""] if parts.empty?
|
165
|
+
|
166
|
+
parts = parts.join('/')
|
167
|
+
prefixes = prefixes ? prefixes.map { |p| "#{p}/#{parts}" } : [parts]
|
134
168
|
|
135
|
-
|
136
|
-
@@default_handlers ||= Template::Handlers.extensions
|
169
|
+
return name, prefixes
|
137
170
|
end
|
138
171
|
|
139
172
|
def handlers_regexp #:nodoc:
|
@@ -141,111 +174,76 @@ module ActionView
|
|
141
174
|
end
|
142
175
|
end
|
143
176
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
# Calculate the details key. Remove the handlers from calculation to improve performance
|
148
|
-
# since the user cannot modify it explicitly.
|
149
|
-
def details_key #:nodoc:
|
150
|
-
@details_key ||= DetailsKey.get(@details) if @cache
|
151
|
-
end
|
152
|
-
|
153
|
-
# Temporary skip passing the details_key forward.
|
154
|
-
def disable_cache
|
155
|
-
old_value, @cache = @cache, false
|
156
|
-
yield
|
157
|
-
ensure
|
158
|
-
@cache = old_value
|
159
|
-
end
|
177
|
+
include Accessors
|
178
|
+
include DetailsCache
|
179
|
+
include ViewPaths
|
160
180
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
self.formats = formats
|
167
|
-
@frozen_formats = true
|
168
|
-
end
|
181
|
+
def initialize(view_paths, details = {}, prefixes = [])
|
182
|
+
@details, @details_key = {}, nil
|
183
|
+
@frozen_formats, @skip_default_locale = false, false
|
184
|
+
@cache = true
|
185
|
+
@prefixes = prefixes
|
169
186
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
if values
|
174
|
-
values.concat(_formats_defaults) if values.delete "*/*"
|
175
|
-
values << :html if values == [:js]
|
176
|
-
end
|
177
|
-
super(values)
|
178
|
-
end
|
187
|
+
self.view_paths = view_paths
|
188
|
+
initialize_details(details)
|
189
|
+
end
|
179
190
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
191
|
+
# Freeze the current formats in the lookup context. By freezing them, you
|
192
|
+
# that next template lookups are not going to modify the formats. The con
|
193
|
+
# use this, to ensure that formats won't be further modified (as it does
|
194
|
+
def freeze_formats(formats, unless_frozen=false) #:nodoc:
|
195
|
+
return if unless_frozen && @frozen_formats
|
196
|
+
self.formats = formats
|
197
|
+
@frozen_formats = true
|
198
|
+
end
|
185
199
|
|
186
|
-
|
187
|
-
|
188
|
-
|
200
|
+
# Override formats= to expand ["*/*"] values and automatically
|
201
|
+
# add :html as fallback to :js.
|
202
|
+
def formats=(values)
|
203
|
+
if values
|
204
|
+
values.concat(default_formats) if values.delete "*/*"
|
205
|
+
values << :html if values == [:js]
|
189
206
|
end
|
207
|
+
super(values)
|
208
|
+
end
|
190
209
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
config = I18n.config.respond_to?(:original_config) ? I18n.config.original_config : I18n.config
|
197
|
-
config.locale = value
|
198
|
-
end
|
210
|
+
# Do not use the default locale on template lookup.
|
211
|
+
def skip_default_locale!
|
212
|
+
@skip_default_locale = true
|
213
|
+
self.locale = nil
|
214
|
+
end
|
199
215
|
|
200
|
-
|
201
|
-
|
216
|
+
# Override locale to return a symbol instead of array.
|
217
|
+
def locale
|
218
|
+
@details[:locale].first
|
219
|
+
end
|
202
220
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
_set_detail(:formats, formats[0,1])
|
211
|
-
|
212
|
-
begin
|
213
|
-
yield
|
214
|
-
ensure
|
215
|
-
_set_detail(:formats, old_formats)
|
216
|
-
end
|
217
|
-
end
|
221
|
+
# Overload locale= to also set the I18n.locale. If the current I18n.config object responds
|
222
|
+
# to original_config, it means that it's has a copy of the original I18n configuration and it's
|
223
|
+
# acting as proxy, which we need to skip.
|
224
|
+
def locale=(value)
|
225
|
+
if value
|
226
|
+
config = I18n.config.respond_to?(:original_config) ? I18n.config.original_config : I18n.config
|
227
|
+
config.locale = value
|
218
228
|
end
|
219
229
|
|
220
|
-
|
221
|
-
|
222
|
-
# the execution of the block and reverted to the previous value after.
|
223
|
-
def update_details(new_details)
|
224
|
-
old_details = @details.dup
|
230
|
+
super(@skip_default_locale ? I18n.locale : default_locale)
|
231
|
+
end
|
225
232
|
|
226
|
-
|
227
|
-
|
228
|
-
|
233
|
+
# A method which only uses the first format in the formats array for layout lookup.
|
234
|
+
def with_layout_format
|
235
|
+
if formats.size == 1
|
236
|
+
yield
|
237
|
+
else
|
238
|
+
old_formats = formats
|
239
|
+
_set_detail(:formats, formats[0,1])
|
229
240
|
|
230
241
|
begin
|
231
242
|
yield
|
232
243
|
ensure
|
233
|
-
|
234
|
-
@details = old_details
|
244
|
+
_set_detail(:formats, old_formats)
|
235
245
|
end
|
236
246
|
end
|
237
|
-
|
238
|
-
protected
|
239
|
-
|
240
|
-
def _set_detail(key, value)
|
241
|
-
@details_key = nil
|
242
|
-
@details = @details.dup if @details.frozen?
|
243
|
-
@details[key] = value.freeze
|
244
|
-
end
|
245
247
|
end
|
246
|
-
|
247
|
-
include Accessors
|
248
|
-
include Details
|
249
|
-
include ViewPaths
|
250
248
|
end
|
251
249
|
end
|