Skip to content

Commit

Permalink
belongs_to associations will now render errors attached to the associ…
Browse files Browse the repository at this point in the history
…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
justinfrench committed Apr 22, 2010
1 parent f0d57ed commit 1bd9545
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 2 deletions.
18 changes: 16 additions & 2 deletions lib/formtastic.rb
Expand Up @@ -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
Expand Down Expand Up @@ -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
#
Expand Down
19 changes: 19 additions & 0 deletions spec/errors_spec.rb
Expand Up @@ -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

2 changes: 2 additions & 0 deletions spec/spec_helper.rb
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 1bd9545

Please sign in to comment.