diff --git a/Appraisals b/Appraisals index e710b8a46..84b869c52 100644 --- a/Appraisals +++ b/Appraisals @@ -9,3 +9,7 @@ end appraise 'rails-3.2' do gem 'rails', '~> 3.2.0' end + +appraise 'rails-4' do + gem 'rails', :git => 'git://github.com/rails/rails.git' +end diff --git a/README.textile b/README.textile index 71101707f..6bf709560 100644 --- a/README.textile +++ b/README.textile @@ -329,6 +329,7 @@ Many inputs provide a collection of options to choose from (like @:select@, @:ra f.input :author, :as => :radio, :collection => { @justin.name => @justin.id, @kate.name => @kate.id } f.input :author, :as => :radio, :collection => ["Justin", "Kate", "Amelia", "Gus", "Meg"] f.input :admin, :as => :radio, :collection => ["Yes!", "No"] + f.input :book_id, :as => :select, :collection => Hash[Book.all.map{|b| [b.name,b.id]}] diff --git a/formtastic.gemspec b/formtastic.gemspec index 057ba9cdd..ee52bffad 100644 --- a/formtastic.gemspec +++ b/formtastic.gemspec @@ -23,7 +23,7 @@ Gem::Specification.new do |s| s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.rubygems_version = %q{1.3.6} - s.add_dependency(%q, ["~> 3.0"]) + s.add_dependency(%q, [">= 3.0"]) s.add_development_dependency(%q, ["~> 2.8.0"]) s.add_development_dependency(%q, [">= 1.0.0"]) diff --git a/gemfiles/rails-4.gemfile b/gemfiles/rails-4.gemfile new file mode 100644 index 000000000..9ead4a5e8 --- /dev/null +++ b/gemfiles/rails-4.gemfile @@ -0,0 +1,7 @@ +# This file was generated by Appraisal + +source :rubygems + +gem "rails", :git=>"git://github.com/rails/rails.git" + +gemspec :path=>"../" \ No newline at end of file diff --git a/lib/formtastic/inputs/boolean_input.rb b/lib/formtastic/inputs/boolean_input.rb index 5d27a335a..91f3e2cd9 100644 --- a/lib/formtastic/inputs/boolean_input.rb +++ b/lib/formtastic/inputs/boolean_input.rb @@ -97,9 +97,32 @@ def input_html_options_name end def checked? - object && ActionView::Helpers::InstanceTag.check_box_checked?(object.send(method), checked_value) + if defined? ActionView::Helpers::InstanceTag + object && ActionView::Helpers::InstanceTag.check_box_checked?(object.send(method), checked_value) + else + object && boolean_checked?(object.send(method), checked_value) + end end + + private + def boolean_checked?(value, checked_value) + case value + when TrueClass, FalseClass + value + when NilClass + false + when Integer + value != 0 + when String + value == checked_value + when Array + value.include?(checked_value) + else + value.to_i != 0 + end + end + end end end diff --git a/lib/formtastic/inputs/select_input.rb b/lib/formtastic/inputs/select_input.rb index d7c59d02e..7397e26df 100644 --- a/lib/formtastic/inputs/select_input.rb +++ b/lib/formtastic/inputs/select_input.rb @@ -195,7 +195,7 @@ def input_options end def input_html_options - extra_input_html_options.merge(super) + extra_input_html_options.merge(super.reject {|k,v| k==:name && v.nil?} ) end def extra_input_html_options diff --git a/spec/builder/semantic_fields_for_spec.rb b/spec/builder/semantic_fields_for_spec.rb index 3bae0489a..59cb731b1 100644 --- a/spec/builder/semantic_fields_for_spec.rb +++ b/spec/builder/semantic_fields_for_spec.rb @@ -101,7 +101,7 @@ it 'should render errors on the nested inputs' do @errors = mock('errors') - @errors.stub!(:[]).with(:login).and_return(['oh noes']) + @errors.stub!(:[]).with(errors_matcher(:login)).and_return(['oh noes']) @bob.stub!(:errors).and_return(@errors) concat(semantic_form_for(@new_post, :namespace => 'context2') do |builder| diff --git a/spec/helpers/semantic_errors_helper_spec.rb b/spec/helpers/semantic_errors_helper_spec.rb index a14d50fa6..364260ec1 100644 --- a/spec/helpers/semantic_errors_helper_spec.rb +++ b/spec/helpers/semantic_errors_helper_spec.rb @@ -17,7 +17,7 @@ describe 'when there is only one error on base' do before do - @errors.stub!(:[]).with(:base).and_return(@base_error) + @errors.stub!(:[]).with(errors_matcher(:base)).and_return(@base_error) end it 'should render an unordered list' do @@ -29,7 +29,7 @@ describe 'when there is more than one error on base' do before do - @errors.stub!(:[]).with(:base).and_return(@base_errors) + @errors.stub!(:[]).with(errors_matcher(:base)).and_return(@base_errors) end it 'should render an unordered list' do @@ -44,8 +44,8 @@ describe 'when there are errors on title' do before do - @errors.stub!(:[]).with(:title).and_return(@title_errors) - @errors.stub!(:[]).with(:base).and_return([]) + @errors.stub!(:[]).with(errors_matcher(:title)).and_return(@title_errors) + @errors.stub!(:[]).with(errors_matcher(:base)).and_return([]) end it 'should render an unordered list' do @@ -58,8 +58,8 @@ describe 'when there are errors on title and base' do before do - @errors.stub!(:[]).with(:title).and_return(@title_errors) - @errors.stub!(:[]).with(:base).and_return(@base_error) + @errors.stub!(:[]).with(errors_matcher(:title)).and_return(@title_errors) + @errors.stub!(:[]).with(errors_matcher(:base)).and_return(@base_error) end it 'should render an unordered list' do @@ -73,8 +73,8 @@ describe 'when there are no errors' do before do - @errors.stub!(:[]).with(:title).and_return(nil) - @errors.stub!(:[]).with(:base).and_return(nil) + @errors.stub!(:[]).with(errors_matcher(:title)).and_return(nil) + @errors.stub!(:[]).with(errors_matcher(:base)).and_return(nil) end it 'should return nil' do @@ -86,7 +86,7 @@ describe 'when there is one error on base and options with class is passed' do before do - @errors.stub!(:[]).with(:base).and_return(@base_error) + @errors.stub!(:[]).with(errors_matcher(:base)).and_return(@base_error) end it 'should render an unordered list with given class' do @@ -98,7 +98,7 @@ describe 'when :base is passed in as an argument' do before do - @errors.stub!(:[]).with(:base).and_return(@base_error) + @errors.stub!(:[]).with(errors_matcher(:base)).and_return(@base_error) end it 'should ignore :base and only render base errors once' do diff --git a/spec/inputs/custom_input_spec.rb b/spec/inputs/custom_input_spec.rb index 1ad9ff202..f1fe3b61d 100644 --- a/spec/inputs/custom_input_spec.rb +++ b/spec/inputs/custom_input_spec.rb @@ -11,8 +11,11 @@ def input_args @method = :title @options = {} @proc = Proc.new {} - @builder = Formtastic::FormBuilder.new(@object_name, @object, @template, @options, @proc) - + if Rails::VERSION::MAJOR == 4 + @builder = Formtastic::FormBuilder.new(@object_name, @object, @template, @options) + else + @builder = Formtastic::FormBuilder.new(@object_name, @object, @template, @options, @proc) + end [@builder, @template, @object, @object_name, @method, @options] end diff --git a/spec/inputs/hidden_input_spec.rb b/spec/inputs/hidden_input_spec.rb index 24d796cc4..c7eb248a4 100644 --- a/spec/inputs/hidden_input_spec.rb +++ b/spec/inputs/hidden_input_spec.rb @@ -52,7 +52,7 @@ it "should not render inline errors" do @errors = mock('errors') - @errors.stub!(:[]).with(:secret).and_return(["foo", "bah"]) + @errors.stub!(:[]).with(errors_matcher(:secret)).and_return(["foo", "bah"]) @new_post.stub!(:errors).and_return(@errors) concat(semantic_form_for(@new_post) do |builder| diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index f0d8951c2..9e92ec790 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -413,7 +413,31 @@ def with_config(config_method_name, value, &block) yield Formtastic::FormBuilder.send(:"#{config_method_name}=", old_value) end - + + class ToSMatcher + def initialize(str) + @str=str.to_s + end + + def matches?(value) + value.to_s==@str + end + + def failure_message_for_should + "Expected argument that converted to #{@str}" + end + end + + def errors_matcher(method) + # In edge rails (Rails 4) tags store method_name as a string and index the errors object using a string + # therefore allow stubs to match on either string or symbol. The errors object calls to_sym on all index + # accesses so @object.errors[:abc] is equivalent to @object.errors["abc"] + if Rails::VERSION::MAJOR == 4 + ToSMatcher.new(method) + else + method + end + end end ::ActiveSupport::Deprecation.silenced = false diff --git a/spec/support/custom_macros.rb b/spec/support/custom_macros.rb index 137b720a9..5795af0f0 100644 --- a/spec/support/custom_macros.rb +++ b/spec/support/custom_macros.rb @@ -177,9 +177,9 @@ def it_should_apply_error_logic_for_input_type(type) before do @title_errors = ['must not be blank', 'must be longer than 10 characters', 'must be awesome'] @errors = mock('errors') - @errors.stub!(:[]).with(:title).and_return(@title_errors) + @errors.stub!(:[]).with(errors_matcher(:title)).and_return(@title_errors) Formtastic::FormBuilder.file_metadata_suffixes.each do |suffix| - @errors.stub!(:[]).with("title_#{suffix}".to_sym).and_return(nil) + @errors.stub!(:[]).with(errors_matcher("title_#{suffix}".to_sym)).and_return(nil) end @new_post.stub!(:errors).and_return(@errors) end