From 1bd9545b6c19302c510ad443fded00942619c5cb Mon Sep 17 00:00:00 2001 From: Justin French Date: Wed, 21 Apr 2010 06:48:37 +1000 Subject: [PATCH] belongs_to associations will now render errors attached to the association and the column (fixes issue #161) * previously f.input(:section) would only look to errors[:section] * so anything in errors[:section_id] would not be displayed * some associations like validates_uniqueness_of need to be done on the column name * Formtastic will now also look at errors[:section_id] (or whatever the foreign key is named) * we squish all the errors together, make sure they're unique and display them all with the input --- lib/formtastic.rb | 18 ++++++++++++++++-- spec/errors_spec.rb | 19 +++++++++++++++++++ spec/spec_helper.rb | 2 ++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/lib/formtastic.rb b/lib/formtastic.rb index 0d6ef2d68..d1232096c 100644 --- a/lib/formtastic.rb +++ b/lib/formtastic.rb @@ -422,8 +422,10 @@ def label(method, options_or_text=nil, options=nil) # def inline_errors_for(method, options = nil) #:nodoc: if render_inline_errors? - errors = @object.errors[method.to_sym] - send(:"error_#{@@inline_errors}", [*errors]) if errors.present? + errors = [@object.errors[method.to_sym]] + errors << [@object.errors[association_primary_key(method)]] if association_macro_for_method(method) == :belongs_to + errors = errors.flatten.compact.uniq + send(:"error_#{@@inline_errors}", [*errors]) if errors.any? else nil end @@ -483,6 +485,18 @@ def association_columns(*by_associations) #:nodoc: [] end end + + # Returns nil, or a symbol like :belongs_to or :has_many + def association_macro_for_method(method) #:nodoc: + reflection = self.reflection_for(method) + reflection.macro if reflection + end + + def association_primary_key(method) + reflection = self.reflection_for(method) + reflection.options[:foreign_key] if reflection && !reflection.options[:foreign_key].blank? + :"#{method}_id" + end # Prepare options to be sent to label # diff --git a/spec/errors_spec.rb b/spec/errors_spec.rb index 5f1361c38..b7653324f 100644 --- a/spec/errors_spec.rb +++ b/spec/errors_spec.rb @@ -81,5 +81,24 @@ end end + + describe 'when there are errors on the association and column' do + + it "should list all unique errors" do + ::Formtastic::SemanticFormBuilder.inline_errors = :list + ::Post.stub!(:reflections).and_return({:author => mock('reflection', :options => {}, :macro => :belongs_to)}) + + @errors.stub!(:[]).with(:author).and_return(['must not be blank']) + @errors.stub!(:[]).with(:author_id).and_return(['is already taken', 'must not be blank']) # note the duplicate of association + + semantic_form_for(@new_post) do |builder| + concat(builder.input(:author)) + end + output_buffer.should have_tag("ul.errors li", /must not be blank/, :count => 1) + output_buffer.should have_tag("ul.errors li", /is already taken/, :count => 1) + end + + end + end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index b2f9d8988..33638f677 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -146,6 +146,7 @@ def new_author_path; "/authors/new"; end ::Post.stub!(:human_name).and_return('Post') ::Post.stub!(:reflect_on_all_validations).and_return([]) ::Post.stub!(:reflect_on_validations_for).and_return([]) + ::Post.stub!(:reflections).and_return({}) ::Post.stub!(:reflect_on_association).and_return do |column_name| case column_name when :author, :author_status @@ -180,6 +181,7 @@ def new_author_path; "/authors/new"; end @new_post.stub!(:column_for_attribute).with(:publish_at).and_return(mock('column', :type => :date)) @new_post.stub!(:column_for_attribute).with(:time_zone).and_return(mock('column', :type => :string)) @new_post.stub!(:column_for_attribute).with(:allow_comments).and_return(mock('column', :type => :boolean)) + @new_post.stub!(:column_for_attribute).with(:author).and_return(mock('column', :type => :integer)) @new_post.stub!(:author).and_return(@bob) @new_post.stub!(:author_id).and_return(@bob.id)