Class: State
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- State
- Defined in:
- app/models/state.rb
Overview
== Schema Information
Table name: states
Database name: primary
id :integer not null, primary key
code :string(255) not null
country_iso3 :string(255) not null
name :string(255) not null
region :string
Indexes
index_states_on_code_and_country_iso3 (code,country_iso3) UNIQUE
index_states_on_country_iso3 (country_iso3)
Constant Summary collapse
- MAIN_COUNTRIES_ISO3 =
Main countries iso3.
%w[USA CAN].freeze
- US_CONTINENTAL_STATE_LIST =
Us continental state list.
%w[AL AR AZ CA CO CT DC DE FL GA IA ID IL IN KS KY LA MA MD ME MI MN MO MS MT NC ND NE NH NJ NM NV NY OH OK OR PA RI SC SD TN TX UT VA VT WA WI WV WY].freeze
- CA_MAIN_PROVINCES =
Ca main provinces.
%w[AB BC MB NB NS ON QC SK].freeze
- CONTINENTAL_REGION_CODES =
Continental region codes.
[] + US_CONTINENTAL_STATE_LIST + CA_MAIN_PROVINCES
Constants included from Models::Schedulable
Models::Schedulable::SIMPLE_FORM_OPTIONS
Instance Attribute Summary collapse
- #code ⇒ String readonly
- #country_iso3 ⇒ String readonly
- #name ⇒ String readonly
Has many collapse
Belongs to collapse
Class Method Summary collapse
-
.by_country ⇒ ActiveRecord::Relation<State>
A relation of States that are by country.
-
.by_country_iso ⇒ ActiveRecord::Relation<State>
A relation of States that are by country iso.
-
.canada ⇒ ActiveRecord::Relation<State>
A relation of States that are canada.
-
.code_for_string(str, countries_iso3: MAIN_COUNTRIES_ISO3) ⇒ String?
Looks up the state code for the given state name string.
-
.normalize_subdivision_name(str) ⇒ String
Normalizes a state/province string for comparison.
-
.options_for_shipping_rates ⇒ Array<Array(String, String)>
Returns a list of state name/code pairs for all states except territories, sorted by region, for use in shipping rate options.
-
.sorted ⇒ ActiveRecord::Relation<State>
A relation of States that are sorted.
- .state_ids_for_select(countries_iso: nil, grouped_by_country: false, locale: nil) ⇒ Array<Array<String, Integer, nil>>, Hash{String => Array<Array<String, Integer, nil>>}
-
.states_for_select(countries_iso: nil, grouped_by_country: false, locale: nil) ⇒ Array<Array<String>>, Hash{String => Array<Array<String>>}
Returns a list of states grouped by country or ungrouped, filtered by the provided country ISO codes.
-
.usa ⇒ ActiveRecord::Relation<State>
A relation of States that are usa.
Instance Method Summary collapse
Methods inherited from ApplicationRecord
ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation
Methods included from Models::Schedulable
Methods included from Models::AfterCommittable
Methods included from Models::EventPublishable
Instance Attribute Details
#code ⇒ String (readonly)
45 |
# File 'app/models/state.rb', line 45 validates :code, uniqueness: { scope: :country_iso3 } |
#country_iso3 ⇒ String (readonly)
49 |
# File 'app/models/state.rb', line 49 validates :country_iso3, presence: true |
#name ⇒ String (readonly)
47 |
# File 'app/models/state.rb', line 47 validates :name, presence: true |
Class Method Details
.by_country ⇒ ActiveRecord::Relation<State>
A relation of States that are by country. Active Record Scope
41 |
# File 'app/models/state.rb', line 41 scope :by_country, ->(country_iso3) { where(country_iso3: country_iso3.upcase) } |
.by_country_iso ⇒ ActiveRecord::Relation<State>
A relation of States that are by country iso. Active Record Scope
42 |
# File 'app/models/state.rb', line 42 scope :by_country_iso, ->(country_iso) { joins(:country).where(countries: { iso: country_iso.upcase }) } |
.canada ⇒ ActiveRecord::Relation<State>
A relation of States that are canada. Active Record Scope
40 |
# File 'app/models/state.rb', line 40 scope :canada, -> { where(country_iso3: 'CAN') } |
.code_for_string(str, countries_iso3: MAIN_COUNTRIES_ISO3) ⇒ String?
Looks up the state code for the given state name string.
Searches through the given list of country ISO3 codes.
Returns nil if no match found.
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'app/models/state.rb', line 139 def self.code_for_string(str, countries_iso3: MAIN_COUNTRIES_ISO3) return nil if str.blank? subdivision_name = normalize_subdivision_name(str) code = nil countries_iso3.each do |iso3| next unless (c = ISO3166::Country.find_country_by_alpha3(iso3)) # This code finder is case sensitive so doing our own # code = c.find_subdivision_by_name(str)&.code code = c.subdivisions.find do |sub_code, sub| normalize_subdivision_name(sub_code) == subdivision_name || normalize_subdivision_name(sub.name) == subdivision_name || [sub.unofficial_names].flatten.compact.any? { |n| normalize_subdivision_name(n) == subdivision_name } end&.first break if code end # if no matches, try our internal table code ||= State.where(country_iso3: countries_iso3).where(State[:name].matches(subdivision_name, nil, false)).first&.code code end |
.normalize_subdivision_name(str) ⇒ String
Normalizes a state/province string for comparison.
Transliterates accents to ASCII BEFORE stripping punctuation. The strip
removes every character outside A-Z and whitespace, so on an accented
name it deletes the letter outright rather than folding it — "Québec"
became "QUBEC" and matched nothing, which blanked state_code and failed
Amazon.ca order import with "State code can't be blank". Applied to both
sides of the comparison so an accented ISO name matches an ASCII input too.
Input is coerced to valid UTF-8 first: I18n.transliterate matches with a
UTF-8 regexp, so a non-UTF-8 string (ISO-8859-1 from an EDI feed) raises
Encoding::CompatibilityError and malformed bytes raise ArgumentError.
The old ASCII-only strip tolerated both, and this runs inside order import,
so it must degrade rather than raise.
178 179 180 181 182 |
# File 'app/models/state.rb', line 178 def self.normalize_subdivision_name(str) value = str.to_s value = value.encode(Encoding::UTF_8, invalid: :replace, undef: :replace, replace: '') unless value.encoding == Encoding::UTF_8 I18n.transliterate(value.scrub('')).upcase.gsub(/[^A-Z\s]/, '').strip end |
.options_for_shipping_rates ⇒ Array<Array(String, String)>
Returns a list of state name/code pairs for all states except
territories, sorted by region, for use in shipping rate options.
126 127 128 129 130 131 |
# File 'app/models/state.rb', line 126 def self. # .insert(-1,%w[CONTINENTAL CONTINENTAL]) where.not(region: 'US - Territories').sort_by(&:region).to_a.map do |c| ["#{c.name} - #{c.region.split(' - ').second}", c.code] end end |
.sorted ⇒ ActiveRecord::Relation<State>
A relation of States that are sorted. Active Record Scope
38 |
# File 'app/models/state.rb', line 38 scope :sorted, -> { order(:name) } |
.state_ids_for_select(countries_iso: nil, grouped_by_country: false, locale: nil) ⇒ Array<Array<String, Integer, nil>>, Hash{String => Array<Array<String, Integer, nil>>}
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'app/models/state.rb', line 95 def self.state_ids_for_select(countries_iso: nil, grouped_by_country: false, locale: nil) locale ||= I18n.locale lang_code = locale.to_s.first(2) if countries_iso == :all grouped_by_country = true # force it otherwise makes no sense countries_iso = ISO3166::Country.codes elsif countries_iso.nil? countries_iso = %w[US CA] else countries_iso = [countries_iso].flatten.compact end grouped = {} ungrouped = countries_iso.flat_map do |iso| iso3166_country = if iso.size == 2 ISO3166::Country[iso] elsif iso.size == 3 ISO3166::Country.find_country_by_alpha3(iso) end next unless iso3166_country states_array = iso3166_country.subdivisions.map { |k, v| [v.translations[lang_code] || k, State.where(code: k).first&.id] } || [] grouped_country_name = iso3166_country.translations[lang_code] || iso3166_country.iso_short_name grouped[grouped_country_name] = states_array unless states_array.empty? states_array end grouped_by_country ? grouped : ungrouped end |
.states_for_select(countries_iso: nil, grouped_by_country: false, locale: nil) ⇒ Array<Array<String>>, Hash{String => Array<Array<String>>}
Returns a list of states grouped by country or ungrouped,
filtered by the provided country ISO codes.
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'app/models/state.rb', line 63 def self.states_for_select(countries_iso: nil, grouped_by_country: false, locale: nil) locale ||= I18n.locale lang_code = locale.to_s.first(2) if countries_iso == :all grouped_by_country = true # force it otherwise makes no sense countries_iso = ISO3166::Country.codes elsif countries_iso.nil? countries_iso = %w[US CA] else countries_iso = [countries_iso].flatten.compact end grouped = {} ungrouped = countries_iso.flat_map do |iso| iso3166_country = if iso.size == 2 ISO3166::Country[iso] elsif iso.size == 3 ISO3166::Country.find_country_by_alpha3(iso) end next unless iso3166_country states_array = iso3166_country.subdivisions.map { |k, v| [v.translations[lang_code] || k, k] } || [] grouped_country_name = iso3166_country.translations[lang_code] || iso3166_country.iso_short_name grouped[grouped_country_name] = states_array unless states_array.empty? states_array end grouped_by_country ? grouped : ungrouped end |
.usa ⇒ ActiveRecord::Relation<State>
A relation of States that are usa. Active Record Scope
39 |
# File 'app/models/state.rb', line 39 scope :usa, -> { where(country_iso3: 'USA') } |
Instance Method Details
#country ⇒ Country?
36 |
# File 'app/models/state.rb', line 36 belongs_to :country, foreign_key: 'country_iso3', primary_key: 'iso3', optional: true |
#tax_exemptions ⇒ ActiveRecord::Relation<TaxExemption>
31 |
# File 'app/models/state.rb', line 31 has_many :tax_exemptions, foreign_key: 'state_code', primary_key: 'code' |
#tax_rates ⇒ ActiveRecord::Relation<TaxRate>
33 |
# File 'app/models/state.rb', line 33 has_many :tax_rates, foreign_key: 'state_code', primary_key: 'code' |
#to_s ⇒ String
52 53 54 |
# File 'app/models/state.rb', line 52 def to_s name end |