aboutsummaryrefslogtreecommitdiffstats
path: root/actionview
diff options
context:
space:
mode:
Diffstat (limited to 'actionview')
-rw-r--r--actionview/CHANGELOG.md12
-rw-r--r--actionview/lib/action_view/base.rb2
-rw-r--r--actionview/lib/action_view/helpers/asset_tag_helper.rb2
-rw-r--r--actionview/lib/action_view/helpers/form_helper.rb15
-rw-r--r--actionview/lib/action_view/helpers/form_options_helper.rb22
-rw-r--r--actionview/lib/action_view/helpers/form_tag_helper.rb4
-rw-r--r--actionview/lib/action_view/helpers/number_helper.rb2
-rw-r--r--actionview/lib/action_view/helpers/tags/collection_check_boxes.rb25
-rw-r--r--actionview/lib/action_view/helpers/tags/collection_helpers.rb28
-rw-r--r--actionview/lib/action_view/helpers/tags/collection_radio_buttons.rb10
-rw-r--r--actionview/lib/action_view/helpers/translation_helper.rb2
-rw-r--r--actionview/lib/action_view/layouts.rb2
-rw-r--r--actionview/lib/action_view/lookup_context.rb4
-rw-r--r--actionview/lib/action_view/routing_url_for.rb18
-rw-r--r--actionview/test/actionpack/abstract/render_test.rb1
-rw-r--r--actionview/test/actionpack/controller/render_test.rb4
-rw-r--r--actionview/test/fixtures/digestor/comments/_comment.html.erb2
-rw-r--r--actionview/test/template/form_collections_helper_test.rb53
-rw-r--r--actionview/test/template/form_helper_test.rb34
-rw-r--r--actionview/test/template/form_tag_helper_test.rb34
-rw-r--r--actionview/test/template/lookup_context_test.rb4
-rw-r--r--actionview/test/template/render_test.rb10
-rw-r--r--actionview/test/template/translation_helper_test.rb8
23 files changed, 225 insertions, 73 deletions
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md
index 9ea250643a..c010b7ce91 100644
--- a/actionview/CHANGELOG.md
+++ b/actionview/CHANGELOG.md
@@ -1,3 +1,13 @@
+* Collection input propagates input's `id` to the label's `for` attribute when
+ using html options as the last element of collection.
+
+ *Vasiliy Ermolovich*
+
+* Add a `hidden_field` on the `collection_radio_buttons` to avoid raising a error
+ when the only input on the form is the `collection_radio_buttons`.
+
+ *Mauro George*
+
* `url_for` does not modify its arguments when generating polymorphic URLs.
*Bernerd Schaefer*
@@ -184,7 +194,7 @@
*Nikolay Shebanov*
-* Add a `hidden_field` on the `file_field` to avoid raise a error when the only
+* Add a `hidden_field` on the `file_field` to avoid raising an error when the only
input on the form is the `file_field`.
*Mauro George*
diff --git a/actionview/lib/action_view/base.rb b/actionview/lib/action_view/base.rb
index 72ca6f7ec6..ad1cb1a4be 100644
--- a/actionview/lib/action_view/base.rb
+++ b/actionview/lib/action_view/base.rb
@@ -75,7 +75,7 @@ module ActionView #:nodoc:
#
# Headline: <%= local_assigns[:headline] %>
#
- # This is useful in cases where you aren't sure if the local variable has been assigned. Alternately, you could also use
+ # This is useful in cases where you aren't sure if the local variable has been assigned. Alternatively, you could also use
# <tt>defined? headline</tt> to first check if the variable has been assigned before using it.
#
# === Template caching
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/form_helper.rb b/actionview/lib/action_view/helpers/form_helper.rb
index ebf5ea5b77..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)
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 470dc86d6c..d7182d1fac 100644
--- a/actionview/lib/action_view/helpers/number_helper.rb
+++ b/actionview/lib/action_view/helpers/number_helper.rb
@@ -139,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..b87b4281d6 100644
--- a/actionview/lib/action_view/helpers/tags/collection_helpers.rb
+++ b/actionview/lib/action_view/helpers/tags/collection_helpers.rb
@@ -19,6 +19,8 @@ module ActionView
def label(label_html_options={}, &block)
html_options = @input_html_options.slice(:index, :namespace).merge(label_html_options)
+ html_options[:for] ||= @input_html_options[:id] if @input_html_options[:id]
+
@template_object.label(@object_name, @sanitized_attribute_name, @text, html_options, &block)
end
end
@@ -79,6 +81,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 dde1ef22ac..4c4d2c4457 100644
--- a/actionview/lib/action_view/helpers/translation_helper.rb
+++ b/actionview/lib/action_view/helpers/translation_helper.rb
@@ -90,7 +90,7 @@ module ActionView
keys = I18n.normalize_keys(e.locale, e.key, e.options[:scope])
title = "translation missing: #{keys.join('.')}"
- interpolations = options.except(:default)
+ interpolations = options.except(:default, :scope)
if interpolations.any?
title << ", " << interpolations.map { |k, v| "#{k}: #{ERB::Util.html_escape(v)}" }.join(', ')
end
diff --git a/actionview/lib/action_view/layouts.rb b/actionview/lib/action_view/layouts.rb
index cabba967c9..a74a5e05f3 100644
--- a/actionview/lib/action_view/layouts.rb
+++ b/actionview/lib/action_view/layouts.rb
@@ -401,7 +401,7 @@ module ActionView
# ==== Parameters
# * <tt>formats</tt> - The formats accepted to this layout
# * <tt>require_layout</tt> - If set to true and layout is not found,
- # an ArgumentError exception is raised (defaults to false)
+ # an +ArgumentError+ exception is raised (defaults to false)
#
# ==== Returns
# * <tt>template</tt> - The template object for the default layout (or nil)
diff --git a/actionview/lib/action_view/lookup_context.rb b/actionview/lib/action_view/lookup_context.rb
index 8b7ede250a..ec6edfaaa3 100644
--- a/actionview/lib/action_view/lookup_context.rb
+++ b/actionview/lib/action_view/lookup_context.rb
@@ -20,7 +20,7 @@ module ActionView
mattr_accessor :registered_details
self.registered_details = []
- def self.register_detail(name, options = {}, &block)
+ def self.register_detail(name, &block)
self.registered_details << name
initialize = registered_details.map { |n| "@details[:#{n}] = details[:#{n}] || default_#{n}" }
@@ -55,7 +55,7 @@ module ActionView
end
register_detail(:formats) { ActionView::Base.default_formats || [:html, :text, :js, :css, :xml, :json] }
register_detail(:variants) { [] }
- register_detail(:handlers){ Template::Handlers.extensions }
+ register_detail(:handlers) { Template::Handlers.extensions }
class DetailsKey #:nodoc:
alias :eql? :equal?
diff --git a/actionview/lib/action_view/routing_url_for.rb b/actionview/lib/action_view/routing_url_for.rb
index b4cbc80bd5..45e78d1ad9 100644
--- a/actionview/lib/action_view/routing_url_for.rb
+++ b/actionview/lib/action_view/routing_url_for.rb
@@ -32,7 +32,7 @@ module ActionView
#
# ==== Examples
# <%= url_for(action: 'index') %>
- # # => /blog/
+ # # => /blogs/
#
# <%= url_for(action: 'find', controller: 'books') %>
# # => /books/find
@@ -84,21 +84,13 @@ module ActionView
when Hash
options = options.symbolize_keys
unless options.key?(:only_path)
- if options[:host].nil?
- options[:only_path] = _generate_paths_by_default
- else
- options[:only_path] = false
- end
+ options[:only_path] = only_path?(options[:host])
end
super(options)
when ActionController::Parameters
unless options.key?(:only_path)
- if options[:host].nil?
- options[:only_path] = _generate_paths_by_default
- else
- options[:only_path] = false
- end
+ options[:only_path] = only_path?(options[:host])
end
super(options)
@@ -147,5 +139,9 @@ module ActionView
def _generate_paths_by_default
true
end
+
+ def only_path?(host)
+ _generate_paths_by_default unless host
+ end
end
end
diff --git a/actionview/test/actionpack/abstract/render_test.rb b/actionview/test/actionpack/abstract/render_test.rb
index e5721d6416..e185b76adb 100644
--- a/actionview/test/actionpack/abstract/render_test.rb
+++ b/actionview/test/actionpack/abstract/render_test.rb
@@ -1,5 +1,4 @@
require 'abstract_unit'
-require 'active_support/deprecation'
module AbstractController
module Testing
diff --git a/actionview/test/actionpack/controller/render_test.rb b/actionview/test/actionpack/controller/render_test.rb
index 27150c7d5f..bdb9e0397b 100644
--- a/actionview/test/actionpack/controller/render_test.rb
+++ b/actionview/test/actionpack/controller/render_test.rb
@@ -466,7 +466,7 @@ class TestController < ApplicationController
end
def render_content_type_from_body
- response.content_type = Mime::RSS
+ response.content_type = Mime[:rss]
render body: "hello world!"
end
@@ -728,7 +728,7 @@ class RenderTest < ActionController::TestCase
def test_render_process
get :render_action_hello_world_as_string
- assert_equal ["Hello world!"], @controller.process(:render_action_hello_world_as_string)
+ assert_equal "Hello world!", @controller.process(:render_action_hello_world_as_string)
end
# :ported:
diff --git a/actionview/test/fixtures/digestor/comments/_comment.html.erb b/actionview/test/fixtures/digestor/comments/_comment.html.erb
index f172e749da..a8fa21f644 100644
--- a/actionview/test/fixtures/digestor/comments/_comment.html.erb
+++ b/actionview/test/fixtures/digestor/comments/_comment.html.erb
@@ -1 +1 @@
-Great story, bro!
+Great story!
diff --git a/actionview/test/template/form_collections_helper_test.rb b/actionview/test/template/form_collections_helper_test.rb
index b193d387c3..b59be8e36c 100644
--- a/actionview/test/template/form_collections_helper_test.rb
+++ b/actionview/test/template/form_collections_helper_test.rb
@@ -198,6 +198,41 @@ class FormCollectionsHelperTest < ActionView::TestCase
assert_select 'input[type=radio][value=false][checked=checked]'
end
+ test 'collection radio buttons generates only one hidden field for the entire collection, to ensure something will be sent back to the server when posting an empty collection' do
+ collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')]
+ with_collection_radio_buttons :user, :category_ids, collection, :id, :name
+
+ assert_select "input[type=hidden][name='user[category_ids][]'][value='']", count: 1
+ end
+
+ test 'collection radio buttons generates a hidden field using the given :name in :html_options' do
+ collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')]
+ with_collection_radio_buttons :user, :category_ids, collection, :id, :name, {}, { name: "user[other_category_ids][]" }
+
+ assert_select "input[type=hidden][name='user[other_category_ids][]'][value='']", count: 1
+ end
+
+ test 'collection radio buttons generates a hidden field with index if it was provided' do
+ collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')]
+ with_collection_radio_buttons :user, :category_ids, collection, :id, :name, { index: 322 }
+
+ assert_select "input[type=hidden][name='user[322][category_ids][]'][value='']", count: 1
+ end
+
+ test 'collection radio buttons does not generate a hidden field if include_hidden option is false' do
+ collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')]
+ with_collection_radio_buttons :user, :category_ids, collection, :id, :name, include_hidden: false
+
+ assert_select "input[type=hidden][name='user[category_ids][]'][value='']", count: 0
+ end
+
+ test 'collection radio buttons does not generate a hidden field if include_hidden option is false with key as string' do
+ collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')]
+ with_collection_radio_buttons :user, :category_ids, collection, :id, :name, 'include_hidden' => false
+
+ assert_select "input[type=hidden][name='user[category_ids][]'][value='']", count: 0
+ end
+
# COLLECTION CHECK BOXES
test 'collection check boxes accepts a collection and generate a series of checkboxes for value method' do
collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')]
@@ -235,6 +270,13 @@ class FormCollectionsHelperTest < ActionView::TestCase
assert_select "input[type=hidden][name='user[category_ids][]'][value='']", :count => 0
end
+ test 'collection check boxes does not generate a hidden field if include_hidden option is false with key as string' do
+ collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')]
+ with_collection_check_boxes :user, :category_ids, collection, :id, :name, 'include_hidden' => false
+
+ assert_select "input[type=hidden][name='user[category_ids][]'][value='']", count: 0
+ end
+
test 'collection check boxes accepts a collection and generate a series of checkboxes with labels for label method' do
collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')]
with_collection_check_boxes :user, :category_ids, collection, :id, :name
@@ -264,6 +306,17 @@ class FormCollectionsHelperTest < ActionView::TestCase
assert_select 'input[type=checkbox][value="2"].bar'
end
+ test 'collection check boxes propagates input id to the label for attribute' do
+ collection = [[1, 'Category 1', {id: 'foo'}], [2, 'Category 2', {id: 'bar'}]]
+ with_collection_check_boxes :user, :active, collection, :first, :second
+
+ assert_select 'input[type=checkbox][value="1"]#foo'
+ assert_select 'input[type=checkbox][value="2"]#bar'
+
+ assert_select 'label[for=foo]'
+ assert_select 'label[for=bar]'
+ end
+
test 'collection check boxes sets the label class defined inside the block' do
collection = [[1, 'Category 1', {class: 'foo'}], [2, 'Category 2', {class: 'bar'}]]
with_collection_check_boxes :user, :active, collection, :second, :first do |b|
diff --git a/actionview/test/template/form_helper_test.rb b/actionview/test/template/form_helper_test.rb
index f6181c28fd..e540bf27d9 100644
--- a/actionview/test/template/form_helper_test.rb
+++ b/actionview/test/template/form_helper_test.rb
@@ -1597,7 +1597,8 @@ class FormHelperTest < ActionView::TestCase
"<input id='post_active_true' name='post[active]' type='radio' value='true' />" +
"<label for='post_active_true'>true</label>" +
"<input checked='checked' id='post_active_false' name='post[active]' type='radio' value='false' />" +
- "<label for='post_active_false'>false</label>"
+ "<label for='post_active_false'>false</label>" +
+ "<input type='hidden' name='post[active][]' value='' />"
end
assert_dom_equal expected, output_buffer
@@ -1620,7 +1621,8 @@ class FormHelperTest < ActionView::TestCase
"true</label>" +
"<label for='post_active_false'>"+
"<input checked='checked' id='post_active_false' name='post[active]' type='radio' value='false' />" +
- "false</label>"
+ "false</label>" +
+ "<input type='hidden' name='post[active][]' value='' />"
end
assert_dom_equal expected, output_buffer
@@ -1646,6 +1648,7 @@ class FormHelperTest < ActionView::TestCase
"<label for='post_active_false'>"+
"<input checked='checked' id='post_active_false' name='post[active]' type='radio' value='false' />" +
"false</label>"+
+ "<input type='hidden' name='post[active][]' value='' />" +
"<input id='post_id' name='post[id]' type='hidden' value='1' />"
end
@@ -1664,7 +1667,8 @@ class FormHelperTest < ActionView::TestCase
"<input id='foo_post_active_true' name='post[active]' type='radio' value='true' />" +
"<label for='foo_post_active_true'>true</label>" +
"<input checked='checked' id='foo_post_active_false' name='post[active]' type='radio' value='false' />" +
- "<label for='foo_post_active_false'>false</label>"
+ "<label for='foo_post_active_false'>false</label>" +
+ "<input type='hidden' name='post[active][]' value='' />"
end
assert_dom_equal expected, output_buffer
@@ -1682,7 +1686,8 @@ class FormHelperTest < ActionView::TestCase
"<input id='post_1_active_true' name='post[1][active]' type='radio' value='true' />" +
"<label for='post_1_active_true'>true</label>" +
"<input checked='checked' id='post_1_active_false' name='post[1][active]' type='radio' value='false' />" +
- "<label for='post_1_active_false'>false</label>"
+ "<label for='post_1_active_false'>false</label>" +
+ "<input type='hidden' name='post[1][active][]' value='' />"
end
assert_dom_equal expected, output_buffer
@@ -2293,6 +2298,27 @@ class FormHelperTest < ActionView::TestCase
assert_dom_equal expected, output_buffer
end
+ def test_deep_nested_fields_for
+ @comment.save
+ form_for(:posts) do |f|
+ f.fields_for('post[]', @post) do |f2|
+ f2.text_field(:id)
+ @post.comments.each do |comment|
+ concat f2.fields_for('comment[]', comment) { |c|
+ concat c.text_field(:name)
+ }
+ end
+ end
+ end
+
+ expected = whole_form do
+ "<input name='posts[post][0][comment][1][name]' type='text' id='posts_post_0_comment_1_name' value='comment #1' />"
+ end
+
+ assert_dom_equal expected, output_buffer
+ end
+
+
def test_nested_fields_for_with_nested_collections
form_for(@post, as: 'post[]') do |f|
concat f.text_field(:title)
diff --git a/actionview/test/template/form_tag_helper_test.rb b/actionview/test/template/form_tag_helper_test.rb
index a9d9562580..de1eb89dc5 100644
--- a/actionview/test/template/form_tag_helper_test.rb
+++ b/actionview/test/template/form_tag_helper_test.rb
@@ -64,6 +64,18 @@ class FormTagHelperTest < ActionView::TestCase
assert_dom_equal expected, actual
end
+ def test_check_box_tag_disabled
+ actual = check_box_tag "admin","1", false, disabled: true
+ expected = %(<input id="admin" disabled="disabled" name="admin" type="checkbox" value="1" />)
+ assert_dom_equal expected, actual
+ end
+
+ def test_check_box_tag_default_checked
+ actual = check_box_tag "admin","1", true
+ expected = %(<input id="admin" checked="checked" name="admin" type="checkbox" value="1" />)
+ assert_dom_equal expected, actual
+ end
+
def test_check_box_tag_id_sanitized
label_elem = root_elem(check_box_tag("project[2][admin]"))
assert_match VALID_HTML_ID, label_elem['id']
@@ -351,12 +363,18 @@ class FormTagHelperTest < ActionView::TestCase
assert_dom_equal expected, actual
end
- def test_text_field_disabled
+ def test_text_field_tag_disabled
actual = text_field_tag "title", "Hello!", disabled: true
expected = %(<input id="title" name="title" disabled="disabled" type="text" value="Hello!" />)
assert_dom_equal expected, actual
end
+ def test_text_field_tag_with_placeholder_option
+ actual = text_field_tag "title", "Hello!", placeholder: 'Enter search term...'
+ expected = %(<input id="title" name="title" placeholder="Enter search term..." type="text" value="Hello!" />)
+ assert_dom_equal expected, actual
+ end
+
def test_text_field_tag_with_multiple_options
actual = text_field_tag "title", "Hello!", :size => 70, :maxlength => 80
expected = %(<input id="title" name="title" size="70" maxlength="80" type="text" value="Hello!" />)
@@ -450,21 +468,21 @@ class FormTagHelperTest < ActionView::TestCase
ActionView::Base.automatically_disable_submit_tag = true
end
- def test_data_disable_with_string
+ def test_submit_tag_having_data_disable_with_string
assert_dom_equal(
%(<input data-disable-with="Processing..." data-confirm="Are you sure?" name='commit' type="submit" value="Save" />),
submit_tag("Save", { "data-disable-with" => "Processing...", "data-confirm" => "Are you sure?" })
)
end
- def test_data_disable_with_boolean
+ def test_submit_tag_having_data_disable_with_boolean
assert_dom_equal(
%(<input data-confirm="Are you sure?" name='commit' type="submit" value="Save" />),
submit_tag("Save", { "data-disable-with" => false, "data-confirm" => "Are you sure?" })
)
end
- def test_data_hash_disable_with_boolean
+ def test_submit_tag_having_data_hash_disable_with_boolean
assert_dom_equal(
%(<input data-confirm="Are you sure?" name='commit' type="submit" value="Save" />),
submit_tag("Save", { :data => { :confirm => "Are you sure?", :disable_with => false } })
@@ -485,6 +503,14 @@ class FormTagHelperTest < ActionView::TestCase
)
end
+ def test_submit_tag_doesnt_have_data_disable_with_twice
+ assert_equal(
+ %(<input type="submit" name="commit" value="Save" data-confirm="Are you sure?" data-disable-with="Processing..." />),
+ submit_tag("Save", { "data-disable-with" => "Processing...", "data-confirm" => "Are you sure?" })
+ )
+ end
+
+
def test_button_tag
assert_dom_equal(
%(<button name="button" type="submit">Button</button>),
diff --git a/actionview/test/template/lookup_context_test.rb b/actionview/test/template/lookup_context_test.rb
index 14dafd7d63..2e3a3f9bae 100644
--- a/actionview/test/template/lookup_context_test.rb
+++ b/actionview/test/template/lookup_context_test.rb
@@ -27,7 +27,7 @@ class LookupContextTest < ActiveSupport::TestCase
end
test "normalizes details on initialization" do
- assert_equal Mime::SET, @lookup_context.formats
+ assert_equal Mime::SET.to_a, @lookup_context.formats
assert_equal :en, @lookup_context.locale
end
@@ -48,7 +48,7 @@ class LookupContextTest < ActiveSupport::TestCase
test "handles */* formats" do
@lookup_context.formats = ["*/*"]
- assert_equal Mime::SET, @lookup_context.formats
+ assert_equal Mime::SET.to_a, @lookup_context.formats
end
test "handles explicitly defined */* formats fallback to :js" do
diff --git a/actionview/test/template/render_test.rb b/actionview/test/template/render_test.rb
index 9c2c9507b7..00fc28a522 100644
--- a/actionview/test/template/render_test.rb
+++ b/actionview/test/template/render_test.rb
@@ -627,6 +627,16 @@ class CachedCollectionViewRenderTest < CachedViewRenderTest
@view.render(partial: "test/customer", collection: [customer], cache: ->(item) { [item, 'key'] })
end
+ test "with caching with custom key and rendering with different key" do
+ customer = Customer.new("david")
+ key = cache_key([customer, 'key'], "test/_customer")
+
+ ActionView::PartialRenderer.collection_cache.write(key, 'Hello')
+
+ assert_equal "Hello: david",
+ @view.render(partial: "test/customer", collection: [customer], cache: ->(item) { [item, 'another_key'] })
+ end
+
test "automatic caching with inferred cache name" do
customer = CachedCustomer.new("david")
key = cache_key(customer, "test/_cached_customer")
diff --git a/actionview/test/template/translation_helper_test.rb b/actionview/test/template/translation_helper_test.rb
index 261576bead..631bceadd8 100644
--- a/actionview/test/template/translation_helper_test.rb
+++ b/actionview/test/template/translation_helper_test.rb
@@ -66,6 +66,14 @@ class TranslationHelperTest < ActiveSupport::TestCase
assert translate(:"translations.missing").html_safe?
end
+ def test_returns_missing_translation_message_does_filters_out_i18n_options
+ expected = '<span class="translation_missing" title="translation missing: en.translations.missing, year: 2015">Missing</span>'
+ assert_equal expected, translate(:"translations.missing", year: '2015', default: [])
+
+ expected = '<span class="translation_missing" title="translation missing: en.scoped.translations.missing, year: 2015">Missing</span>'
+ assert_equal expected, translate(:"translations.missing", year: '2015', scope: %i(scoped))
+ end
+
def test_raises_missing_translation_message_with_raise_config_option
ActionView::Base.raise_on_missing_translations = true