Module: EcsRails::Validations::Entity::ClassMethods

Defined in:
lib/ecs_rails/validations.rb

Overview

Class-level hooks. human_attribute_name is a class method, and ActiveModel::Error.full_message reaches it via base.class, so the override that decouples the human label from the error key has to live here rather than on the instance.

Instance Method Summary collapse

Instance Method Details

#ecs_component_reader?(reader) ⇒ Boolean

Is reader the name of a component reader on this entity?

Deliberately method_defined? and not the registry (components). The registry is a mutable process-wide singleton that the Railtie clears and repopulates on reload, and that sibling specs clear outright — so components can transiently be empty for a fully-composed entity. The generated reader is the durable artifact: the DSL defines it into an included module at declaration time, and it survives a registry clear (the same reason delegation keeps working across one). Since human_attribute_name is a hot method every form field hits, this is also the cheaper check.

It can only ever matter for a dotted key, and the only dotted keys the gem produces are component-namespaced error keys whose head is, by construction, a real reader — so the looseness (any instance method named reader would pass) is harmless.

Returns:

  • (Boolean)


86
87
88
# File 'lib/ecs_rails/validations.rb', line 86

def ecs_component_reader?(reader)
  method_defined?(reader)
end

#human_attribute_name(attribute, options = {}) ⇒ Object

Turns a component-namespaced error key into a readable label, so that the key and the full message can diverge (RFC-0007):

errors[:”email.address”] # machine-readable, namespaced by reader full_messages # => “Email address is invalid” (human)

ActiveModel couples these: full_message is “%human_attribute_name(attribute) %message”, and the stock human_attribute_name("email.address") rpartitions on the dot and returns just “Address” — giving “Address is invalid”, which drops the component entirely. Humanising the whole dotted key instead (“email.address” -> “email_address” -> “Email address”) keeps the component as a word and reads as one sentence, only the first word capitalised — which is exactly the RFC’s expected message and, notably, not “Email Address” (deferring to the component’s own human_attribute_name would capitalise both).

Guarded to component reader keys only, so this never hijacks an unrelated dotted attribute a host app might introduce.



60
61
62
63
64
65
66
67
68
# File 'lib/ecs_rails/validations.rb', line 60

def human_attribute_name(attribute, options = {})
  key = attribute.to_s
  reader, dot, rest = key.partition(".")

  return super if dot.empty? || rest.empty?
  return super unless ecs_component_reader?(reader)

  key.tr(".", "_").humanize
end