aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCarlos Antonio da Silva <carlosantoniodasilva@gmail.com>2012-01-31 16:31:17 -0200
committerCarlos Antonio da Silva <carlosantoniodasilva@gmail.com>2012-02-02 09:40:22 -0200
commit7af0ec75d0d933d75f9a63a63bbbde554f206721 (patch)
tree481d56735c6c1a5d0efb6faa2fb30b435789587f
parent9323fb60572815fc63fa618a5bd17b68cf8c8e35 (diff)
downloadrails-7af0ec75d0d933d75f9a63a63bbbde554f206721.tar.gz
rails-7af0ec75d0d933d75f9a63a63bbbde554f206721.tar.bz2
rails-7af0ec75d0d933d75f9a63a63bbbde554f206721.zip
Add collection_check_boxes helper
[Carlos Antonio da Silva + Rafael Mendonça França]
-rw-r--r--actionpack/lib/action_view/helpers/form_options_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/tags.rb1
-rw-r--r--actionpack/lib/action_view/helpers/tags/collection_check_boxes.rb30
-rw-r--r--actionpack/test/template/form_collections_helper_test.rb228
4 files changed, 262 insertions, 1 deletions
diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb
index 5ca2f2abdc..96519a7428 100644
--- a/actionpack/lib/action_view/helpers/form_options_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_options_helper.rb
@@ -195,6 +195,10 @@ module ActionView
Tags::CollectionRadioButtons.new(object, method, self, collection, value_method, text_method, options, html_options).render(&block)
end
+ def collection_check_boxes(object, method, collection, value_method, text_method, options = {}, html_options = {}, &block)
+ Tags::CollectionCheckBoxes.new(object, method, self, collection, value_method, text_method, options, html_options).render(&block)
+ end
+
# Returns <tt><select></tt>, <tt><optgroup></tt> and <tt><option></tt> tags for the collection of existing return values of
# +method+ for +object+'s class. The value returned from calling +method+ on the instance +object+ will
# be selected. If calling +method+ returns +nil+, no selection is made without including <tt>:prompt</tt>
diff --git a/actionpack/lib/action_view/helpers/tags.rb b/actionpack/lib/action_view/helpers/tags.rb
index fa19cf2dba..c480799fe3 100644
--- a/actionpack/lib/action_view/helpers/tags.rb
+++ b/actionpack/lib/action_view/helpers/tags.rb
@@ -5,6 +5,7 @@ module ActionView
autoload :Base
autoload :CheckBox
+ autoload :CollectionCheckBoxes
autoload :CollectionRadioButtons
autoload :CollectionSelect
autoload :DateSelect
diff --git a/actionpack/lib/action_view/helpers/tags/collection_check_boxes.rb b/actionpack/lib/action_view/helpers/tags/collection_check_boxes.rb
new file mode 100644
index 0000000000..d8f7a1fff6
--- /dev/null
+++ b/actionpack/lib/action_view/helpers/tags/collection_check_boxes.rb
@@ -0,0 +1,30 @@
+module ActionView
+ module Helpers
+ module Tags
+ class CollectionCheckBoxes < CollectionRadioButtons
+ delegate :check_box, :label, :to => :@template_object
+
+ def render
+ rendered_collection = render_collection(
+ @method_name, @collection, @value_method, @text_method, @options, @html_options
+ ) do |value, text, default_html_options|
+ default_html_options[:multiple] = true
+
+ if block_given?
+ yield sanitize_attribute_name(@method_name, value), text, value, default_html_options
+ else
+ check_box(@object_name, @method_name, default_html_options, value, nil) +
+ label(@object_name, sanitize_attribute_name(@method_name, value), text, :class => "collection_check_boxes")
+ end
+ end
+
+ # Prepend a hidden field to make sure something will be sent back to the
+ # server if all checkboxes are unchecked.
+ hidden = @template_object.hidden_field_tag("#{@object_name}[#{@method_name}][]", "", :id => nil)
+
+ wrap_rendered_collection(rendered_collection + hidden, @options)
+ end
+ end
+ end
+ end
+end
diff --git a/actionpack/test/template/form_collections_helper_test.rb b/actionpack/test/template/form_collections_helper_test.rb
index 7af634936d..e8ec274a04 100644
--- a/actionpack/test/template/form_collections_helper_test.rb
+++ b/actionpack/test/template/form_collections_helper_test.rb
@@ -1,5 +1,8 @@
require 'abstract_unit'
+class Tag < Struct.new(:id, :name)
+end
+
class FormCollectionsHelperTest < ActionView::TestCase
def assert_no_select(selector, value = nil)
assert_select(selector, :text => value, :count => 0)
@@ -9,7 +12,11 @@ class FormCollectionsHelperTest < ActionView::TestCase
concat collection_radio_buttons(*args, &block)
end
- # COLLECTION RADIO
+ def with_collection_check_boxes(*args, &block)
+ concat collection_check_boxes(*args, &block)
+ end
+
+ # COLLECTION RADIO BUTTONS
test 'collection radio accepts a collection and generate inputs from value method' do
with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s
@@ -171,4 +178,223 @@ class FormCollectionsHelperTest < ActionView::TestCase
assert_select 'label[for=user_active_true] > input#user_active_true[type=radio]'
assert_select 'label[for=user_active_false] > input#user_active_false[type=radio]'
end
+
+ # COLLECTION CHECK BOXES
+ test 'collection check boxes accepts a collection and generate a serie of checkboxes for value method' do
+ collection = [Tag.new(1, 'Tag 1'), Tag.new(2, 'Tag 2')]
+ with_collection_check_boxes :user, :tag_ids, collection, :id, :name
+
+ assert_select 'input#user_tag_ids_1[type=checkbox][value=1]'
+ assert_select 'input#user_tag_ids_2[type=checkbox][value=2]'
+ end
+
+ test 'collection check boxes 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 = [Tag.new(1, 'Tag 1'), Tag.new(2, 'Tag 2')]
+ with_collection_check_boxes :user, :tag_ids, collection, :id, :name
+
+ assert_select "input[type=hidden][name='user[tag_ids][]'][value=]", :count => 1
+ end
+
+ test 'collection check boxes accepts a collection and generate a serie of checkboxes with labels for label method' do
+ collection = [Tag.new(1, 'Tag 1'), Tag.new(2, 'Tag 2')]
+ with_collection_check_boxes :user, :tag_ids, collection, :id, :name
+
+ assert_select 'label.collection_check_boxes[for=user_tag_ids_1]', 'Tag 1'
+ assert_select 'label.collection_check_boxes[for=user_tag_ids_2]', 'Tag 2'
+ end
+
+ test 'collection check boxes handles camelized collection values for labels correctly' do
+ with_collection_check_boxes :user, :active, ['Yes', 'No'], :to_s, :to_s
+
+ assert_select 'label.collection_check_boxes[for=user_active_yes]', 'Yes'
+ assert_select 'label.collection_check_boxes[for=user_active_no]', 'No'
+ end
+
+ test 'colection check box should sanitize collection values for labels correctly' do
+ with_collection_check_boxes :user, :name, ['$0.99', '$1.99'], :to_s, :to_s
+ assert_select 'label.collection_check_boxes[for=user_name_099]', '$0.99'
+ assert_select 'label.collection_check_boxes[for=user_name_199]', '$1.99'
+ end
+
+ test 'collection check boxes accepts selected values as :checked option' do
+ collection = (1..3).map{|i| [i, "Tag #{i}"] }
+ with_collection_check_boxes :user, :tag_ids, collection, :first, :last, :checked => [1, 3]
+
+ assert_select 'input[type=checkbox][value=1][checked=checked]'
+ assert_select 'input[type=checkbox][value=3][checked=checked]'
+ assert_no_select 'input[type=checkbox][value=2][checked=checked]'
+ end
+
+ test 'collection check boxes accepts a single checked value' do
+ collection = (1..3).map{|i| [i, "Tag #{i}"] }
+ with_collection_check_boxes :user, :tag_ids, collection, :first, :last, :checked => 3
+
+ assert_select 'input[type=checkbox][value=3][checked=checked]'
+ assert_no_select 'input[type=checkbox][value=1][checked=checked]'
+ assert_no_select 'input[type=checkbox][value=2][checked=checked]'
+ end
+
+ test 'collection check boxes accepts selected values as :checked option and override the model values' do
+ skip "check with fields for"
+ collection = (1..3).map{|i| [i, "Tag #{i}"] }
+ :user.tag_ids = [2]
+ with_collection_check_boxes :user, :tag_ids, collection, :first, :last, :checked => [1, 3]
+
+ assert_select 'input[type=checkbox][value=1][checked=checked]'
+ assert_select 'input[type=checkbox][value=3][checked=checked]'
+ assert_no_select 'input[type=checkbox][value=2][checked=checked]'
+ end
+
+ test 'collection check boxes accepts multiple disabled items' do
+ collection = (1..3).map{|i| [i, "Tag #{i}"] }
+ with_collection_check_boxes :user, :tag_ids, collection, :first, :last, :disabled => [1, 3]
+
+ assert_select 'input[type=checkbox][value=1][disabled=disabled]'
+ assert_select 'input[type=checkbox][value=3][disabled=disabled]'
+ assert_no_select 'input[type=checkbox][value=2][disabled=disabled]'
+ end
+
+ test 'collection check boxes accepts single disable item' do
+ collection = (1..3).map{|i| [i, "Tag #{i}"] }
+ with_collection_check_boxes :user, :tag_ids, collection, :first, :last, :disabled => 1
+
+ assert_select 'input[type=checkbox][value=1][disabled=disabled]'
+ assert_no_select 'input[type=checkbox][value=3][disabled=disabled]'
+ assert_no_select 'input[type=checkbox][value=2][disabled=disabled]'
+ end
+
+ test 'collection check boxes accepts a proc to disabled items' do
+ collection = (1..3).map{|i| [i, "Tag #{i}"] }
+ with_collection_check_boxes :user, :tag_ids, collection, :first, :last, :disabled => proc { |i| i.first == 1 }
+
+ assert_select 'input[type=checkbox][value=1][disabled=disabled]'
+ assert_no_select 'input[type=checkbox][value=3][disabled=disabled]'
+ assert_no_select 'input[type=checkbox][value=2][disabled=disabled]'
+ end
+
+ test 'collection check boxes accepts html options' do
+ collection = [[1, 'Tag 1'], [2, 'Tag 2']]
+ with_collection_check_boxes :user, :tag_ids, collection, :first, :last, {}, :class => 'check'
+
+ assert_select 'input.check[type=checkbox][value=1]'
+ assert_select 'input.check[type=checkbox][value=2]'
+ end
+
+ test 'collection check boxes with fields for' do
+ skip "test collection check boxes with fields for (and radio buttons as well)"
+ collection = [Tag.new(1, 'Tag 1'), Tag.new(2, 'Tag 2')]
+ concat(form_for(:user) do |f|
+ f.fields_for(:post) do |p|
+ p.collection_check_boxes :tag_ids, collection, :id, :name
+ end
+ end)
+
+ assert_select 'input#user_post_tag_ids_1[type=checkbox][value=1]'
+ assert_select 'input#user_post_tag_ids_2[type=checkbox][value=2]'
+
+ assert_select 'label.collection_check_boxes[for=user_post_tag_ids_1]', 'Tag 1'
+ assert_select 'label.collection_check_boxes[for=user_post_tag_ids_2]', 'Tag 2'
+ end
+
+ test 'collection check boxeses wraps the collection in the given collection wrapper tag' do
+ with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s, :collection_wrapper_tag => :ul
+
+ assert_select 'ul input[type=checkbox]', :count => 2
+ end
+
+ test 'collection check boxeses does not render any wrapper tag by default' do
+ with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s
+
+ assert_select 'input[type=checkbox]', :count => 2
+ assert_no_select 'ul'
+ end
+
+ test 'collection check boxeses does not wrap the collection when given falsy values' do
+ with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s, :collection_wrapper_tag => false
+
+ assert_select 'input[type=checkbox]', :count => 2
+ assert_no_select 'ul'
+ end
+
+ test 'collection check boxeses uses the given class for collection wrapper tag' do
+ with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s,
+ :collection_wrapper_tag => :ul, :collection_wrapper_class => "items-list"
+
+ assert_select 'ul.items-list input[type=checkbox]', :count => 2
+ end
+
+ test 'collection check boxeses uses no class for collection wrapper tag when no wrapper tag is given' do
+ with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s,
+ :collection_wrapper_class => "items-list"
+
+ assert_select 'input[type=checkbox]', :count => 2
+ assert_no_select 'ul'
+ assert_no_select '.items-list'
+ end
+
+ test 'collection check boxeses uses no class for collection wrapper tag by default' do
+ with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s, :collection_wrapper_tag => :ul
+
+ assert_select 'ul'
+ assert_no_select 'ul[class]'
+ end
+
+ test 'collection check boxeses wrap items in a span tag by default' do
+ with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s
+
+ assert_select 'span input[type=checkbox]', :count => 2
+ end
+
+ test 'collection check boxeses wraps each item in the given item wrapper tag' do
+ with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s, :item_wrapper_tag => :li
+
+ assert_select 'li input[type=checkbox]', :count => 2
+ end
+
+ test 'collection check boxeses does not wrap each item when given explicitly falsy value' do
+ with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s, :item_wrapper_tag => false
+
+ assert_select 'input[type=checkbox]'
+ assert_no_select 'span input[type=checkbox]'
+ end
+
+ test 'collection check boxeses uses the given class for item wrapper tag' do
+ with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s,
+ :item_wrapper_tag => :li, :item_wrapper_class => "inline"
+
+ assert_select "li.inline input[type=checkbox]", :count => 2
+ end
+
+ test 'collection check boxeses uses no class for item wrapper tag when no wrapper tag is given' do
+ with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s,
+ :item_wrapper_tag => nil, :item_wrapper_class => "inline"
+
+ assert_select 'input[type=checkbox]', :count => 2
+ assert_no_select 'li'
+ assert_no_select '.inline'
+ end
+
+ test 'collection check boxeses uses no class for item wrapper tag by default' do
+ with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s,
+ :item_wrapper_tag => :li
+
+ assert_select "li", :count => 2
+ assert_no_select "li[class]"
+ end
+
+ test 'collection check boxes does not wrap input inside the label' do
+ with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s
+
+ assert_select 'input[type=checkbox] + label'
+ assert_no_select 'label input'
+ end
+
+ test 'collection check boxes accepts a block to render the radio and label as required' do
+ with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s do |label_for, text, value, html_options|
+ label(:user, label_for, text) { check_box(:user, :active, html_options, value) }
+ end
+
+ assert_select 'label[for=user_active_true] > input#user_active_true[type=checkbox]'
+ assert_select 'label[for=user_active_false] > input#user_active_false[type=checkbox]'
+ end
end