Permalink
Browse files

Added :as => :country as a new input option (default for :string colu…

…mns with names matching /country/).

Rails doesn't come with a country_select helper by default any more, so you'll need to install the "official" plugin, or any other country_select plugin you wish that behaves in the same way.

A default set of "priority countries" is always included, and can be configured (see README).
  • Loading branch information...
1 parent 012f7cc commit 82394788418b640178968bee3ca3d7f4f29cd6c7 @justinfrench committed May 11, 2009
Showing with 128 additions and 3 deletions.
  1. +6 −0 README.textile
  2. +37 −2 lib/formtastic.rb
  3. +85 −1 spec/formtastic_spec.rb
View
@@ -239,6 +239,8 @@ h2. The Available Inputs
* :string (a text field) - default for :string column types
* :numeric (a text field, like string) - default for :integer, :float and :decimal column types
* :file (a file field) - default for paperclip or attachment_fu attributes
+* :country (a select menu of country names) - default for :string columns named "country", requires a country_select plugin to be installed
+
The documentation is pretty good for each of these (what it does, what the output is, what the options are, etc) so go check it out.
@@ -285,6 +287,9 @@ If you wish, put something like this in config/initializers/formtastic_config.rb
# the input, in the following order: hints, input and errors. You can
# customize it doing just as below:
Formtastic::SemanticFormBuilder.inline_order = [:hints, :input, :errors]
+
+ # Set the default "priority countries" to suit your user base when using :as => :country
+ Formtastic::SemanticFormBuilder.priority_countries = ["Australia", "New Zealand"]
</pre>
@@ -314,6 +319,7 @@ h2. Dependencies
There are none, but...
* if you have the "ValidationReflection":http://github.com/redinger/validation_reflection plugin is installed, you won't have to specify the :required option (it checks the validations on the model instead)
+* if you want to use the :country input, you'll need to install the "iso-3166-country-select plugin":http://github.com/rails/iso-3166-country-select (or any other country_select plugin with the same API)
* rspec, rspec_hpricot_matchers and rcov gems (plus any of their own dependencies) are required for the test suite
View
@@ -18,13 +18,13 @@ class SemanticFormBuilder < ActionView::Helpers::FormBuilder
@@collection_label_methods = %w[to_label display_name full_name name title username login value to_s]
@@inline_order = [ :input, :hints, :errors ]
@@file_methods = [ :file?, :public_filename ]
+ @@priority_countries = ["Australia", "Canada", "United Kingdom", "United States"]
cattr_accessor :default_text_field_size, :all_fields_required_by_default, :required_string,
:optional_string, :inline_errors, :label_str_method, :collection_label_methods,
- :inline_order, :file_methods
+ :inline_order, :file_methods, :priority_countries
# Keeps simple mappings in a hash
- #
INPUT_MAPPINGS = {
:string => :text_field,
:password => :password_field,
@@ -66,6 +66,7 @@ class SemanticFormBuilder < ActionView::Helpers::FormBuilder
# * :boolean (a checkbox) - default for :boolean column types (you can also have booleans as :select and :radio)
# * :string (a text field) - default for :string column types
# * :numeric (a text field, like string) - default for :integer, :float and :decimal column types
+ # * :country (a select menu of country names) - requires a country_select plugin to be installed
#
# Example:
#
@@ -818,6 +819,39 @@ def check_boxes_input(method, options)
field_set_and_list_wrapping_for_method(method, options, list_item_content)
end
+
+
+ # Outputs a country select input, wrapping around a regular country_select helper.
+ # Rails doesn't come with a country_select helper by default any more, so you'll need to install
+ # the "official" plugin, or, if you wish, any other country_select plugin that behaves in the
+ # same way.
+ #
+ # The Rails plugin iso-3166-country-select plugin can be found "here":http://github.com/rails/iso-3166-country-select.
+ #
+ # By default, Formtastic includes a handfull of english-speaking countries as "priority counties",
+ # which you can change to suit your market and user base (see README for more info on config).
+ #
+ # Examples:
+ # f.input :location, :as => :country # use Formtastic::SemanticFormBuilder.priority_countries array for the priority countries
+ # f.input :location, :as => :country, :priority_countries => /Australia/ # set your own
+ #
+ def country_input(method, options)
+ raise "To use the :country input, please install a country_select plugin, like this one: http://github.com/rails/iso-3166-country-select" unless self.respond_to?(:country_select)
+
+ html_options = options.delete(:input_html) || {}
+
+ self.label(method, options.slice(:label, :required)) +
+ self.country_select(method, options.delete(:priority_countries), set_options(options), html_options)
+ end
+
+
+ def time_zone_input(method, options)
+ html_options = options.delete(:input_html) || {}
+
+ self.label(method, options.slice(:label, :required)) +
+ self.time_zone_select(method, options.delete(:priority_zones), set_options(options), html_options)
+ end
+
# Outputs a label containing a checkbox and the label text. The label defaults
# to the column name (method name) and can be altered with the :label option.
@@ -950,6 +984,7 @@ def default_input_type(method) #:nodoc:
return :datetime if column.type == :timestamp
return :numeric if [:integer, :float, :decimal].include?(column.type)
return :password if column.type == :string && method.to_s =~ /password/
+ return :country if column.type == :string && method.to_s =~ /country/
# otherwise assume the input name will be the same as the column type (eg string_input)
return column.type
View
@@ -234,6 +234,10 @@ class Author; end
@new_post.stub!(:body)
@new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string, :limit => 255))
end
+
+ after do
+ Formtastic::SemanticFormHelper.builder = Formtastic::SemanticFormBuilder
+ end
it "can be overridden" do
@@ -635,6 +639,10 @@ def custom(arg1, arg2, options = {})
default_input_type(:float).should == :numeric
default_input_type(:decimal).should == :numeric
end
+
+ it 'should default to :country for :string columns named country' do
+ default_input_type(:string, :country).should == :country
+ end
describe 'defaulting to file column' do
Formtastic::SemanticFormBuilder.file_methods.each do |method|
@@ -1127,7 +1135,84 @@ def custom(arg1, arg2, options = {})
end
end
end
+
+ describe ":as => :country" do
+
+ before do
+ @new_post.stub!(:country)
+ @new_post.stub!(:column_for_attribute).and_return(mock('column', :type => :string))
+ end
+
+ describe "when country_select is not available as a helper from a plugin" do
+
+ it "should raise an error, sugesting the author installs a plugin" do
+ lambda {
+ semantic_form_for(@new_post) do |builder|
+ concat(builder.input(:country, :as => :country))
+ end
+ }.should raise_error
+ end
+
+ end
+
+ describe "when country_select is available as a helper (from a plugin)" do
+
+ before do
+ semantic_form_for(@new_post) do |builder|
+ builder.stub!(:country_select).and_return("<select><option>...</option></select>")
+ concat(builder.input(:country, :as => :country))
+ end
+ end
+
+ it "should have a time_zone class on the wrapper" do
+ output_buffer.should have_tag('form li.country')
+ end
+ it 'should have a post_title_input id on the wrapper' do
+ output_buffer.should have_tag('form li#post_country_input')
+ end
+
+ it 'should generate a label for the input' do
+ output_buffer.should have_tag('form li label')
+ output_buffer.should have_tag('form li label[@for="post_country"')
+ output_buffer.should have_tag('form li label', /Country/)
+ end
+
+ it "should generate a select" do
+ output_buffer.should have_tag("form li select")
+ end
+
+ end
+
+ describe ":priority_countries option" do
+
+ it "should be passed down to the country_select helper when provided" do
+ priority_countries = ["Foo", "Bah"]
+ semantic_form_for(@new_post) do |builder|
+ builder.stub!(:country_select).and_return("<select><option>...</option></select>")
+ builder.should_receive(:country_select).with(:country, priority_countries, {}, {}).and_return("<select><option>...</option></select>")
+
+ concat(builder.input(:country, :as => :country, :priority_countries => priority_countries))
+ end
+ end
+
+ it "should default to the @@priority_countries config when absent" do
+ priority_countries = Formtastic::SemanticFormBuilder.priority_countries
+ priority_countries.should_not be_empty
+ priority_countries.should_not be_nil
+
+ semantic_form_for(@new_post) do |builder|
+ builder.stub!(:country_select).and_return("<select><option>...</option></select>")
+ builder.should_receive(:country_select).with(:country, priority_countries, {}, {}).and_return("<select><option>...</option></select>")
+
+ concat(builder.input(:country, :as => :country, :priority_countries => priority_countries))
+ end
+ end
+
+ end
+
+ end
+
describe ':as => :radio' do
before do
@@ -2158,7 +2243,6 @@ def custom(arg1, arg2, options = {})
end
end
-
describe '#inputs' do
describe 'with a block' do

1 comment on commit 8239478

Contributor

josevalim commented on 8239478 May 12, 2009

Awesome too!

Please sign in to comment.