Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Collections - support for sets and symbols #885

Merged
merged 8 commits into from

3 participants

@dwbutler

I'm using the role_model gem to model roles in my application. RoleModel exposes a 'roles' attribute which is implemented as a set of symbols. I tried creating a checkboxes input, but Formtastic just ignored the selected values.

I modified Formtastic input collections to accept sets (or any array-like object that responds to :to_a). I also modified it to work with symbols.

@travisbot

This pull request fails (merged a93299a into 4bd0330).

@dwbutler

Hi, just wondering if you've had a chance to look at this. Thanks!

@justinfrench

@dwbutler looks okay, will need some documentation!

@dwbutler

Sure, no problem! I don't see an obvious place to add documentation though. Should I just add some comments to the modified code?

@justinfrench

@dwbutler I think something would need to go in the examples at the top of CheckBoxesInput and anything else that mixes in Collections, not ideal, but shouldn't take long :)

@dwbutler

I took a look at this again and realized I didn't actually test sets and symbols with the other collection input types. I'll have some more thorough testing and documentation ready to go later this week.

@dwbutler

Okay, I wrote some tests and examples for the three collection classes I could find - check box input, radio input, and select input. I think this should be good to go now.

@justinfrench
Owner

@dwbutler CI fails for 1.8.7 and ree, so I guess you're using some 1.9-only syntax? Haven't looked closely yet, ping me when you think the build is good!

@dwbutler

Nope, everything is passing for me in 1.8.7. Looks like an unhappy coincidence that Travis happened to fail in 1.8.7 and ree. (It failed while trying to run bundle install.)

@dwbutler

Hey, just wondering if you had a chance to run the specs for this. I'm pretty sure the Travis CI results were a fluke. Here's a fairly clean Travis run (which had a misfire in 1.9.3 / Rails 4 this time): https://travis-ci.org/dwbutler/formtastic/builds/4104685

@dwbutler

Bump! :)

I know it's been quite a while, but I merged in master yesterday and the Travis build passes. Would you mind giving this another look?

Thanks!

@justinfrench
Owner

Very late merge. Thanks!

@justinfrench justinfrench merged commit 3aecd12 into justinfrench:master
@dwbutler
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
2  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
View
8 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
View
2  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)
View
18 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
View
18 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
View
20 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
Something went wrong with that request. Please try again.