actionview 4.2.11.3 → 5.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionview might be problematic. Click here for more details.

Files changed (65) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +136 -255
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -3
  5. data/lib/action_view.rb +1 -1
  6. data/lib/action_view/base.rb +14 -2
  7. data/lib/action_view/dependency_tracker.rb +46 -15
  8. data/lib/action_view/digestor.rb +13 -9
  9. data/lib/action_view/flows.rb +1 -1
  10. data/lib/action_view/gem_version.rb +4 -4
  11. data/lib/action_view/helpers/asset_tag_helper.rb +15 -5
  12. data/lib/action_view/helpers/asset_url_helper.rb +51 -12
  13. data/lib/action_view/helpers/atom_feed_helper.rb +5 -4
  14. data/lib/action_view/helpers/cache_helper.rb +75 -20
  15. data/lib/action_view/helpers/capture_helper.rb +3 -2
  16. data/lib/action_view/helpers/controller_helper.rb +1 -0
  17. data/lib/action_view/helpers/date_helper.rb +39 -10
  18. data/lib/action_view/helpers/debug_helper.rb +1 -1
  19. data/lib/action_view/helpers/form_helper.rb +81 -35
  20. data/lib/action_view/helpers/form_options_helper.rb +74 -35
  21. data/lib/action_view/helpers/form_tag_helper.rb +46 -19
  22. data/lib/action_view/helpers/javascript_helper.rb +4 -4
  23. data/lib/action_view/helpers/number_helper.rb +10 -12
  24. data/lib/action_view/helpers/record_tag_helper.rb +12 -99
  25. data/lib/action_view/helpers/rendering_helper.rb +2 -2
  26. data/lib/action_view/helpers/sanitize_helper.rb +1 -2
  27. data/lib/action_view/helpers/tag_helper.rb +20 -13
  28. data/lib/action_view/helpers/tags/base.rb +33 -28
  29. data/lib/action_view/helpers/tags/collection_check_boxes.rb +2 -30
  30. data/lib/action_view/helpers/tags/collection_helpers.rb +28 -0
  31. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +1 -9
  32. data/lib/action_view/helpers/tags/file_field.rb +15 -0
  33. data/lib/action_view/helpers/tags/label.rb +1 -1
  34. data/lib/action_view/helpers/tags/placeholderable.rb +1 -1
  35. data/lib/action_view/helpers/tags/search_field.rb +12 -9
  36. data/lib/action_view/helpers/tags/text_field.rb +0 -1
  37. data/lib/action_view/helpers/tags/translator.rb +1 -1
  38. data/lib/action_view/helpers/text_helper.rb +25 -9
  39. data/lib/action_view/helpers/translation_helper.rb +56 -26
  40. data/lib/action_view/helpers/url_helper.rb +40 -65
  41. data/lib/action_view/layouts.rb +11 -10
  42. data/lib/action_view/lookup_context.rb +14 -40
  43. data/lib/action_view/model_naming.rb +1 -1
  44. data/lib/action_view/path_set.rb +15 -18
  45. data/lib/action_view/railtie.rb +20 -3
  46. data/lib/action_view/record_identifier.rb +44 -19
  47. data/lib/action_view/renderer/abstract_renderer.rb +1 -1
  48. data/lib/action_view/renderer/partial_renderer.rb +27 -26
  49. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +70 -0
  50. data/lib/action_view/renderer/renderer.rb +2 -6
  51. data/lib/action_view/renderer/streaming_template_renderer.rb +1 -1
  52. data/lib/action_view/renderer/template_renderer.rb +12 -11
  53. data/lib/action_view/rendering.rb +8 -5
  54. data/lib/action_view/routing_url_for.rb +18 -6
  55. data/lib/action_view/template.rb +50 -13
  56. data/lib/action_view/template/error.rb +14 -7
  57. data/lib/action_view/template/handlers.rb +3 -3
  58. data/lib/action_view/template/handlers/erb.rb +25 -0
  59. data/lib/action_view/template/handlers/raw.rb +1 -1
  60. data/lib/action_view/template/resolver.rb +36 -58
  61. data/lib/action_view/template/types.rb +1 -1
  62. data/lib/action_view/test_case.rb +13 -8
  63. data/lib/action_view/testing/resolvers.rb +3 -4
  64. data/lib/action_view/view_paths.rb +6 -22
  65. metadata +17 -14
@@ -1,108 +1,21 @@
1
- require 'action_view/record_identifier'
2
-
3
1
  module ActionView
4
- # = Action View Record Tag Helpers
5
2
  module Helpers
6
3
  module RecordTagHelper
7
- include ActionView::RecordIdentifier
8
-
9
- # Produces a wrapper DIV element with id and class parameters that
10
- # relate to the specified Active Record object. Usage example:
11
- #
12
- # <%= div_for(@person, class: "foo") do %>
13
- # <%= @person.name %>
14
- # <% end %>
15
- #
16
- # produces:
17
- #
18
- # <div id="person_123" class="person foo"> Joe Bloggs </div>
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
- #
33
- def div_for(record, *args, &block)
34
- content_tag_for(:div, record, *args, &block)
4
+ def div_for(*)
5
+ raise NoMethodError, "The `div_for` method has been removed from " \
6
+ "Rails. To continue using it, add the `record_tag_helper` gem to " \
7
+ "your Gemfile:\n" \
8
+ " gem 'record_tag_helper', '~> 1.0'\n" \
9
+ "Consult the Rails upgrade guide for details."
35
10
  end
36
11
 
37
- # content_tag_for creates an HTML element with id and class parameters
38
- # that relate to the specified Active Record object. For example:
39
- #
40
- # <%= content_tag_for(:tr, @person) do %>
41
- # <td><%= @person.first_name %></td>
42
- # <td><%= @person.last_name %></td>
43
- # <% end %>
44
- #
45
- # would produce the following HTML (assuming @person is an instance of
46
- # a Person object, with an id value of 123):
47
- #
48
- # <tr id="person_123" class="person">....</tr>
49
- #
50
- # If you require the HTML id attribute to have a prefix, you can specify it:
51
- #
52
- # <%= content_tag_for(:tr, @person, :foo) do %> ...
53
- #
54
- # produces:
55
- #
56
- # <tr id="foo_person_123" class="person">...
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
- #
73
- # content_tag_for also accepts a hash of options, which will be converted to
74
- # additional HTML attributes. If you specify a <tt>:class</tt> value, it will be combined
75
- # with the default class name for your object. For example:
76
- #
77
- # <%= content_tag_for(:li, @person, class: "bar") %>...
78
- #
79
- # produces:
80
- #
81
- # <li id="person_123" class="person bar">...
82
- #
83
- def content_tag_for(tag_name, single_or_multiple_records, prefix = nil, options = nil, &block)
84
- options, prefix = prefix, nil if prefix.is_a?(Hash)
85
-
86
- Array(single_or_multiple_records).map do |single_record|
87
- content_tag_for_single_record(tag_name, single_record, prefix, options, &block)
88
- end.join("\n").html_safe
12
+ def content_tag_for(*)
13
+ raise NoMethodError, "The `content_tag_for` method has been removed from " \
14
+ "Rails. To continue using it, add the `record_tag_helper` gem to " \
15
+ "your Gemfile:\n" \
16
+ " gem 'record_tag_helper', '~> 1.0'\n" \
17
+ "Consult the Rails upgrade guide for details."
89
18
  end
90
-
91
- private
92
-
93
- # Called by <tt>content_tag_for</tt> internally to render a content tag
94
- # for each record.
95
- def content_tag_for_single_record(tag_name, record, prefix, options, &block)
96
- options = options ? options.dup : {}
97
- options[:class] = [ dom_class(record, prefix), options[:class] ].compact
98
- options[:id] = dom_id(record, prefix)
99
-
100
- if block_given?
101
- content_tag(tag_name, capture(record, &block), options)
102
- else
103
- content_tag(tag_name, "", options)
104
- end
105
- end
106
19
  end
107
20
  end
108
21
  end
@@ -18,7 +18,7 @@ module ActionView
18
18
  # performs HTML escape on the string first. Setting the content type as
19
19
  # <tt>text/html</tt>.
20
20
  # * <tt>:body</tt> - Renders the text passed in, and inherits the content
21
- # type of <tt>text/html</tt> from <tt>ActionDispatch::Response</tt>
21
+ # type of <tt>text/plain</tt> from <tt>ActionDispatch::Response</tt>
22
22
  # object.
23
23
  #
24
24
  # If no options hash is passed or :update specified, the default is to render a partial and use the second parameter
@@ -32,7 +32,7 @@ module ActionView
32
32
  view_renderer.render(self, options)
33
33
  end
34
34
  else
35
- view_renderer.render_partial(self, :partial => options, :locals => locals)
35
+ view_renderer.render_partial(self, :partial => options, :locals => locals, &block)
36
36
  end
37
37
  end
38
38
 
@@ -1,5 +1,4 @@
1
1
  require 'active_support/core_ext/object/try'
2
- require 'active_support/deprecation'
3
2
  require 'rails-html-sanitizer'
4
3
 
5
4
  module ActionView
@@ -121,7 +120,7 @@ module ActionView
121
120
  attr_writer :full_sanitizer, :link_sanitizer, :white_list_sanitizer
122
121
 
123
122
  # Vendors the full, link and white list sanitizers.
124
- # Provided strictly for compabitility and can be removed in Rails 5.
123
+ # Provided strictly for compatibility and can be removed in Rails 5.
125
124
  def sanitizer_vendor
126
125
  Rails::Html::Sanitizer
127
126
  end
@@ -18,13 +18,14 @@ module ActionView
18
18
  itemscope allowfullscreen default inert sortable
19
19
  truespeed typemustmatch).to_set
20
20
 
21
- BOOLEAN_ATTRIBUTES.merge(BOOLEAN_ATTRIBUTES.map {|attribute| attribute.to_sym })
21
+ BOOLEAN_ATTRIBUTES.merge(BOOLEAN_ATTRIBUTES.map(&:to_sym))
22
22
 
23
23
  TAG_PREFIXES = ['aria', 'data', :aria, :data].to_set
24
24
 
25
- PRE_CONTENT_STRINGS = {
26
- :textarea => "\n"
27
- }
25
+ PRE_CONTENT_STRINGS = Hash.new { "".freeze }
26
+ PRE_CONTENT_STRINGS[:textarea] = "\n"
27
+ PRE_CONTENT_STRINGS["textarea"] = "\n"
28
+
28
29
 
29
30
  # Returns an empty HTML tag of type +name+ which by default is XHTML
30
31
  # compliant. Set +open+ to true to create an open tag compatible
@@ -143,24 +144,30 @@ module ActionView
143
144
  def content_tag_string(name, content, options, escape = true)
144
145
  tag_options = tag_options(options, escape) if options
145
146
  content = ERB::Util.unwrapped_html_escape(content) if escape
146
- "<#{name}#{tag_options}>#{PRE_CONTENT_STRINGS[name.to_sym]}#{content}</#{name}>".html_safe
147
+ "<#{name}#{tag_options}>#{PRE_CONTENT_STRINGS[name]}#{content}</#{name}>".html_safe
147
148
  end
148
149
 
149
150
  def tag_options(options, escape = true)
150
151
  return if options.blank?
151
- attrs = []
152
+ output = ""
153
+ sep = " ".freeze
152
154
  options.each_pair do |key, value|
153
155
  if TAG_PREFIXES.include?(key) && value.is_a?(Hash)
154
156
  value.each_pair do |k, v|
155
- attrs << prefix_tag_option(key, k, v, escape)
157
+ output << sep
158
+ output << prefix_tag_option(key, k, v, escape)
156
159
  end
157
160
  elsif BOOLEAN_ATTRIBUTES.include?(key)
158
- attrs << boolean_tag_option(key) if value
161
+ if value
162
+ output << sep
163
+ output << boolean_tag_option(key)
164
+ end
159
165
  elsif !value.nil?
160
- attrs << tag_option(key, value, escape)
166
+ output << sep
167
+ output << tag_option(key, value, escape)
161
168
  end
162
169
  end
163
- " #{attrs * ' '}" unless attrs.empty?
170
+ output unless output.empty?
164
171
  end
165
172
 
166
173
  def prefix_tag_option(prefix, key, value, escape)
@@ -177,11 +184,11 @@ module ActionView
177
184
 
178
185
  def tag_option(key, value, escape)
179
186
  if value.is_a?(Array)
180
- value = escape ? safe_join(value, " ") : value.join(" ")
187
+ value = escape ? safe_join(value, " ".freeze) : value.join(" ".freeze)
181
188
  else
182
- value = escape ? ERB::Util.unwrapped_html_escape(value) : value.to_s
189
+ value = escape ? ERB::Util.unwrapped_html_escape(value) : value
183
190
  end
184
- %(#{key}="#{value.gsub('"'.freeze, '&quot;'.freeze)}")
191
+ %(#{key}="#{value}")
185
192
  end
186
193
  end
187
194
  end
@@ -14,7 +14,7 @@ module ActionView
14
14
  @object_name.sub!(/\[\]$/,"") || @object_name.sub!(/\[\]\]$/,"]")
15
15
  @object = retrieve_object(options.delete(:object))
16
16
  @options = options
17
- @auto_index = retrieve_autoindex(Regexp.last_match.pre_match) if Regexp.last_match
17
+ @auto_index = Regexp.last_match ? retrieve_autoindex(Regexp.last_match.pre_match) : nil
18
18
  end
19
19
 
20
20
  # This is what child classes implement.
@@ -79,35 +79,30 @@ module ActionView
79
79
  end
80
80
 
81
81
  def add_default_name_and_id(options)
82
- if options.has_key?("index")
83
- options["name"] ||= options.fetch("name"){ tag_name_with_index(options["index"], options["multiple"]) }
84
- options["id"] = options.fetch("id"){ tag_id_with_index(options["index"]) }
85
- options.delete("index")
86
- elsif defined?(@auto_index)
87
- options["name"] ||= options.fetch("name"){ tag_name_with_index(@auto_index, options["multiple"]) }
88
- options["id"] = options.fetch("id"){ tag_id_with_index(@auto_index) }
89
- else
90
- options["name"] ||= options.fetch("name"){ tag_name(options["multiple"]) }
91
- options["id"] = options.fetch("id"){ tag_id }
82
+ index = name_and_id_index(options)
83
+ options["name"] = options.fetch("name"){ tag_name(options["multiple"], index) }
84
+ options["id"] = options.fetch("id"){ tag_id(index) }
85
+ if namespace = options.delete("namespace")
86
+ options['id'] = options['id'] ? "#{namespace}_#{options['id']}" : namespace
92
87
  end
93
-
94
- options["id"] = [options.delete('namespace'), options["id"]].compact.join("_").presence
95
- end
96
-
97
- def tag_name(multiple = false)
98
- "#{@object_name}[#{sanitized_method_name}]#{"[]" if multiple}"
99
88
  end
100
89
 
101
- def tag_name_with_index(index, multiple = false)
102
- "#{@object_name}[#{index}][#{sanitized_method_name}]#{"[]" if multiple}"
103
- end
104
-
105
- def tag_id
106
- "#{sanitized_object_name}_#{sanitized_method_name}"
90
+ def tag_name(multiple = false, index = nil)
91
+ # a little duplication to construct less strings
92
+ if index
93
+ "#{@object_name}[#{index}][#{sanitized_method_name}]#{"[]" if multiple}"
94
+ else
95
+ "#{@object_name}[#{sanitized_method_name}]#{"[]" if multiple}"
96
+ end
107
97
  end
108
98
 
109
- def tag_id_with_index(index)
110
- "#{sanitized_object_name}_#{index}_#{sanitized_method_name}"
99
+ def tag_id(index = nil)
100
+ # a little duplication to construct less strings
101
+ if index
102
+ "#{sanitized_object_name}_#{index}_#{sanitized_method_name}"
103
+ else
104
+ "#{sanitized_object_name}_#{sanitized_method_name}"
105
+ end
111
106
  end
112
107
 
113
108
  def sanitized_object_name
@@ -125,7 +120,12 @@ module ActionView
125
120
  def select_content_tag(option_tags, options, html_options)
126
121
  html_options = html_options.stringify_keys
127
122
  add_default_name_and_id(html_options)
128
- options[:include_blank] ||= true unless options[:prompt] || select_not_required?(html_options)
123
+
124
+ if placeholder_required?(html_options)
125
+ raise ArgumentError, "include_blank cannot be false for a required field." if options[:include_blank] == false
126
+ options[:include_blank] ||= true unless options[:prompt]
127
+ end
128
+
129
129
  value = options.fetch(:selected) { value(object) }
130
130
  select = content_tag("select", add_options(option_tags, options, value), html_options)
131
131
 
@@ -136,8 +136,9 @@ module ActionView
136
136
  end
137
137
  end
138
138
 
139
- def select_not_required?(html_options)
140
- !html_options["required"] || html_options["multiple"] || html_options["size"].to_i > 1
139
+ def placeholder_required?(html_options)
140
+ # See https://html.spec.whatwg.org/multipage/forms.html#attr-select-required
141
+ html_options["required"] && !html_options["multiple"] && html_options.fetch("size", 1).to_i == 1
141
142
  end
142
143
 
143
144
  def add_options(option_tags, options, value = nil)
@@ -149,6 +150,10 @@ module ActionView
149
150
  end
150
151
  option_tags
151
152
  end
153
+
154
+ def name_and_id_index(options)
155
+ options.key?("index") ? options.delete("index") || "" : @auto_index
156
+ end
152
157
  end
153
158
  end
154
159
  end
@@ -9,29 +9,13 @@ module ActionView
9
9
  class CheckBoxBuilder < Builder # :nodoc:
10
10
  def check_box(extra_html_options={})
11
11
  html_options = extra_html_options.merge(@input_html_options)
12
+ html_options[:multiple] = true
12
13
  @template_object.check_box(@object_name, @method_name, html_options, @value, nil)
13
14
  end
14
15
  end
15
16
 
16
17
  def render(&block)
17
- rendered_collection = render_collection do |item, value, text, default_html_options|
18
- default_html_options[:multiple] = true
19
- builder = instantiate_builder(CheckBoxBuilder, item, value, text, default_html_options)
20
-
21
- if block_given?
22
- @template_object.capture(builder, &block)
23
- else
24
- render_component(builder)
25
- end
26
- end
27
-
28
- # Append a hidden field to make sure something will be sent back to the
29
- # server if all check boxes are unchecked.
30
- if @options.fetch(:include_hidden, true)
31
- rendered_collection + hidden_field
32
- else
33
- rendered_collection
34
- end
18
+ render_collection_for(CheckBoxBuilder, &block)
35
19
  end
36
20
 
37
21
  private
@@ -39,18 +23,6 @@ module ActionView
39
23
  def render_component(builder)
40
24
  builder.check_box + builder.label
41
25
  end
42
-
43
- def hidden_field
44
- hidden_name = @html_options[:name]
45
-
46
- hidden_name ||= if @options.has_key?(:index)
47
- "#{tag_name_with_index(@options[:index])}[]"
48
- else
49
- "#{tag_name}[]"
50
- end
51
-
52
- @template_object.hidden_field_tag(hidden_name, "", id: nil)
53
- end
54
26
  end
55
27
  end
56
28
  end
@@ -19,6 +19,8 @@ module ActionView
19
19
 
20
20
  def label(label_html_options={}, &block)
21
21
  html_options = @input_html_options.slice(:index, :namespace).merge(label_html_options)
22
+ html_options[:for] ||= @input_html_options[:id] if @input_html_options[:id]
23
+
22
24
  @template_object.label(@object_name, @sanitized_attribute_name, @text, html_options, &block)
23
25
  end
24
26
  end
@@ -79,6 +81,32 @@ module ActionView
79
81
  yield item, value, text, default_html_options.merge(additional_html_options)
80
82
  end.join.html_safe
81
83
  end
84
+
85
+ def render_collection_for(builder_class, &block) #:nodoc:
86
+ options = @options.stringify_keys
87
+ rendered_collection = render_collection do |item, value, text, default_html_options|
88
+ builder = instantiate_builder(builder_class, item, value, text, default_html_options)
89
+
90
+ if block_given?
91
+ @template_object.capture(builder, &block)
92
+ else
93
+ render_component(builder)
94
+ end
95
+ end
96
+
97
+ # Append a hidden field to make sure something will be sent back to the
98
+ # server if all radio buttons are unchecked.
99
+ if options.fetch('include_hidden', true)
100
+ rendered_collection + hidden_field
101
+ else
102
+ rendered_collection
103
+ end
104
+ end
105
+
106
+ def hidden_field #:nodoc:
107
+ hidden_name = @html_options[:name] || "#{tag_name(false, @options[:index])}[]"
108
+ @template_object.hidden_field_tag(hidden_name, "", id: nil)
109
+ end
82
110
  end
83
111
  end
84
112
  end
@@ -14,15 +14,7 @@ module ActionView
14
14
  end
15
15
 
16
16
  def render(&block)
17
- render_collection do |item, value, text, default_html_options|
18
- builder = instantiate_builder(RadioButtonBuilder, item, value, text, default_html_options)
19
-
20
- if block_given?
21
- @template_object.capture(builder, &block)
22
- else
23
- render_component(builder)
24
- end
25
- end
17
+ render_collection_for(RadioButtonBuilder, &block)
26
18
  end
27
19
 
28
20
  private
@@ -2,6 +2,21 @@ module ActionView
2
2
  module Helpers
3
3
  module Tags # :nodoc:
4
4
  class FileField < TextField # :nodoc:
5
+
6
+ def render
7
+ options = @options.stringify_keys
8
+
9
+ if options.fetch("include_hidden", true)
10
+ add_default_name_and_id(options)
11
+ options[:type] = "file"
12
+ tag("input", name: options["name"], type: "hidden", value: "") + tag("input", options)
13
+ else
14
+ options.delete("include_hidden")
15
+ @options = options
16
+
17
+ super
18
+ end
19
+ end
5
20
  end
6
21
  end
7
22
  end