diff options
Diffstat (limited to 'actionview/lib/action_view/helpers')
11 files changed, 76 insertions, 49 deletions
diff --git a/actionview/lib/action_view/helpers/asset_tag_helper.rb b/actionview/lib/action_view/helpers/asset_tag_helper.rb index e506c782d6..fa46a22500 100644 --- a/actionview/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionview/lib/action_view/helpers/asset_tag_helper.rb @@ -136,7 +136,7 @@ module ActionView tag( "link", "rel" => tag_options[:rel] || "alternate", - "type" => tag_options[:type] || Mime::Type.lookup_by_extension(type.to_s).to_s, + "type" => tag_options[:type] || Mime[type].to_s, "title" => tag_options[:title] || type.to_s.upcase, "href" => url_options.is_a?(Hash) ? url_for(url_options.merge(:only_path => false)) : url_options ) diff --git a/actionview/lib/action_view/helpers/cache_helper.rb b/actionview/lib/action_view/helpers/cache_helper.rb index 636d7d4cc3..e473aeaea9 100644 --- a/actionview/lib/action_view/helpers/cache_helper.rb +++ b/actionview/lib/action_view/helpers/cache_helper.rb @@ -229,10 +229,9 @@ module ActionView def fragment_name_with_digest(name, virtual_path) #:nodoc: virtual_path ||= @virtual_path if virtual_path - names = Array(name.is_a?(Hash) ? controller.url_for(name).split("://").last : name) + name = controller.url_for(name).split("://").last if name.is_a?(Hash) digest = Digestor.digest name: virtual_path, finder: lookup_context, dependencies: view_cache_dependencies - - [ *names, digest ] + [ name, digest ] else name end diff --git a/actionview/lib/action_view/helpers/form_helper.rb b/actionview/lib/action_view/helpers/form_helper.rb index 3a9acafaa2..2a367b85af 100644 --- a/actionview/lib/action_view/helpers/form_helper.rb +++ b/actionview/lib/action_view/helpers/form_helper.rb @@ -849,8 +849,8 @@ module ActionView # file_field(:user, :avatar) # # => <input type="file" id="user_avatar" name="user[avatar]" /> # - # file_field(:post, :image, :multiple => true) - # # => <input type="file" id="post_image" name="post[image]" multiple="true" /> + # file_field(:post, :image, multiple: true) + # # => <input type="file" id="post_image" name="post[image][]" multiple="multiple" /> # # file_field(:post, :attached, accept: 'text/html') # # => <input accept="text/html" type="file" id="post_attached" name="post[attached]" /> @@ -1038,7 +1038,7 @@ module ActionView # date_field("user", "born_on") # # => <input id="user_born_on" name="user[born_on]" type="date" /> # - # The default value is generated by trying to call "to_date" + # The default value is generated by trying to call +strftime+ with "%Y-%m-%d" # on the object's value, which makes it behave as expected for instances # of DateTime and ActiveSupport::TimeWithZone. You can still override that # by passing the "value" option explicitly, e.g. @@ -1617,7 +1617,14 @@ module ActionView @auto_index end - record_name = index ? "#{object_name}[#{index}][#{record_name}]" : "#{object_name}[#{record_name}]" + record_name = if index + "#{object_name}[#{index}][#{record_name}]" + elsif record_name.to_s.end_with?('[]') + record_name = record_name.to_s.sub(/(.*)\[\]$/, "[\\1][#{record_object.id}]") + "#{object_name}#{record_name}" + else + "#{object_name}[#{record_name}]" + end fields_options[:child_index] = index @template.fields_for(record_name, record_object, fields_options, &block) @@ -1880,7 +1887,7 @@ module ActionView # create: "Add %{model}" # # ==== Examples - # button("Create a post") + # button("Create post") # # => <button name='button' type='submit'>Create post</button> # # button do diff --git a/actionview/lib/action_view/helpers/form_options_helper.rb b/actionview/lib/action_view/helpers/form_options_helper.rb index 728e633bbf..430051379d 100644 --- a/actionview/lib/action_view/helpers/form_options_helper.rb +++ b/actionview/lib/action_view/helpers/form_options_helper.rb @@ -548,7 +548,7 @@ module ActionView end # Returns a string of option tags for pretty much any time zone in the - # world. Supply a ActiveSupport::TimeZone name as +selected+ to have it + # world. Supply an ActiveSupport::TimeZone name as +selected+ to have it # marked as the selected option tag. You can also supply an array of # ActiveSupport::TimeZone objects as +priority_zones+, so that they will # be listed above the rest of the (long) list. (You can use @@ -556,7 +556,7 @@ module ActionView # of the US time zones, or a Regexp to select the zones of your choice) # # The +selected+ parameter must be either +nil+, or a string that names - # a ActiveSupport::TimeZone. + # an ActiveSupport::TimeZone. # # By default, +model+ is the ActiveSupport::TimeZone constant (which can # be obtained in Active Record as a value object). The only requirement @@ -644,6 +644,24 @@ module ActionView # collection_radio_buttons(:post, :author_id, Author.all, :id, :name_with_initial) do |b| # b.label(:"data-value" => b.value) { b.radio_button + b.text } # end + # + # ==== Gotcha + # + # The HTML specification says when nothing is select on a collection of radio buttons + # web browsers do not send any value to server. + # Unfortunately this introduces a gotcha: + # if a +User+ model has a +category_id+ field, and in the form none category is selected no +category_id+ parameter is sent. So, + # any strong parameters idiom like + # + # params.require(:user).permit(...) + # + # will raise an error since no +{user: ...}+ will be present. + # + # To prevent this the helper generates an auxiliary hidden field before + # every collection of radio buttons. The hidden field has the same name as collection radio button and blank value. + # + # In case if you don't want the helper to generate this hidden field you can specify + # <tt>include_hidden: false</tt> option. def collection_radio_buttons(object, method, collection, value_method, text_method, options = {}, html_options = {}, &block) Tags::CollectionRadioButtons.new(object, method, self, collection, value_method, text_method, options, html_options).render(&block) end diff --git a/actionview/lib/action_view/helpers/form_tag_helper.rb b/actionview/lib/action_view/helpers/form_tag_helper.rb index af684e05c6..0191064326 100644 --- a/actionview/lib/action_view/helpers/form_tag_helper.rb +++ b/actionview/lib/action_view/helpers/form_tag_helper.rb @@ -20,7 +20,7 @@ module ActionView mattr_accessor :embed_authenticity_token_in_remote_forms self.embed_authenticity_token_in_remote_forms = false - # Starts a form tag that points the action to an url configured with <tt>url_for_options</tt> just like + # Starts a form tag that points the action to a url configured with <tt>url_for_options</tt> just like # ActionController::Base#url_for. The method for the form defaults to POST. # # ==== Options @@ -450,9 +450,9 @@ module ActionView disable_with_text ||= value.clone tag_options.deep_merge!("data" => { "disable_with" => disable_with_text }) else - tag_options.delete("data-disable-with") tag_options["data"].delete(:disable_with) if tag_options["data"] end + tag_options.delete("data-disable-with") end tag :input, tag_options diff --git a/actionview/lib/action_view/helpers/number_helper.rb b/actionview/lib/action_view/helpers/number_helper.rb index 13effa592d..d7182d1fac 100644 --- a/actionview/lib/action_view/helpers/number_helper.rb +++ b/actionview/lib/action_view/helpers/number_helper.rb @@ -1,4 +1,3 @@ - require 'active_support/core_ext/hash/keys' require 'active_support/core_ext/string/output_safety' require 'active_support/number_helper' @@ -140,7 +139,7 @@ module ActionView # number_to_percentage(302.24398923423, precision: 5) # => 302.24399% # number_to_percentage(1000, locale: :fr) # => 1 000,000% # number_to_percentage("98a") # => 98a% - # number_to_percentage(100, format: "%n %") # => 100 % + # number_to_percentage(100, format: "%n %") # => 100.000 % # # number_to_percentage("98a", raise: true) # => InvalidNumberError def number_to_percentage(number, options = {}) diff --git a/actionview/lib/action_view/helpers/tags/collection_check_boxes.rb b/actionview/lib/action_view/helpers/tags/collection_check_boxes.rb index 1765fa6558..3256d44e18 100644 --- a/actionview/lib/action_view/helpers/tags/collection_check_boxes.rb +++ b/actionview/lib/action_view/helpers/tags/collection_check_boxes.rb @@ -9,29 +9,13 @@ module ActionView class CheckBoxBuilder < Builder # :nodoc: def check_box(extra_html_options={}) html_options = extra_html_options.merge(@input_html_options) + html_options[:multiple] = true @template_object.check_box(@object_name, @method_name, html_options, @value, nil) end end def render(&block) - rendered_collection = render_collection do |item, value, text, default_html_options| - default_html_options[:multiple] = true - builder = instantiate_builder(CheckBoxBuilder, item, value, text, default_html_options) - - if block_given? - @template_object.capture(builder, &block) - else - render_component(builder) - end - end - - # Append a hidden field to make sure something will be sent back to the - # server if all check boxes are unchecked. - if @options.fetch(:include_hidden, true) - rendered_collection + hidden_field - else - rendered_collection - end + render_collection_for(CheckBoxBuilder, &block) end private @@ -39,11 +23,6 @@ module ActionView def render_component(builder) builder.check_box + builder.label end - - def hidden_field - hidden_name = @html_options[:name] || "#{tag_name(false, @options[:index])}[]" - @template_object.hidden_field_tag(hidden_name, "", id: nil) - end end end end diff --git a/actionview/lib/action_view/helpers/tags/collection_helpers.rb b/actionview/lib/action_view/helpers/tags/collection_helpers.rb index 8050638363..fea4c8d4ec 100644 --- a/actionview/lib/action_view/helpers/tags/collection_helpers.rb +++ b/actionview/lib/action_view/helpers/tags/collection_helpers.rb @@ -79,6 +79,32 @@ module ActionView yield item, value, text, default_html_options.merge(additional_html_options) end.join.html_safe end + + def render_collection_for(builder_class, &block) #:nodoc: + options = @options.stringify_keys + rendered_collection = render_collection do |item, value, text, default_html_options| + builder = instantiate_builder(builder_class, item, value, text, default_html_options) + + if block_given? + @template_object.capture(builder, &block) + else + render_component(builder) + end + end + + # Append a hidden field to make sure something will be sent back to the + # server if all radio buttons are unchecked. + if options.fetch('include_hidden', true) + rendered_collection + hidden_field + else + rendered_collection + end + end + + def hidden_field #:nodoc: + hidden_name = @html_options[:name] || "#{tag_name(false, @options[:index])}[]" + @template_object.hidden_field_tag(hidden_name, "", id: nil) + end end end end diff --git a/actionview/lib/action_view/helpers/tags/collection_radio_buttons.rb b/actionview/lib/action_view/helpers/tags/collection_radio_buttons.rb index 20be34c1f2..21aaf122f8 100644 --- a/actionview/lib/action_view/helpers/tags/collection_radio_buttons.rb +++ b/actionview/lib/action_view/helpers/tags/collection_radio_buttons.rb @@ -14,15 +14,7 @@ module ActionView end def render(&block) - render_collection do |item, value, text, default_html_options| - builder = instantiate_builder(RadioButtonBuilder, item, value, text, default_html_options) - - if block_given? - @template_object.capture(builder, &block) - else - render_component(builder) - end - end + render_collection_for(RadioButtonBuilder, &block) end private diff --git a/actionview/lib/action_view/helpers/translation_helper.rb b/actionview/lib/action_view/helpers/translation_helper.rb index 0615bd2e0d..dde1ef22ac 100644 --- a/actionview/lib/action_view/helpers/translation_helper.rb +++ b/actionview/lib/action_view/helpers/translation_helper.rb @@ -88,7 +88,14 @@ module ActionView raise e if raise_error keys = I18n.normalize_keys(e.locale, e.key, e.options[:scope]) - content_tag('span', keys.last.to_s.titleize, :class => 'translation_missing', :title => "translation missing: #{keys.join('.')}") + title = "translation missing: #{keys.join('.')}" + + interpolations = options.except(:default) + if interpolations.any? + title << ", " << interpolations.map { |k, v| "#{k}: #{ERB::Util.html_escape(v)}" }.join(', ') + end + + content_tag('span', keys.last.to_s.titleize, class: 'translation_missing', title: title) end end alias :t :translate diff --git a/actionview/lib/action_view/helpers/url_helper.rb b/actionview/lib/action_view/helpers/url_helper.rb index d676a0a931..5684de35e8 100644 --- a/actionview/lib/action_view/helpers/url_helper.rb +++ b/actionview/lib/action_view/helpers/url_helper.rb @@ -464,7 +464,7 @@ module ActionView extras = %w{ cc bcc body subject reply_to }.map! { |item| option = html_options.delete(item).presence || next - "#{item.dasherize}=#{Rack::Utils.escape_path(option)}" + "#{item.dasherize}=#{ERB::Util.url_encode(option)}" }.compact extras = extras.empty? ? '' : '?' + extras.join('&') |