Module: ConcernsOnRails::Models::Addressable
- Extended by:
- ActiveSupport::Concern
- Defined in:
- lib/concerns_on_rails/models/addressable.rb
Overview
Declarative normalization + format validation for a postal address spread across several columns. One macro wires up whitespace cleanup, postal-code and ISO country-code checks, required-part presence, and a ‘full_address` helper — no external geocoding service required.
class Location < ApplicationRecord
include ConcernsOnRails::Addressable
addressable_by # standard line1/line2/city/state/postal_code/country columns
# addressable_by line1: :street, postal_code: :zip, country: :country_code,
# required: %i[line1 city postal_code], default_country: "GB",
# validate_state: true, verify_with: ->(rec) { Usps.verify(rec) }
end
Scope is format/structure only — it checks shape, not real-world deliverability. Layer a real verifier on via ‘verify_with:`. Relates to the per-field Normalizable concern.
Defined Under Namespace
Modules: ClassMethods
Constant Summary collapse
- DEFAULT_FIELDS =
Canonical address part => default column name.
{ line1: :line1, line2: :line2, city: :city, state: :state, postal_code: :postal_code, country: :country }.freeze
- DEFAULT_REQUIRED =
Parts required by default (each must map to an existing column).
%i[line1 city postal_code country].freeze
Instance Method Summary collapse
-
#address_attributes ⇒ Object
‘{ part => value }` for the present parts (handy for serializers / verifiers).
-
#address_complete? ⇒ Boolean
True when every required part has a value (presence only, no format check).
-
#address_lines ⇒ Object
The present parts as an ordered array (handy for multi-line rendering).
-
#address_present? ⇒ Boolean
True when any configured part has a value.
-
#full_address(separator: ", ") ⇒ Object
The present parts joined into a single line, in canonical order.
-
#normalize_address ⇒ Object
— Normalization (before_validation) ————————————.
-
#validate_address ⇒ Object
— Validation ———————————————————–.
Instance Method Details
#address_attributes ⇒ Object
‘{ part => value }` for the present parts (handy for serializers / verifiers).
131 132 133 134 135 136 |
# File 'lib/concerns_on_rails/models/addressable.rb', line 131 def address_attributes self.class.addressable_fields.each_with_object({}) do |(part, column), acc| value = self[column] acc[part] = value if value.present? end end |
#address_complete? ⇒ Boolean
True when every required part has a value (presence only, no format check).
124 125 126 127 128 |
# File 'lib/concerns_on_rails/models/addressable.rb', line 124 def address_complete? self.class.addressable_required.all? do |part| (column = self.class.addressable_fields[part]) && self[column].present? end end |
#address_lines ⇒ Object
The present parts as an ordered array (handy for multi-line rendering).
114 115 116 |
# File 'lib/concerns_on_rails/models/addressable.rb', line 114 def address_lines ordered_parts.filter_map { |part| self[self.class.addressable_fields[part]].presence } end |
#address_present? ⇒ Boolean
True when any configured part has a value.
119 120 121 |
# File 'lib/concerns_on_rails/models/addressable.rb', line 119 def address_present? ordered_parts.any? { |part| self[self.class.addressable_fields[part]].present? } end |
#full_address(separator: ", ") ⇒ Object
The present parts joined into a single line, in canonical order.
109 110 111 |
# File 'lib/concerns_on_rails/models/addressable.rb', line 109 def full_address(separator: ", ") address_lines.join(separator) end |
#normalize_address ⇒ Object
— Normalization (before_validation) ————————————
86 87 88 89 90 91 92 93 94 |
# File 'lib/concerns_on_rails/models/addressable.rb', line 86 def normalize_address country = resolved_country self.class.addressable_fields.each do |part, column| value = self[column] next unless value.is_a?(String) self[column] = normalize_part(part, country, value) end end |
#validate_address ⇒ Object
— Validation ———————————————————–
98 99 100 101 102 103 104 |
# File 'lib/concerns_on_rails/models/addressable.rb', line 98 def validate_address validate_required_parts validate_country_code validate_postal_code validate_state_code if self.class.addressable_validate_state run_address_verifier if self.class.addressable_verifier && errors.empty? end |