diff options
Diffstat (limited to 'actionview/lib/action_view/helpers')
7 files changed, 80 insertions, 51 deletions
diff --git a/actionview/lib/action_view/helpers/atom_feed_helper.rb b/actionview/lib/action_view/helpers/atom_feed_helper.rb index dba70e284e..c875f5870f 100644 --- a/actionview/lib/action_view/helpers/atom_feed_helper.rb +++ b/actionview/lib/action_view/helpers/atom_feed_helper.rb @@ -132,7 +132,7 @@ module ActionView end private - # Delegate to xml builder, first wrapping the element in a xhtml + # Delegate to xml builder, first wrapping the element in an xhtml # namespaced div element if the method and arguments indicate # that an xhtml_block? is desired. def method_missing(method, *arguments, &block) diff --git a/actionview/lib/action_view/helpers/cache_helper.rb b/actionview/lib/action_view/helpers/cache_helper.rb index 401f398721..4c7c4b91c6 100644 --- a/actionview/lib/action_view/helpers/cache_helper.rb +++ b/actionview/lib/action_view/helpers/cache_helper.rb @@ -126,44 +126,29 @@ module ActionView # # Now all you have to do is change that timestamp when the helper method changes. # - # === Automatic Collection Caching + # === Collection Caching # - # When rendering collections such as: + # When rendering a collection of objects that each use the same partial, a `cached` + # option can be passed. + # For collections rendered such: # - # <%= render @notifications %> - # <%= render partial: 'notifications/notification', collection: @notifications %> + # <%= render partial: 'notifications/notification', collection: @notifications, cached: true %> # - # If the notifications/_notification partial starts with a cache call as: + # The `cached: true` will make Action View's rendering read several templates + # from cache at once instead of one call per template. # - # <% cache notification do %> - # <%= notification.name %> - # <% end %> - # - # The collection can then automatically use any cached renders for that - # template by reading them at once instead of one by one. - # - # See ActionView::Template::Handlers::ERB.resource_cache_call_pattern for - # more information on what cache calls make a template eligible for this - # collection caching. - # - # The automatic cache multi read can be turned off like so: + # Templates in the collection not already cached are written to cache. # - # <%= render @notifications, cache: false %> + # Works great alongside individual template fragment caching. + # For instance if the template the collection renders is cached like: # - # === Explicit Collection Caching - # - # If the partial template doesn't start with a clean cache call as - # mentioned above, you can still benefit from collection caching by - # adding a special comment format anywhere in the template, like: - # - # <%# Template Collection: notification %> - # <% my_helper_that_calls_cache(some_arg, notification) do %> - # <%= notification.name %> + # # notifications/_notification.html.erb + # <% cache notification do %> + # <%# ... %> # <% end %> # - # The pattern used to match these is <tt>/# Template Collection: (\S+)/</tt>, - # so it's important that you type it out just so. - # You can only declare one collection in a partial template file. + # Any collection renders will find those cached templates when attempting + # to read multiple templates at once. def cache(name = {}, options = {}, &block) if controller.respond_to?(:perform_caching) && controller.perform_caching name_options = options.slice(:skip_digest, :virtual_path) diff --git a/actionview/lib/action_view/helpers/form_helper.rb b/actionview/lib/action_view/helpers/form_helper.rb index c1015ffe89..7ced37572e 100644 --- a/actionview/lib/action_view/helpers/form_helper.rb +++ b/actionview/lib/action_view/helpers/form_helper.rb @@ -1118,6 +1118,10 @@ module ActionView # # => <input id="user_born_on" name="user[born_on]" type="datetime" min="2014-05-20T00:00:00.000+0000" /> # def datetime_field(object_name, method, options = {}) + ActiveSupport::Deprecation.warn(<<-MESSAGE.squish) + datetime_field is deprecated and will be removed in Rails 5.1. + Use datetime_local_field instead. + MESSAGE Tags::DatetimeField.new(object_name, method, self, options).render end @@ -1922,8 +1926,6 @@ module ActionView @object_name.to_s.humanize end - model = model.downcase - defaults = [] defaults << :"helpers.submit.#{object_name}.#{key}" defaults << :"helpers.submit.#{key}" diff --git a/actionview/lib/action_view/helpers/form_tag_helper.rb b/actionview/lib/action_view/helpers/form_tag_helper.rb index 55dac74d00..cfff0bef5d 100644 --- a/actionview/lib/action_view/helpers/form_tag_helper.rb +++ b/actionview/lib/action_view/helpers/form_tag_helper.rb @@ -691,6 +691,10 @@ module ActionView # * <tt>:step</tt> - The acceptable value granularity. # * Otherwise accepts the same options as text_field_tag. def datetime_field_tag(name, value = nil, options = {}) + ActiveSupport::Deprecation.warn(<<-MESSAGE.squish) + datetime_field_tag is deprecated and will be removed in Rails 5.1. + Use datetime_local_field_tag instead. + MESSAGE text_field_tag(name, value, options.merge(type: :datetime)) end @@ -862,13 +866,13 @@ module ActionView def extra_tags_for_form(html_options) authenticity_token = html_options.delete("authenticity_token") - method = html_options.delete("method").to_s + method = html_options.delete("method").to_s.downcase method_tag = case method - when /^get$/i # must be case-insensitive, but can't use downcase as might be nil + when 'get' html_options["method"] = "get" '' - when /^post$/i, "", nil + when 'post', '' html_options["method"] = "post" token_tag(authenticity_token, form_options: { action: html_options["action"], diff --git a/actionview/lib/action_view/helpers/sanitize_helper.rb b/actionview/lib/action_view/helpers/sanitize_helper.rb index 191a881de0..f9784c3483 100644 --- a/actionview/lib/action_view/helpers/sanitize_helper.rb +++ b/actionview/lib/action_view/helpers/sanitize_helper.rb @@ -120,7 +120,7 @@ module ActionView attr_writer :full_sanitizer, :link_sanitizer, :white_list_sanitizer # Vendors the full, link and white list sanitizers. - # Provided strictly for compatibility and can be removed in Rails 5. + # Provided strictly for compatibility and can be removed in Rails 5.1. def sanitizer_vendor Rails::Html::Sanitizer end diff --git a/actionview/lib/action_view/helpers/tag_helper.rb b/actionview/lib/action_view/helpers/tag_helper.rb index 2562504896..42e7358a1d 100644 --- a/actionview/lib/action_view/helpers/tag_helper.rb +++ b/actionview/lib/action_view/helpers/tag_helper.rb @@ -154,6 +154,7 @@ module ActionView options.each_pair do |key, value| if TAG_PREFIXES.include?(key) && value.is_a?(Hash) value.each_pair do |k, v| + next if v.nil? output << sep output << prefix_tag_option(key, k, v, escape) end diff --git a/actionview/lib/action_view/helpers/url_helper.rb b/actionview/lib/action_view/helpers/url_helper.rb index 3a4561a083..11c7daf4da 100644 --- a/actionview/lib/action_view/helpers/url_helper.rb +++ b/actionview/lib/action_view/helpers/url_helper.rb @@ -302,7 +302,7 @@ module ActionView params = html_options.delete('params') method = html_options.delete('method').to_s - method_tag = BUTTON_TAG_METHOD_VERBS.include?(method) ? method_tag(method) : ''.html_safe + method_tag = BUTTON_TAG_METHOD_VERBS.include?(method) ? method_tag(method) : ''.freeze.html_safe form_method = method == 'get' ? 'get' : 'post' form_options = html_options.delete('form') || {} @@ -312,9 +312,10 @@ module ActionView form_options[:'data-remote'] = true if remote request_token_tag = if form_method == 'post' - token_tag(nil, form_options: form_options) + request_method = method.empty? ? 'post' : method + token_tag(nil, form_options: { action: url, method: request_method }) else - '' + ''.freeze end html_options = convert_options_to_data_attributes(options, html_options) @@ -329,8 +330,8 @@ module ActionView inner_tags = method_tag.safe_concat(button).safe_concat(request_token_tag) if params - params.each do |param_name, value| - inner_tags.safe_concat tag(:input, type: "hidden", name: param_name, value: value.to_param) + to_form_params(params).each do |param| + inner_tags.safe_concat tag(:input, type: "hidden", name: param[:name], value: param[:value]) end end content_tag('form', inner_tags, form_options) @@ -480,7 +481,7 @@ module ActionView option = html_options.delete(item).presence || next "#{item.dasherize}=#{ERB::Util.url_encode(option)}" }.compact - extras = extras.empty? ? '' : '?' + extras.join('&') + extras = extras.empty? ? ''.freeze : '?' + extras.join('&') encoded_email_address = ERB::Util.url_encode(email_address).gsub("%40", "@") html_options["href"] = "mailto:#{encoded_email_address}#{extras}" @@ -558,29 +559,29 @@ module ActionView def convert_options_to_data_attributes(options, html_options) if html_options html_options = html_options.stringify_keys - html_options['data-remote'] = 'true' if link_to_remote_options?(options) || link_to_remote_options?(html_options) + html_options['data-remote'] = 'true'.freeze if link_to_remote_options?(options) || link_to_remote_options?(html_options) - method = html_options.delete('method') + method = html_options.delete('method'.freeze) add_method_to_attributes!(html_options, method) if method html_options else - link_to_remote_options?(options) ? {'data-remote' => 'true'} : {} + link_to_remote_options?(options) ? {'data-remote' => 'true'.freeze} : {} end end def link_to_remote_options?(options) if options.is_a?(Hash) - options.delete('remote') || options.delete(:remote) + options.delete('remote'.freeze) || options.delete(:remote) end end def add_method_to_attributes!(html_options, method) - if method && method.to_s.downcase != "get" && html_options["rel"] !~ /nofollow/ - html_options["rel"] = "#{html_options["rel"]} nofollow".lstrip + if method && method.to_s.downcase != "get".freeze && html_options["rel".freeze] !~ /nofollow/ + html_options["rel".freeze] = "#{html_options["rel".freeze]} nofollow".lstrip end - html_options["data-method"] = method + html_options["data-method".freeze] = method end def token_tag(token=nil, form_options: {}) @@ -588,13 +589,49 @@ module ActionView token ||= form_authenticity_token(form_options: form_options) tag(:input, type: "hidden", name: request_forgery_protection_token.to_s, value: token) else - '' + ''.freeze end end def method_tag(method) tag('input', type: 'hidden', name: '_method', value: method.to_s) end + + # Returns an array of hashes each containing :name and :value keys + # suitable for use as the names and values of form input fields: + # + # to_form_params(name: 'David', nationality: 'Danish') + # # => [{name: :name, value: 'David'}, {name: 'nationality', value: 'Danish'}] + # + # to_form_params(country: {name: 'Denmark'}) + # # => [{name: 'country[name]', value: 'Denmark'}] + # + # to_form_params(countries: ['Denmark', 'Sweden']}) + # # => [{name: 'countries[]', value: 'Denmark'}, {name: 'countries[]', value: 'Sweden'}] + # + # An optional namespace can be passed to enclose key names: + # + # to_form_params({ name: 'Denmark' }, 'country') + # # => [{name: 'country[name]', value: 'Denmark'}] + def to_form_params(attribute, namespace = nil) # :nodoc: + params = [] + case attribute + when Hash + attribute.each do |key, value| + prefix = namespace ? "#{namespace}[#{key}]" : key + params.push(*to_form_params(value, prefix)) + end + when Array + array_prefix = "#{namespace}[]" + attribute.each do |value| + params.push(*to_form_params(value, array_prefix)) + end + else + params << { name: namespace, value: attribute.to_param } + end + + params.sort_by { |pair| pair[:name] } + end end end end |