Skip to content
This repository
Browse code

Merge remote-tracking branch 'okonski/range_helper' into refactor. Give

numeric functionality for inputs and ValidationHelper#range_options_for.

Conflicts:
	lib/formtastic/form_builder.rb
	lib/formtastic/inputs/numeric_input.rb
  • Loading branch information...
commit d32f348e5b6ab8c7f1702439345ec98226349d46 2 parents 368d878 + 60c6b3f
Jakub Okoński farnoy authored
3  README.textile
Source Rendered
@@ -305,7 +305,7 @@ The Formtastic input types:
305 305 * @:time@ - a time select. Default for column types: @:time@.
306 306 * @:boolean@ - a checkbox. Default for column types: @:boolean@.
307 307 * @:string@ - a text field. Default for column types: @:string@.
308   -* @:numeric@ - a text field (just like string). Default for column types: @:integer@, @:float@, and @:decimal@.
  308 +* @:numeric@ - a text field (just like string). Default for column types: @:integer@, @:float@, and @:decimal@. Handles range validations.
309 309 * @:file@ - a file field. Default for file-attachment attributes matching: "paperclip":http://github.com/thoughtbot/paperclip or "attachment_fu":http://github.com/technoweenie/attachment_fu.
310 310 * @:country@ - a select menu of country names. Default for column types: :string with name @"country"@ - requires a *country_select* plugin to be installed.
311 311 * @:email@ - a text field (just like string). Default for columns with name matching @"email"@. New in HTML5. Works on some mobile browsers already.
@@ -313,6 +313,7 @@ The Formtastic input types:
313 313 * @:phone@ - a text field (just like string). Default for columns with name matching @"phone"@ or @"fax"@. New in HTML5.
314 314 * @:search@ - a text field (just like string). Default for columns with name matching @"search"@. New in HTML5. Works on Safari.
315 315 * @:hidden@ - a hidden field. Creates a hidden field (added for compatibility).
  316 +* @:range@ - a slider field. Handles range validations.
316 317
317 318 The comments in the code are pretty good for each of these (what it does, what the output is, what the options are, etc.) so go check it out.
318 319
34 lib/formtastic/form_builder.rb
... ... @@ -1,3 +1,37 @@
  1 +<<<<<<< HEAD
  2 +=======
  3 +$LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__))))
  4 +
  5 +require 'html_attributes'
  6 +
  7 +require 'helpers/inputs_helper'
  8 +require 'helpers/buttons_helper'
  9 +require 'helpers/label_helper'
  10 +require 'helpers/errors_helper'
  11 +require 'helpers/validation_helper'
  12 +
  13 +require 'inputs/boolean_input'
  14 +require 'inputs/check_boxes_input'
  15 +require 'inputs/country_input'
  16 +require 'inputs/datetime_input'
  17 +require 'inputs/date_input'
  18 +require 'inputs/email_input'
  19 +require 'inputs/file_input'
  20 +require 'inputs/hidden_input'
  21 +require 'inputs/numeric_input'
  22 +require 'inputs/password_input'
  23 +require 'inputs/phone_input'
  24 +require 'inputs/radio_input'
  25 +require 'inputs/range_input'
  26 +require 'inputs/search_input'
  27 +require 'inputs/select_input'
  28 +require 'inputs/string_input'
  29 +require 'inputs/text_input'
  30 +require 'inputs/time_input'
  31 +require 'inputs/time_zone_input'
  32 +require 'inputs/url_input'
  33 +
  34 +>>>>>>> okonski/range_helper
1 35 module Formtastic
2 36 class FormBuilder < ActionView::Helpers::FormBuilder
3 37
39 lib/formtastic/helpers/validation_helper.rb
... ... @@ -0,0 +1,39 @@
  1 +module Formtastic
  2 + module Helpers
  3 + module ValidationHelper
  4 +
  5 + def range_options_for(method, options = {})
  6 + options[:input_html] ||= {}
  7 + if options[:in]
  8 + options[:input_html][:in] = options.delete :in
  9 + options[:input_html][:step] = options.delete :step || 1
  10 + return options
  11 + end
  12 +
  13 + reflections = @object.class.reflect_on_validations_for(method) if @object.class.respond_to? :reflect_on_validations_for
  14 + reflections ||= []
  15 + reflections.each do |reflection|
  16 + if reflection.macro == :validates_numericality_of
  17 + if reflection.options.include?(:greater_than)
  18 + range_start = (reflection.options[:greater_than] + 1)
  19 + elsif reflection.options.include?(:greater_than_or_equal_to)
  20 + range_start = reflection.options[:greater_than_or_equal_to]
  21 + end
  22 + if reflection.options.include?(:less_than)
  23 + range_end = (reflection.options[:less_than] - 1)
  24 + elsif reflection.options.include?(:less_than_or_equal_to)
  25 + range_end = reflection.options[:less_than_or_equal_to]
  26 + end
  27 +
  28 + options[:input_html][:in] = (range_start..range_end)
  29 + end
  30 + end
  31 +
  32 + options[:input_html][:step] ||= 1
  33 +
  34 + return options
  35 + end
  36 +
  37 + end
  38 + end
  39 +end
9 lib/formtastic/inputs/numeric_input.rb
... ... @@ -1,3 +1,5 @@
  1 +require 'inputs/basic'
  2 +
1 3 module Formtastic
2 4 module Inputs
3 5
@@ -39,6 +41,11 @@ def to_html
39 41 builder.number_field(method, input_html_options)
40 42 end
41 43 end
  44 +
  45 + # Outputs a label and standard Rails text field inside the wrapper.
  46 + def numeric_input(method, options)
  47 + basic_input_helper(:number_field, :numeric, method, range_options_for(method, options))
  48 + end
42 49 end
43 50 end
44   -end
  51 +end
12 lib/formtastic/inputs/range_input.rb
... ... @@ -0,0 +1,12 @@
  1 +module Formtastic
  2 + module Inputs
  3 + module RangeInput
  4 + include Formtastic::Inputs::Base
  5 +
  6 + def range_input(method, options)
  7 + basic_input_helper(:range_field, :numeric, method, range_options_for(method, options))
  8 + end
  9 +
  10 + end
  11 + end
  12 +end
88 spec/inputs/range_input_spec.rb
... ... @@ -0,0 +1,88 @@
  1 +# encoding: utf-8
  2 +require 'spec_helper'
  3 +require 'active_record'
  4 +
  5 +describe 'range input' do
  6 +
  7 + include FormtasticSpecHelper
  8 +
  9 + before do
  10 + @output_buffer = ''
  11 + mock_everything
  12 + end
  13 +
  14 + describe "when object is provided" do
  15 + before do
  16 + concat(semantic_form_for(@bob) do |builder|
  17 + concat(builder.input(:age, :as => :range))
  18 + end)
  19 + end
  20 +
  21 + it_should_have_input_wrapper_with_class(:range)
  22 + it_should_have_input_wrapper_with_id("author_age_input")
  23 + it_should_have_label_with_text(/Age/)
  24 + it_should_have_label_for("author_age")
  25 + it_should_have_input_with_id("author_age")
  26 + it_should_have_input_with_type(:range)
  27 + it_should_have_input_with_name("author[age]")
  28 +
  29 + end
  30 +
  31 + describe "when namespace is provided" do
  32 +
  33 + before do
  34 + concat(semantic_form_for(@james, :namespace => "context2") do |builder|
  35 + concat(builder.input(:age, :as => :range))
  36 + end)
  37 + end
  38 +
  39 + it_should_have_input_wrapper_with_id("context2_author_age_input")
  40 + it_should_have_label_and_input_with_id("context2_author_age")
  41 +
  42 + end
  43 +
  44 + describe "core processing" do
  45 +
  46 + before { mock_everything; @options = {} }
  47 +
  48 + describe "with validation_reflection" do
  49 +
  50 + before do
  51 + # Insane, but we need to test with and without validation_reflection
  52 + ::Author.stub!(:reflect_on_validations_for).with(:age).and_return([ActiveRecord::Reflection::MacroReflection.new(:validates_numericality_of, :age, {:greater_than => 0, :less_than => 6}, ::Author)])
  53 + end
  54 +
  55 + it "works with alternate validation options" do
  56 + ::Author.stub!(:reflect_on_validations_for).with(:age).and_return([ActiveRecord::Reflection::MacroReflection.new(:validates_numericality_of, :age, {:greater_than_or_equal_to => 1930, :less_than_or_equal_to => (Time.now.year - 5)}, ::Author)])
  57 +
  58 + concat(semantic_form_for(@james) do |builder|
  59 + concat(builder.input(:age, @options.merge(:as => :range)))
  60 + end)
  61 +
  62 + output_buffer.should have_tag("form li input[step=\"1\"][min=\"1930\"][max=\"#{Time.now.year - 5}\"]")
  63 + end
  64 +
  65 + it "assigns range and step from model" do
  66 + concat(semantic_form_for(@james) do |builder|
  67 + concat(builder.input(:age, @options.merge(:as => :range)))
  68 + end)
  69 +
  70 + output_buffer.should have_tag("form li input[step=\"1\"][min=\"1\"][max=\"5\"]")
  71 + end
  72 +
  73 + it "allows for overriding range and step values" do
  74 + @options.merge! :in => 9..10, :step => 0.2
  75 +
  76 + concat(semantic_form_for(@james) do |builder|
  77 + concat(builder.input(:age, @options.merge(:as => :range)))
  78 + end)
  79 +
  80 + output_buffer.should have_tag("form li input[step=\"0.2\"][min=\"9\"][max=\"10\"]")
  81 + end
  82 +
  83 + end
  84 +
  85 + end
  86 +
  87 +end
  88 +
3  spec/spec_helper.rb
@@ -121,6 +121,7 @@ def new_author_path; "/authors/new"; end
121 121 @fred.stub!(:class).and_return(::Author)
122 122 @fred.stub!(:to_label).and_return('Fred Smith')
123 123 @fred.stub!(:login).and_return('fred_smith')
  124 + @fred.stub!(:age).and_return(27)
124 125 @fred.stub!(:id).and_return(37)
125 126 @fred.stub!(:new_record?).and_return(false)
126 127 @fred.stub!(:errors).and_return(mock('errors', :[] => nil))
@@ -130,6 +131,7 @@ def new_author_path; "/authors/new"; end
130 131 @bob = ::Author.new
131 132 @bob.stub!(:to_label).and_return('Bob Rock')
132 133 @bob.stub!(:login).and_return('bob')
  134 + @bob.stub!(:age).and_return(43)
133 135 @bob.stub!(:created_at)
134 136 @bob.stub!(:id).and_return(42)
135 137 @bob.stub!(:posts).and_return([])
@@ -142,6 +144,7 @@ def new_author_path; "/authors/new"; end
142 144 @james = ::Author.new
143 145 @james.stub!(:to_label).and_return('James Shock')
144 146 @james.stub!(:login).and_return('james')
  147 + @james.stub!(:age).and_return(38)
145 148 @james.stub!(:id).and_return(75)
146 149 @james.stub!(:posts).and_return([])
147 150 @james.stub!(:post_ids).and_return([])

0 comments on commit d32f348

Please sign in to comment.
Something went wrong with that request. Please try again.