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.

Files changed (128) hide show
  1. data/CHANGELOG.md +5503 -108
  2. data/README.rdoc +3 -3
  3. data/lib/abstract_controller/asset_paths.rb +1 -1
  4. data/lib/abstract_controller/base.rb +1 -1
  5. data/lib/abstract_controller/callbacks.rb +102 -18
  6. data/lib/abstract_controller/helpers.rb +1 -1
  7. data/lib/abstract_controller/layouts.rb +116 -50
  8. data/lib/abstract_controller/logger.rb +1 -1
  9. data/lib/abstract_controller/railties/routes_helpers.rb +2 -2
  10. data/lib/abstract_controller/rendering.rb +1 -6
  11. data/lib/abstract_controller/view_paths.rb +6 -5
  12. data/lib/action_controller.rb +0 -15
  13. data/lib/action_controller/caching.rb +0 -1
  14. data/lib/action_controller/caching/actions.rb +5 -6
  15. data/lib/action_controller/caching/fragments.rb +18 -18
  16. data/lib/action_controller/caching/pages.rb +7 -6
  17. data/lib/action_controller/caching/sweeping.rb +1 -1
  18. data/lib/action_controller/log_subscriber.rb +8 -4
  19. data/lib/action_controller/metal.rb +7 -1
  20. data/lib/action_controller/metal/conditional_get.rb +49 -4
  21. data/lib/action_controller/metal/data_streaming.rb +17 -5
  22. data/lib/action_controller/metal/force_ssl.rb +8 -5
  23. data/lib/action_controller/metal/helpers.rb +7 -4
  24. data/lib/action_controller/metal/http_authentication.rb +9 -12
  25. data/lib/action_controller/metal/instrumentation.rb +9 -4
  26. data/lib/action_controller/metal/mime_responds.rb +4 -4
  27. data/lib/action_controller/metal/params_wrapper.rb +12 -8
  28. data/lib/action_controller/metal/redirecting.rb +7 -6
  29. data/lib/action_controller/metal/renderers.rb +9 -11
  30. data/lib/action_controller/metal/request_forgery_protection.rb +2 -1
  31. data/lib/action_controller/metal/rescue.rb +13 -0
  32. data/lib/action_controller/metal/responder.rb +11 -23
  33. data/lib/action_controller/metal/streaming.rb +0 -25
  34. data/lib/action_controller/railtie.rb +1 -0
  35. data/lib/action_controller/railties/paths.rb +4 -3
  36. data/lib/action_controller/record_identifier.rb +4 -4
  37. data/lib/action_controller/test_case.rb +60 -56
  38. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +6 -6
  39. data/lib/action_dispatch.rb +5 -1
  40. data/lib/action_dispatch/http/cache.rb +27 -15
  41. data/lib/action_dispatch/http/filter_parameters.rb +3 -1
  42. data/lib/action_dispatch/http/headers.rb +3 -5
  43. data/lib/action_dispatch/http/mime_negotiation.rb +2 -1
  44. data/lib/action_dispatch/http/mime_type.rb +7 -3
  45. data/lib/action_dispatch/http/mime_types.rb +12 -0
  46. data/lib/action_dispatch/http/parameter_filter.rb +3 -1
  47. data/lib/action_dispatch/http/parameters.rb +0 -4
  48. data/lib/action_dispatch/http/request.rb +18 -68
  49. data/lib/action_dispatch/http/response.rb +11 -32
  50. data/lib/action_dispatch/http/upload.rb +3 -14
  51. data/lib/action_dispatch/http/url.rb +1 -1
  52. data/lib/action_dispatch/middleware/callbacks.rb +1 -2
  53. data/lib/action_dispatch/middleware/cookies.rb +20 -16
  54. data/lib/action_dispatch/middleware/debug_exceptions.rb +82 -0
  55. data/lib/action_dispatch/middleware/exception_wrapper.rb +78 -0
  56. data/lib/action_dispatch/middleware/flash.rb +6 -9
  57. data/lib/action_dispatch/middleware/params_parser.rb +6 -11
  58. data/lib/action_dispatch/middleware/public_exceptions.rb +30 -0
  59. data/lib/action_dispatch/middleware/reloader.rb +38 -14
  60. data/lib/action_dispatch/middleware/remote_ip.rb +66 -36
  61. data/lib/action_dispatch/middleware/request_id.rb +39 -0
  62. data/lib/action_dispatch/middleware/session/abstract_store.rb +4 -16
  63. data/lib/action_dispatch/middleware/session/cache_store.rb +50 -0
  64. data/lib/action_dispatch/middleware/session/cookie_store.rb +1 -1
  65. data/lib/action_dispatch/middleware/show_exceptions.rb +58 -142
  66. data/lib/action_dispatch/middleware/static.rb +2 -10
  67. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +1 -0
  68. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +13 -8
  69. data/lib/action_dispatch/railtie.rb +15 -1
  70. data/lib/action_dispatch/routing.rb +1 -2
  71. data/lib/action_dispatch/routing/mapper.rb +108 -107
  72. data/lib/action_dispatch/routing/redirection.rb +63 -69
  73. data/lib/action_dispatch/routing/route_set.rb +75 -43
  74. data/lib/action_dispatch/routing/routes_proxy.rb +0 -4
  75. data/lib/action_dispatch/routing/url_for.rb +3 -3
  76. data/lib/action_dispatch/testing/assertions/response.rb +5 -7
  77. data/lib/action_dispatch/testing/assertions/routing.rb +10 -9
  78. data/lib/action_dispatch/testing/integration.rb +8 -25
  79. data/lib/action_dispatch/testing/test_process.rb +3 -2
  80. data/lib/action_dispatch/testing/test_request.rb +4 -23
  81. data/lib/action_pack/version.rb +3 -3
  82. data/lib/action_view.rb +1 -5
  83. data/lib/action_view/asset_paths.rb +7 -8
  84. data/lib/action_view/base.rb +7 -5
  85. data/lib/action_view/helpers/asset_paths.rb +1 -1
  86. data/lib/action_view/helpers/asset_tag_helper.rb +4 -8
  87. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +3 -0
  88. data/lib/action_view/helpers/atom_feed_helper.rb +2 -2
  89. data/lib/action_view/helpers/capture_helper.rb +3 -3
  90. data/lib/action_view/helpers/controller_helper.rb +1 -1
  91. data/lib/action_view/helpers/date_helper.rb +26 -18
  92. data/lib/action_view/helpers/debug_helper.rb +1 -1
  93. data/lib/action_view/helpers/form_helper.rb +71 -13
  94. data/lib/action_view/helpers/form_options_helper.rb +65 -34
  95. data/lib/action_view/helpers/form_tag_helper.rb +24 -18
  96. data/lib/action_view/helpers/javascript_helper.rb +12 -3
  97. data/lib/action_view/helpers/number_helper.rb +3 -2
  98. data/lib/action_view/helpers/record_tag_helper.rb +51 -5
  99. data/lib/action_view/helpers/rendering_helper.rb +2 -2
  100. data/lib/action_view/helpers/sanitize_helper.rb +6 -7
  101. data/lib/action_view/helpers/tag_helper.rb +1 -1
  102. data/lib/action_view/helpers/text_helper.rb +5 -4
  103. data/lib/action_view/helpers/url_helper.rb +19 -11
  104. data/lib/action_view/locale/en.yml +6 -0
  105. data/lib/action_view/log_subscriber.rb +1 -1
  106. data/lib/action_view/lookup_context.rb +123 -125
  107. data/lib/action_view/path_set.rb +60 -13
  108. data/lib/action_view/renderer/abstract_renderer.rb +16 -11
  109. data/lib/action_view/renderer/partial_renderer.rb +59 -40
  110. data/lib/action_view/renderer/template_renderer.rb +29 -17
  111. data/lib/action_view/template.rb +0 -1
  112. data/lib/action_view/template/error.rb +6 -5
  113. data/lib/action_view/template/handlers.rb +0 -6
  114. data/lib/action_view/template/handlers/builder.rb +10 -1
  115. data/lib/action_view/template/handlers/erb.rb +2 -2
  116. data/lib/action_view/template/resolver.rb +20 -31
  117. data/lib/action_view/test_case.rb +7 -10
  118. data/lib/sprockets/assets.rake +1 -1
  119. data/lib/sprockets/bootstrap.rb +3 -31
  120. data/lib/sprockets/compressors.rb +69 -7
  121. data/lib/sprockets/helpers/rails_helper.rb +6 -11
  122. data/lib/sprockets/railtie.rb +1 -0
  123. data/lib/sprockets/static_compiler.rb +0 -3
  124. metadata +57 -86
  125. checksums.yaml +0 -7
  126. data/lib/action_dispatch/middleware/closed_error.rb +0 -7
  127. data/lib/action_dispatch/routing/route.rb +0 -67
  128. 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
- # Escape carrier returns and single and double quotes for JavaScript segments.
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, :separator => ",") # => 12,345,678
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, record, prefix = nil, options = nil, &block)
56
- options, prefix = prefix, nil if prefix.is_a?(Hash)
57
- options ||= {}
58
- options.merge!({ :class => "#{dom_class(record, prefix)} #{options[:class]}".strip, :id => dom_id(record, prefix) })
59
- content_tag(tag_name, options, &block)
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::Partials.
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. Check out
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. You can add
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. This uses the
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+. Replace with
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+. Replace with
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+. CDATA sections
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})(?!(?:[^<]*?)(?:["'])[^<>]*>)/i, options[:highlighter])
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>. These
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. You can use named cycles to allow nesting in loops.
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. Current Rails style favors RESTful routes whenever possible, so base
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). You can give +link_to_unless_current+ a block which will
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. So, if we had a comments page and wanted to render a
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. This lets the function
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.nil?
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"].to_s} nofollow".split(" ").uniq.join(" ")
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. (An attribute is considered to be boolean if
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. (See the XHTML 1.0 spec,
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
  #
@@ -152,3 +152,9 @@
152
152
  update: 'Update %{model}'
153
153
  submit: 'Save %{model}'
154
154
 
155
+ # Default translation keys for button FormHelper
156
+ button:
157
+ create: 'Create %{model}'
158
+ update: 'Update %{model}'
159
+ submit: 'Save %{model}'
160
+
@@ -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
- self.registered_detail_setters << [name, "#{name}="]
23
+ initialize = registered_details.map { |n| "@details[:#{n}] = details[:#{n}] || default_#{n}" }
26
24
 
27
- Accessors.send :define_method, :"_#{name}_defaults", &block
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.presence || _#{name}_defaults)
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(:locale) { [I18n.locale, I18n.default_locale] }
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.freeze] ||= new
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
- def initialize(view_paths, details = {}, prefixes = [])
64
- @details, @details_key = { :handlers => default_handlers }, nil
65
- @frozen_formats, @skip_default_locale = false, false
66
- @cache = true
67
- @prefixes = prefixes
71
+ # Add caching behavior on top of Details.
72
+ module DetailsCache
73
+ attr_accessor :cache
68
74
 
69
- self.view_paths = view_paths
70
- self.registered_detail_setters.each do |key, setter|
71
- send(setter, details[key])
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::Base.process_view_paths(paths)
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
- [name, prefixes, partial || false, @details, details_key, keys]
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.gsub(handlers_regexp, '')
123
- parts = name.split('/')
124
- name = parts.pop
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
- return name, prefixes
133
- end
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
- def default_handlers #:nodoc:
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
- module Details
145
- attr_accessor :cache
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
- # Freeze the current formats in the lookup context. By freezing them, you are guaranteeing
162
- # that next template lookups are not going to modify the formats. The controller can also
163
- # use this, to ensure that formats won't be further modified (as it does in respond_to blocks).
164
- def freeze_formats(formats, unless_frozen=false) #:nodoc:
165
- return if unless_frozen && @frozen_formats
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
- # Overload formats= to expand ["*/*"] values and automatically
171
- # add :html as fallback to :js.
172
- def formats=(values)
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
- # Do not use the default locale on template lookup.
181
- def skip_default_locale!
182
- @skip_default_locale = true
183
- self.locale = nil
184
- end
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
- # Overload locale to return a symbol instead of array.
187
- def locale
188
- @details[:locale].first
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
- # Overload locale= to also set the I18n.locale. If the current I18n.config object responds
192
- # to original_config, it means that it's has a copy of the original I18n configuration and it's
193
- # acting as proxy, which we need to skip.
194
- def locale=(value)
195
- if value
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
- super(@skip_default_locale ? I18n.locale : _locale_defaults)
201
- end
216
+ # Override locale to return a symbol instead of array.
217
+ def locale
218
+ @details[:locale].first
219
+ end
202
220
 
203
- # A method which only uses the first format in the formats array for layout lookup.
204
- # This method plays straight with instance variables for performance reasons.
205
- def with_layout_format
206
- if formats.size == 1
207
- yield
208
- else
209
- old_formats = formats
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
- # Update the details keys by merging the given hash into the current
221
- # details hash. If a block is given, the details are modified just during
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
- registered_detail_setters.each do |key, setter|
227
- send(setter, new_details[key]) if new_details.key?(key)
228
- end
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
- @details_key = nil
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