Reputation: 5178
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 user
form that has fields_for
for 5 different nested user_email
records. Let us say two of those user_emails
are invalid:
fields_with_errors
div only gets applied to those two invalid user_email
records as opposed to ALL of the user_email
records in the form. 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
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