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) },
# lengths: { line1: 100, postal_code: 5..10 }, allow_blank: %i[state],
# normalize_country: true, # "Canada"/"CAN" -> "CA"
# if: :on_addresses? # Rails-style condition gating the validations
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
- LABEL =
Prefix for the ArgumentErrors raised during configuration.
"ConcernsOnRails::Models::Addressable".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).
226 227 228 229 230 231 |
# File 'lib/concerns_on_rails/models/addressable.rb', line 226 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).
219 220 221 222 223 |
# File 'lib/concerns_on_rails/models/addressable.rb', line 219 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).
209 210 211 |
# File 'lib/concerns_on_rails/models/addressable.rb', line 209 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.
214 215 216 |
# File 'lib/concerns_on_rails/models/addressable.rb', line 214 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.
204 205 206 |
# File 'lib/concerns_on_rails/models/addressable.rb', line 204 def full_address(separator: ", ") address_lines.join(separator) end |
#normalize_address ⇒ Object
— Normalization (before_validation) ————————————
180 181 182 183 184 185 186 187 188 |
# File 'lib/concerns_on_rails/models/addressable.rb', line 180 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 ———————————————————–
192 193 194 195 196 197 198 199 |
# File 'lib/concerns_on_rails/models/addressable.rb', line 192 def validate_address validate_required_parts validate_lengths 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 |