diff --git a/lib/formtastic.rb b/lib/formtastic.rb index 91e103bdf..0e4943c93 100644 --- a/lib/formtastic.rb +++ b/lib/formtastic.rb @@ -76,7 +76,7 @@ class SemanticFormBuilder < ActionView::Helpers::FormBuilder # def input(method, options = {}) options[:required] = method_required?(method) unless options.key?(:required) - options[:as] ||= default_input_type(method) + options[:as] ||= default_input_type(method, options) html_class = [ options[:as], (options[:required] ? :required : :optional) ] html_class << 'error' if @object && @object.respond_to?(:errors) && !@object.errors[method.to_sym].blank? @@ -1225,27 +1225,31 @@ def field_set_and_list_wrapping_for_method(method, options, contents) #:nodoc: # If there is no column for the method (eg "virtual columns" with an attr_accessor), the # default is a :string, a similar behaviour to Rails' scaffolding. # - def default_input_type(method) #:nodoc: + def default_input_type(method, options = {}) #:nodoc: if column = self.column_for(method) - # handle the special cases where the column type doesn't map to an input method + # Special cases where the column type doesn't map to an input method. return :time_zone if column.type == :string && method.to_s =~ /time_zone/ return :select if column.type == :integer && method.to_s =~ /_id$/ 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/ + + # Try look for hints in options hash. Quite common senario: Enum keys stored as string in the database. + return :select if column.type == :string && options.key?(:collection) - # otherwise assume the input name will be the same as the column type (eg string_input) + # Try 3: Assume the input name will be the same as the column type (e.g. string_input). return column.type else if @object - return :select if self.reflection_for(method) + return :select if self.reflection_for(method) file = @object.send(method) if @object.respond_to?(method) - return :file if file && @@file_methods.any? { |m| file.respond_to?(m) } + return :file if file && @@file_methods.any? { |m| file.respond_to?(m) } end - return :password if method.to_s =~ /password/ + return :select if options.key?(:collection) + return :password if method.to_s =~ /password/ return :string end end diff --git a/spec/inputs/select_input_spec.rb b/spec/inputs/select_input_spec.rb index 4a2bdae7d..4367188e2 100644 --- a/spec/inputs/select_input_spec.rb +++ b/spec/inputs/select_input_spec.rb @@ -393,4 +393,45 @@ end end + describe "enums" do + describe ":collection is set" do + before do + @output_buffer = '' + @some_meta_descriptions = ["One", "Two", "Three"] + @new_post.stub!(:meta_description).any_number_of_times + end + + describe ":as is not set" do + before do + semantic_form_for(@new_post) do |builder| + concat(builder.input(:meta_description, :collection => @some_meta_descriptions)) + end + semantic_form_for(:project, :url => 'http://test.host') do |builder| + concat(builder.input(:meta_description, :collection => @some_meta_descriptions)) + end + end + + it "should render a select field" do + output_buffer.should have_tag("form li select", :count => 2) + end + end + + describe ":as is set" do + before do + # Should not be a case, but just checking :as got highest priority in setting input type. + semantic_form_for(@new_post) do |builder| + concat(builder.input(:meta_description, :as => :string, :collection => @some_meta_descriptions)) + end + semantic_form_for(:project, :url => 'http://test.host') do |builder| + concat(builder.input(:meta_description, :as => :string, :collection => @some_meta_descriptions)) + end + end + + it "should render a text field" do + output_buffer.should have_tag("form li input[@type='text']", :count => 2) + end + end + end + end + end