diff --git a/lib/formtastic/inputs/base/collections.rb b/lib/formtastic/inputs/base/collections.rb index 76d439e84..f827316ab 100644 --- a/lib/formtastic/inputs/base/collections.rb +++ b/lib/formtastic/inputs/base/collections.rb @@ -124,7 +124,7 @@ def send_or_call(duck, object) # Avoids an issue where `send_or_call` can be a String and duck can be something simple like # `:first`, which obviously String responds to. def send_or_call_or_object(duck, object) - return object if object.is_a?(String) || object.is_a?(Integer) # TODO what about other classes etc? + return object if object.is_a?(String) || object.is_a?(Integer) || object.is_a?(Symbol) # TODO what about other classes etc? send_or_call(duck, object) end diff --git a/lib/formtastic/inputs/check_boxes_input.rb b/lib/formtastic/inputs/check_boxes_input.rb index 2db404fea..9f523eed9 100644 --- a/lib/formtastic/inputs/check_boxes_input.rb +++ b/lib/formtastic/inputs/check_boxes_input.rb @@ -46,6 +46,9 @@ module Inputs # <%= f.input :categories, :as => :check_boxes, :collection => [["Ruby", 1], ["Rails", 2]] %> # <%= f.input :categories, :as => :check_boxes, :collection => [["Ruby", 1, {'data-attr' => 'attr-value'}]] %> # <%= f.input :categories, :as => :check_boxes, :collection => 1..5 %> + # <%= f.input :categories, :as => :check_boxes, :collection => [:ruby, :rails] %> + # <%= f.input :categories, :as => :check_boxes, :collection => [["Ruby", :ruby], ["Rails", :rails]] %> + # <%= f.input :categories, :as => :check_boxes, :collection => Set.new([:ruby, :rails]) %> # # @example `:hidden_fields` can be used to skip Rails' rendering of a hidden field before every checkbox # <%= f.input :categories, :as => :check_boxes, :hidden_fields => false %> @@ -182,7 +185,10 @@ def input_name def make_selected_values if object.respond_to?(method) - selected_items = [object.send(method)].compact.flatten + selected_items = object.send(method) + + # Construct an array from the return value, regardless of the return type + selected_items = [*selected_items].compact.flatten [*selected_items.map { |o| send_or_call_or_object(value_method, o) }].compact else diff --git a/lib/formtastic/inputs/radio_input.rb b/lib/formtastic/inputs/radio_input.rb index 435bbccc2..a5b05095c 100644 --- a/lib/formtastic/inputs/radio_input.rb +++ b/lib/formtastic/inputs/radio_input.rb @@ -83,6 +83,8 @@ module Inputs # <%= f.input :author, :as => :radio, :collection => [["Justin", "justin"], ["Kate", "kate"]] %> # <%= f.input :author, :as => :radio, :collection => [["Justin", "1"], ["Kate", "3"]] %> # <%= f.input :author, :as => :radio, :collection => [["Justin", 1], ["Kate", 3]] %> + # <%= f.input :author, :as => :radio, :collection => [["Justin", :justin], ["Kate", :kate]] %> + # <%= f.input :author, :as => :radio, :collection => [:justin, :kate] %> # <%= f.input :author, :as => :radio, :collection => 1..5 %> # # @example The `:member_label` can be used to call a different method (or a Proc) on each object in the collection for rendering the label text (it'll try the methods like `to_s` in `collection_label_methods` config by default) diff --git a/spec/inputs/check_boxes_input_spec.rb b/spec/inputs/check_boxes_input_spec.rb index 227ebc816..de3a34ee1 100644 --- a/spec/inputs/check_boxes_input_spec.rb +++ b/spec/inputs/check_boxes_input_spec.rb @@ -373,6 +373,24 @@ output_buffer.should have_tag("form li fieldset ol li label input[@value='biography'][@checked='checked']") end end + + describe 'when :collection is a set' do + before do + @output_buffer = '' + mock_everything + @fred.stub(:roles) { Set.new([:reviewer, :admin]) } + + concat(semantic_form_for(@fred) do |builder| + concat(builder.input(:roles, :as => :check_boxes, :collection => [['User', :user], ['Reviewer', :reviewer], ['Administrator', :admin]])) + end) + end + + it 'should check the correct checkboxes' do + output_buffer.should have_tag("form li fieldset ol li label input[@value='user']") + output_buffer.should have_tag("form li fieldset ol li label input[@value='admin'][@checked='checked']") + output_buffer.should have_tag("form li fieldset ol li label input[@value='reviewer'][@checked='checked']") + end + end describe "when namespace is provided" do diff --git a/spec/inputs/radio_input_spec.rb b/spec/inputs/radio_input_spec.rb index 4a3806b83..e55a28be4 100644 --- a/spec/inputs/radio_input_spec.rb +++ b/spec/inputs/radio_input_spec.rb @@ -279,4 +279,22 @@ end end + describe "when collection contains symbols" do + before do + @output_buffer = '' + mock_everything + + concat(semantic_form_for(:project) do |builder| + concat(builder.input(:author_id, :as => :radio, :collection => Set.new([["A", :a], ["B", :b], ["C", :c]]))) + end) + end + + it 'should output the correct labels' do + output_buffer.should have_tag("li.choice label", /A/) + output_buffer.should have_tag("li.choice label", /B/) + output_buffer.should have_tag("li.choice label", /C/) + end + end + + end diff --git a/spec/inputs/select_input_spec.rb b/spec/inputs/select_input_spec.rb index 42016bdd4..ba06149ad 100644 --- a/spec/inputs/select_input_spec.rb +++ b/spec/inputs/select_input_spec.rb @@ -30,6 +30,26 @@ end end end + + describe 'using a set of values' do + before do + @set_with_values = Set.new(["Title A", "Title B", "Title C"]) + @set_with_keys_and_values = [["Title D", :d], ["Title E", :e], ["Title F", :f]] + concat(semantic_form_for(@new_post) do |builder| + concat(builder.input(:title, :as => :select, :collection => @set_with_values)) + concat(builder.input(:title, :as => :select, :collection => @set_with_keys_and_values)) + end) + end + + it 'should have a option for each key and/or value' do + @set_with_values.each do |v| + output_buffer.should have_tag("form li select option[@value='#{v}']", /^#{v}$/) + end + @set_with_keys_and_values.each do |v| + output_buffer.should have_tag("form li select option[@value='#{v.second}']", /^#{v.first}$/) + end + end + end describe "using a related model without reflection's options (Mongoid Document)" do before do