Permalink
Browse files

Allow error_messages_for to report errors for multiple objects, as we…

…ll as support for customizing the name of the object in the error summary header. Closes #4186. [andrew@redlinesoftware.com, Marcel Molina Jr.]

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@4287 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
1 parent 8ee378f commit 43ee8ab6e2aa1efeb848885ed51f14709990cc08 Marcel Molina committed Apr 26, 2006
@@ -1,5 +1,9 @@
*SVN*
+* Allow error_messages_for to report errors for multiple objects, as well as support for customizing the name of the object in the error summary header. Closes #4186. [andrew@redlinesoftware.com, Marcel Molina Jr.]
+
+ error_messages_for :account, :user, :subscription, :object_name => :account
+
* Enhance documentation for setting headers in integration tests. Skip auto HTTP prepending when its already there. Closes #4079. [Rick Olson]
* Documentation for AbstractRequest. Closes #4895. [kevin.clark@gmail.com]
@@ -90,31 +90,45 @@ def error_message_on(object, method, prepend_text = "", append_text = "", css_cl
end
end
- # Returns a string with a div containing all the error messages for the object located as an instance variable by the name
- # of <tt>object_name</tt>. This div can be tailored by the following options:
+ # Returns a string with a div containing all of the error messages for the objects located as instance variables by the names
+ # given. If more than one object is specified, the errors for the objects are displayed in the order that the object names are
+ # provided.
+ #
+ # This div can be tailored by the following options:
#
# * <tt>header_tag</tt> - Used for the header of the error div (default: h2)
# * <tt>id</tt> - The id of the error div (default: errorExplanation)
# * <tt>class</tt> - The class of the error div (default: errorExplanation)
+ # * <tt>object_name</tt> - The object name to use in the header, or
+ # any text that you prefer. If <tt>object_name</tt> is not set, the name of
+ # the first object will be used.
+ #
+ # Specifying one object:
+ #
+ # error_messages_for 'user'
+ #
+ # Specifying more than one object (and using the name 'user' in the
+ # header as the <tt>object_name</tt> instead of 'user_common'):
+ #
+ # error_messages_for 'user_common', 'user', :object_name => 'user'
#
# NOTE: This is a pre-packaged presentation of the errors with embedded strings and a certain HTML structure. If what
# you need is significantly different from the default presentation, it makes plenty of sense to access the object.errors
# instance yourself and set it up. View the source of this method to see how easy it is.
- def error_messages_for(object_name, options = {})
- options = options.symbolize_keys
- object = instance_variable_get("@#{object_name}")
- if object && !object.errors.empty?
- content_tag("div",
- content_tag(
- options[:header_tag] || "h2",
- "#{pluralize(object.errors.count, "error")} prohibited this #{object_name.to_s.gsub("_", " ")} from being saved"
- ) +
- content_tag("p", "There were problems with the following fields:") +
- content_tag("ul", object.errors.full_messages.collect { |msg| content_tag("li", msg) }),
- "id" => options[:id] || "errorExplanation", "class" => options[:class] || "errorExplanation"
- )
+ def error_messages_for(*params)
+ options = params.last.is_a?(Hash) ? params.pop.symbolize_keys : {}
+ objects = params.collect {|object_name| instance_variable_get("@#{object_name}") }.compact
+ count = objects.inject(0) {|sum, object| sum + object.errors.count }
+ unless count.zero?
+ header_message = "#{pluralize(count, 'error')} prohibited this #{(options[:object_name] || params.first).to_s.gsub('_', ' ')} from being saved"
+ error_messages = objects.map {|object| object.errors.full_messages.map {|msg| content_tag(:li, msg) } }
+ content_tag(:div,
+ content_tag(options[:header_tag] || :h2, header_message) <<
+ content_tag(:p, 'There were problems with the following fields:') <<
+ content_tag(:ul, error_messages),
+ :id => options[:id] || 'errorExplanation', :class => options[:class] || 'errorExplanation')
else
- ""
+ ''
end
end
@@ -22,10 +22,16 @@ class ActiveRecordHelperTest < Test::Unit::TestCase
alias_method :body_before_type_cast, :body unless respond_to?(:body_before_type_cast)
alias_method :author_name_before_type_cast, :author_name unless respond_to?(:author_name_before_type_cast)
end
+
+ User = Struct.new("User", :email)
+ User.class_eval do
+ alias_method :email_before_type_cast, :email unless respond_to?(:email_before_type_cast)
+ end
+
Column = Struct.new("Column", :type, :name, :human_name)
end
- def setup
+ def setup_post
@post = Post.new
def @post.errors
Class.new {
@@ -50,6 +56,34 @@ def Post.content_columns() [ Column.new(:string, "title", "Title"), Column.new(:
@post.body = "Back to the hill and over it again!"
@post.secret = 1
@post.written_on = Date.new(2004, 6, 15)
+ end
+
+ def setup_user
+ @user = User.new
+ def @user.errors
+ Class.new {
+ def on(field) field == "email" end
+ def empty?() false end
+ def count() 1 end
+ def full_messages() [ "User email can't be empty" ] end
+ }.new
+ end
+
+ def @user.new_record?() true end
+ def @user.to_param() nil end
+
+ def @user.column_for_attribute(attr_name)
+ User.content_columns.select { |column| column.name == attr_name }.first
+ end
+
+ def User.content_columns() [ Column.new(:string, "email", "Email") ] end
+
+ @user.email = ""
+ end
+
+ def setup
+ setup_post
+ setup_user
@controller = Object.new
def @controller.url_for(options, *parameters_for_method_reference)
@@ -124,6 +158,22 @@ def test_error_messages_for_handles_nil
assert_equal "", error_messages_for("notthere")
end
+ def test_error_messages_for_many_objects
+ assert_dom_equal %(<div class="errorExplanation" id="errorExplanation"><h2>2 errors prohibited this post from being saved</h2><p>There were problems with the following fields:</p><ul><li>Author name can't be empty</li><li>User email can't be empty</li></ul></div>), error_messages_for("post", "user")
+
+ # reverse the order, error order changes and so does the title
+ assert_dom_equal %(<div class="errorExplanation" id="errorExplanation"><h2>2 errors prohibited this user from being saved</h2><p>There were problems with the following fields:</p><ul><li>User email can't be empty</li><li>Author name can't be empty</li></ul></div>), error_messages_for("user", "post")
+
+ # add the default to put post back in the title
+ assert_dom_equal %(<div class="errorExplanation" id="errorExplanation"><h2>2 errors prohibited this post from being saved</h2><p>There were problems with the following fields:</p><ul><li>User email can't be empty</li><li>Author name can't be empty</li></ul></div>), error_messages_for("user", "post", :object_name => "post")
+
+ # symbols work as well
+ assert_dom_equal %(<div class="errorExplanation" id="errorExplanation"><h2>2 errors prohibited this post from being saved</h2><p>There were problems with the following fields:</p><ul><li>User email can't be empty</li><li>Author name can't be empty</li></ul></div>), error_messages_for(:user, :post, :object_name => :post)
+
+ # any default works too
+ assert_dom_equal %(<div class="errorExplanation" id="errorExplanation"><h2>2 errors prohibited this monkey from being saved</h2><p>There were problems with the following fields:</p><ul><li>User email can't be empty</li><li>Author name can't be empty</li></ul></div>), error_messages_for(:user, :post, :object_name => "monkey")
+ end
+
def test_form_with_string_multipart
assert_dom_equal(
%(<form action="create" enctype="multipart/form-data" method="post"><p><label for="post_title">Title</label><br /><input id="post_title" name="post[title]" size="30" type="text" value="Hello World" /></p>\n<p><label for="post_body">Body</label><br /><div class="fieldWithErrors"><textarea cols="40" id="post_body" name="post[body]" rows="20">Back to the hill and over it again!</textarea></div></p><input name="commit" type="submit" value="Create" /></form>),

0 comments on commit 43ee8ab

Please sign in to comment.