Neil
Neil

Reputation: 5178

How field_with_errors div Gets Added in a Form When Validations Fail Within fields_for

It is clear to me that when a validation fails in a form: what happens is the errors hash associated to your object gains a new key which is magically mapped to that object's invalid attribute. That key's value is the relevant error message for that invalidation.

The above is all explained nicely in the Working with Validation Errors Rails Guide

This next part is what does not make sense to me. Magically: rails appears to somehow look at the keys in your errors hash, map those to the appropriate form labels and inputs, and then wraps those invalid form labels and inputs with a <div class="field_with_errors"> ... </div>.

I am trying to figure out how that magic works.

To be more specific: I am wondering how rails is able to map the field_with_errors appropriately when there are fields_for present in a form for a has_many association.

Example: Say I have the following associations:

# models/user.rb
class User < ApplicationRecord
  has_many :user_emails
end

# models/user_email.rb
class UserEmail < ApplicationRecord
  belongs_to :user
  validates_presence_of :email_text
end

I then have a userform that has fields_for for 5 different nested user_email records. Let us say two of those user_emails are invalid:

How does rails do this? I cannot find the documentation on this, or find any resources online in regards to the magic that is going on behind the scenes.

Upvotes: 1

Views: 540

Answers (1)

anothermh
anothermh

Reputation: 10536

The objects are passed through the field_error_proc one by one, so each is UserEmail is evaluated separately. The default proc specification is defined here: https://github.com/rails/rails/blob/7da8d76206271bdf200ea201f7e5a49afb9bc9e7/actionview/lib/action_view/base.rb#L144 as:

@@field_error_proc = Proc.new { |html_tag, instance| "<div class=\"field_with_errors\">#{html_tag}</div>".html_safe }

This is called by ActiveModelInstanceTag: https://github.com/rails/rails/blob/92703a9ea5d8b96f30e0b706b801c9185ef14f0e/actionview/lib/action_view/helpers/active_model_helper.rb#L28 with:

Base.field_error_proc.call(html_tag, self)

Note that self here refers to an individual UserEmail object being evaluated. More information on this proc is available at https://github.com/rails/rails/blob/09436fb6d6d188739b40ef120b4344106d81caf9/guides/source/configuring.md#configuring-action-view and at https://github.com/rails/rails/blob/7c3a99eeca07f602bb1e5659656e8eab0a4eacfe/guides/source/active_support_core_extensions.md#cattr_reader-cattr_writer-and-cattr_accessor.

There's no magic at work; it evaluates all the models.

Upvotes: 3

Related Questions