Skip to content

Commit

Permalink
Smarter detection of enum type columns (usually saved in string/varch…
Browse files Browse the repository at this point in the history
…ar fields); a select input will be the default if no :as option is set but :collection option is set. Closes #137.
  • Loading branch information
grimen authored and justinfrench committed Nov 30, 2009
1 parent dd95e9b commit 4a49e97
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 7 deletions.
18 changes: 11 additions & 7 deletions lib/formtastic.rb
Expand Up @@ -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?
Expand Down Expand Up @@ -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
Expand Down
41 changes: 41 additions & 0 deletions spec/inputs/select_input_spec.rb
Expand Up @@ -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

0 comments on commit 4a49e97

Please sign in to comment.