Permalink
Browse files

belongs_to associations will now render errors attached to the associ…

…ation 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
  • Loading branch information...
1 parent f0d57ed commit 1bd9545b6c19302c510ad443fded00942619c5cb @justinfrench committed Apr 20, 2010
Showing with 37 additions and 2 deletions.
  1. +16 −2 lib/formtastic.rb
  2. +19 −0 spec/errors_spec.rb
  3. +2 −0 spec/spec_helper.rb
View
@@ -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
#
View
@@ -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
View
@@ -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)

0 comments on commit 1bd9545

Please sign in to comment.