address_concern 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.gitignore +8 -0
- data/.rspec +1 -0
- data/.ruby-version +1 -0
- data/CHANGELOG +3 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +21 -0
- data/Rakefile +19 -0
- data/Readme.md +231 -0
- data/VERSION +1 -0
- data/address_concern.gemspec +33 -0
- data/bin/console +12 -0
- data/config/locale/overlay/en/id.yml +8 -0
- data/lib/address_concern/address.rb +306 -0
- data/lib/address_concern/address_associations.rb +66 -0
- data/lib/address_concern/attribute_normalizer.rb +9 -0
- data/lib/address_concern/version.rb +5 -0
- data/lib/address_concern.rb +11 -0
- data/lib/generators/address_concern/install_generator.rb +23 -0
- data/lib/generators/address_concern/templates/configurable.yml +33 -0
- data/lib/generators/address_concern/templates/migration.rb +37 -0
- data/spec/models/address_spec.rb +303 -0
- data/spec/spec_helper.rb +50 -0
- data/spec/support/database.mysql2.yml +3 -0
- data/spec/support/database.sqlite3.yml +2 -0
- data/spec/support/models/address.rb +3 -0
- data/spec/support/models/application_record.rb +3 -0
- data/spec/support/models/child.rb +4 -0
- data/spec/support/models/company.rb +3 -0
- data/spec/support/models/employee.rb +4 -0
- data/spec/support/models/user.rb +3 -0
- data/spec/support/schema.rb +19 -0
- data/tmp/.gitkeep +0 -0
- metadata +232 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 54db12d5f83e9438e61c47552eba316511be4cbc69200bee3e51568a10c2c41e
|
4
|
+
data.tar.gz: 73a84002eeafb49d0536d2bf5de94391410b3b4d873633ba62f2fd3e42df8ab5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ac7f541ac00b56b64c9a6e8f6cc7a49ee423cce621c90a13173ddc7e4c852883d5f5a2ad14bca967b2d7c7fcc9678a7b8062bb580c30baa43bb656e681b7fed9
|
7
|
+
data.tar.gz: 305160aabeca32990a9aa74aa2519b6b58b54c7354985ccbb1677fc1ec370b5c0f104319541834c33865f86079f10d4f45b31342be2d2656e90ade6eb42a85fa
|
data/.document
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.7.4
|
data/CHANGELOG
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2011 Paul Campbell
|
2
|
+
Copyright (c) 2011-2018 Tyler Rick
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
|
3
|
+
#---------------------------------------------------------------------------------------------------
|
4
|
+
require 'rspec/core'
|
5
|
+
require 'rspec/core/rake_task'
|
6
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
7
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
8
|
+
end
|
9
|
+
|
10
|
+
desc "Start a console with this version of library loaded"
|
11
|
+
task :console do
|
12
|
+
require 'bundler/setup'
|
13
|
+
require 'address_concern'
|
14
|
+
require 'irb'
|
15
|
+
ARGV.clear
|
16
|
+
IRB.start
|
17
|
+
end
|
18
|
+
|
19
|
+
task :default => :spec
|
data/Readme.md
ADDED
@@ -0,0 +1,231 @@
|
|
1
|
+
# Address Concern
|
2
|
+
|
3
|
+
A reusable polymorphic `Address` model concern for your Rails apps.
|
4
|
+
|
5
|
+
# Installation
|
6
|
+
|
7
|
+
Add `address_concern` to your `Gemfile`:
|
8
|
+
|
9
|
+
gem 'address_concern'
|
10
|
+
|
11
|
+
Then run the generator to create your addresses table:
|
12
|
+
|
13
|
+
rails generate address_concern:install
|
14
|
+
rake db:migrate
|
15
|
+
|
16
|
+
You now have an `Address` model that you can use in your app just as if it were in your `app/models` directory.
|
17
|
+
|
18
|
+
# Usage
|
19
|
+
|
20
|
+
## Base usage
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
class Address < ApplicationRecord
|
24
|
+
include AddressConcern::Address
|
25
|
+
end
|
26
|
+
```
|
27
|
+
|
28
|
+
## `belongs_to_address`
|
29
|
+
|
30
|
+
`AddressConcern::AddressAssociations` is automatically included into `ActiveRecord::Base` and
|
31
|
+
provides a few macros for defining associations with your app's Address model.
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
class Person < ApplicationRecord
|
35
|
+
belongs_to_address
|
36
|
+
end
|
37
|
+
|
38
|
+
person = Person.new
|
39
|
+
person.build_address(address: '...')
|
40
|
+
```
|
41
|
+
|
42
|
+
## Multiple addresses on same model
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
class User < ApplicationRecord
|
46
|
+
belongs_to_address :shipping_address
|
47
|
+
belongs_to_address :billing_address
|
48
|
+
end
|
49
|
+
|
50
|
+
user = User.new
|
51
|
+
shipping_address = user.build_shipping_address(address: '...')
|
52
|
+
billing_address = user.build_billing_address( address: '...')
|
53
|
+
```
|
54
|
+
|
55
|
+
See "Adding an `address` association to your ActiveRecord models" section for more examples of
|
56
|
+
configuration your associations.
|
57
|
+
|
58
|
+
|
59
|
+
# Adding an `address` association to your ActiveRecord models
|
60
|
+
|
61
|
+
You can add an address association (or multiple) to any model that has an address.
|
62
|
+
|
63
|
+
You can associate with the address via a `belongs_to`, `has_one`, or `has_many` — whichever makes
|
64
|
+
the most sense for your use case.
|
65
|
+
|
66
|
+
You can either use standard ActiveRecord association macros, like this:
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
class Person < ApplicationRecord
|
70
|
+
belongs_to :address
|
71
|
+
end
|
72
|
+
```
|
73
|
+
|
74
|
+
... or use the provided macros:
|
75
|
+
|
76
|
+
## `belongs_to_address`
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
class Person < ApplicationRecord
|
80
|
+
belongs_to_address
|
81
|
+
end
|
82
|
+
|
83
|
+
person = Person.new
|
84
|
+
person.build_address(address: '...')
|
85
|
+
```
|
86
|
+
|
87
|
+
If needed, you can pass a name as well as options for the `belongs_to` and (optional) inverse `has_one`
|
88
|
+
associations.
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
class Child < ApplicationRecord
|
92
|
+
belongs_to_address inverse: false
|
93
|
+
belongs_to_address :secret_hideout, inverse: {name: :child_for_secret_hideout}
|
94
|
+
end
|
95
|
+
|
96
|
+
child = Child.new
|
97
|
+
child.build_secret_hideout(address: '...')
|
98
|
+
```
|
99
|
+
|
100
|
+
## `has_address`
|
101
|
+
|
102
|
+
`has_address` creates a `has_one :address` association:
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
class Company < ApplicationRecord
|
106
|
+
has_address
|
107
|
+
end
|
108
|
+
```
|
109
|
+
|
110
|
+
```
|
111
|
+
company = company.new
|
112
|
+
address = company.build_address(address: '...')
|
113
|
+
```
|
114
|
+
|
115
|
+
This also adds a polymorphic `addressable` association on the Address model (not available if you're
|
116
|
+
using `belongs_to :address` on your addressable models):
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
belongs_to :addressable, :polymorphic => true
|
120
|
+
```
|
121
|
+
|
122
|
+
## `has_addresses`
|
123
|
+
|
124
|
+
`has_addresses` creates a `has_many :addresses` association:
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
class User < ApplicationRecord
|
128
|
+
has_addresses
|
129
|
+
end
|
130
|
+
```
|
131
|
+
|
132
|
+
If you want to have several *individually accessible* addresses associated with a single model (such
|
133
|
+
as a separate shipping and billing address), you can do something like this:
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
class User < ApplicationRecord
|
137
|
+
has_addresses :types => [:physical, :shipping, :billing]
|
138
|
+
end
|
139
|
+
```
|
140
|
+
|
141
|
+
Then you can refer to them by name, like this:
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
shipping_address = user.build_shipping_address(address: 'Some address')
|
145
|
+
user.shipping_address # => shipping_address
|
146
|
+
```
|
147
|
+
|
148
|
+
Note that you aren't *limited* to only the address types you specifically list in your
|
149
|
+
`has_addresses` declaration; you can still add and retrieve other addresses using the `has_many
|
150
|
+
:addresses` association:
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
vacation_address = user.addresses.build(address: 'Vacation', :address_type => 'Vacation')
|
154
|
+
user.addresses # => [shipping_address, vacation_address]
|
155
|
+
```
|
156
|
+
|
157
|
+
# Country/state database
|
158
|
+
|
159
|
+
Country/state data comes from the [`carmen`](https://github.com/carmen-ruby/carmen) gem.
|
160
|
+
|
161
|
+
- You can set the country either by using the `country=` writer (if you want to use a country name
|
162
|
+
as input in your frontend) or the `country_code=` writer (if you want to use a country code as
|
163
|
+
input). It will automatically update the other column for you and keep both of them up-to-date.
|
164
|
+
- The country name is stored in the `country` attribute (most common use case).
|
165
|
+
- Country codes can be optionally get/set via the `country_code2` (ISO 3166-1 alpha-2 codes)
|
166
|
+
(aliased as `country_code`) or `country_code3` attributes.
|
167
|
+
- Be aware that if the country you entered isn't recognized (in Carmen's database), it will be
|
168
|
+
rejected and the country field reset to nil. This should probably be considered a bug and be fixed
|
169
|
+
in a later release (using validations instead).
|
170
|
+
|
171
|
+
Other notes regarding country:
|
172
|
+
|
173
|
+
- Added some special handling of UK countries, since Carmen doesn't recognize 'England', etc. as
|
174
|
+
countries but we want to allow those country names to be stored since they may be a part of the
|
175
|
+
address you want to preserve.
|
176
|
+
|
177
|
+
# View helpers
|
178
|
+
|
179
|
+
Because this gem depends on [`carmen`](https://github.com/carmen-ruby/carmen), you have access to
|
180
|
+
its `country_select` and `state_select` helpers.
|
181
|
+
|
182
|
+
# Related Projects
|
183
|
+
|
184
|
+
(Along with some feature/API ideas that we may want to incorporate (pull requests welcome!).)
|
185
|
+
|
186
|
+
- https://github.com/ankane/mainstreet — A standard US address model for Rails
|
187
|
+
- Use `alias_attribute` to map existing field names
|
188
|
+
- Add new fields like `original_attributes` and `verification_info`
|
189
|
+
- Uses `SmartyStreets` to verify addresses (`valid?` returns false).
|
190
|
+
- [`acts_as_address` association macro](https://github.com/ankane/mainstreet/blob/master/lib/mainstreet.rb)
|
191
|
+
- [`Address` model generator](https://github.com/ankane/mainstreet/blob/master/lib/generators/mainstreet/address_generator.rb)
|
192
|
+
- `acts_as_address` could potentially be included into our `Address` model and both gems used together
|
193
|
+
|
194
|
+
- https://github.com/yrgoldteeth/whereabouts — A simple rails plugin that adds a polymorphic address model
|
195
|
+
- `has_whereabouts :location, {:geocode => true}`
|
196
|
+
- `has_whereabouts :location, {:validate => [:city, :state, :zip]}`
|
197
|
+
- [`has_whereabouts` association macro](https://github.com/yrgoldteeth/whereabouts/blob/master/lib/whereabouts_methods.rb)
|
198
|
+
- [`Address` model generator](https://github.com/yrgoldteeth/whereabouts/blob/master/lib/generators/address/templates/address.rb)
|
199
|
+
|
200
|
+
- https://github.com/wilbert/addresses — An Address engine to use Country, State, City and Neighborhood models
|
201
|
+
- Allows you use these models: `Country`, `State` (belongs to country), `City` (belongs to State), `Neighborhood` (belongs to city), `Address` (Belongs to `Neighborhood` and `City`, because neighborhood is not required)
|
202
|
+
- `address.city = Address::City.find(city_id)`
|
203
|
+
- `mount Addresses::Engine => "/addresses"`
|
204
|
+
- [`Address` model](https://github.com/wilbert/addresses/blob/master/app/models/addresses/address.rb)
|
205
|
+
|
206
|
+
- https://github.com/huerlisi/has_vcards — Rails plugin providing VCard like contact and address models and helpers
|
207
|
+
- [`Address` model](https://github.com/huerlisi/has_vcards/blob/master/app/models/has_vcards/address.rb)
|
208
|
+
|
209
|
+
Not maintained for 3+ years:
|
210
|
+
- https://github.com/mobilityhouse/acts_as_addressable — Make your models addressable
|
211
|
+
- `acts_as_addressable :postal, :billing`
|
212
|
+
- [`acts_as_addressable` association macro](https://github.com/mobilityhouse/acts_as_addressable/blob/master/lib/acts_as_addressable/addressable.rb)
|
213
|
+
- [`Address` model generator](https://github.com/mobilityhouse/acts_as_addressable/blob/master/lib/generators/acts_as_addressable/templates/address.rb)
|
214
|
+
- https://github.com/mariusz360/postally_addressable — Add postal addresses to your models
|
215
|
+
- [`has_postal_address` association macro](https://github.com/mariusz360/postally_addressable/blob/master/lib/postally_addressable/has_postal_address.rb)
|
216
|
+
- [`PostalAddress` model](https://github.com/mariusz360/postally_addressable/blob/master/app/models/postal_address.rb)
|
217
|
+
- `alias_attribute :state, :province`
|
218
|
+
- https://github.com/nybblr/somewhere — Serialized address class for use with Rails models. Like it should be.
|
219
|
+
- `address :billing, :postal_code => :zip, :include_prefix => false`
|
220
|
+
- `address.to_hash :exclude => [:country]`
|
221
|
+
- `address.to_s :country => false`
|
222
|
+
- [`Address` model](https://github.com/nybblr/somewhere/blob/master/lib/address.rb)
|
223
|
+
- [`address` association macro](https://github.com/nybblr/somewhere/blob/master/lib/somewhere.rb)
|
224
|
+
- https://github.com/rumblelabs/is_addressable
|
225
|
+
|
226
|
+
# License
|
227
|
+
|
228
|
+
Licensed under the MIT License.
|
229
|
+
|
230
|
+
See LICENSE.txt for further details.
|
231
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.1
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "address_concern/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "address_concern"
|
7
|
+
s.version = AddressConcern.version
|
8
|
+
s.authors = ["Paul Campbell", "Tyler Rick"]
|
9
|
+
s.email = ["paul@rslw.com", "tyler@tylerrick.com"]
|
10
|
+
s.homepage = %q{http://github.com/TylerRick/address_concern}
|
11
|
+
s.summary = %q{A reusable Address model for your Rails apps}
|
12
|
+
s.description = s.summary
|
13
|
+
s.licenses = ["MIT"]
|
14
|
+
|
15
|
+
s.add_dependency "rake"
|
16
|
+
s.add_dependency "cucumber"
|
17
|
+
s.add_dependency "rails", ">= 4.0"
|
18
|
+
s.add_dependency "activerecord", ">= 4.0"
|
19
|
+
s.add_dependency "activesupport", ">= 4.0"
|
20
|
+
s.add_dependency "carmen", '>= 1.1.1'
|
21
|
+
s.add_dependency "attribute_normalizer"
|
22
|
+
s.add_dependency "active_record_ignored_attributes"
|
23
|
+
s.add_dependency "facets"
|
24
|
+
|
25
|
+
s.add_development_dependency 'rspec'
|
26
|
+
s.add_development_dependency 'sqlite3'
|
27
|
+
#s.add_development_dependency 'mysql2', '~>0.2.11'
|
28
|
+
|
29
|
+
s.files = `git ls-files`.split("\n")
|
30
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
31
|
+
#s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
32
|
+
s.require_paths = ["lib"]
|
33
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'address_concern'
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
require_relative "../spec/spec_helper"
|
11
|
+
require "pry"
|
12
|
+
Pry.start
|
@@ -0,0 +1,306 @@
|
|
1
|
+
module AddressConcern::Address
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
included do
|
4
|
+
|
5
|
+
#validates_presence_of :name
|
6
|
+
#validates_presence_of :address
|
7
|
+
#validates_presence_of :state, :if => :state_required?
|
8
|
+
#validates_presence_of :country
|
9
|
+
#validates_format_of :phone, :with => /^[0-9\-\+ ]*$/
|
10
|
+
#validates_format_of :email, :with => /^[^@]*@.*\.[^\.]*$/, :message => 'is invalid. Please enter an address in the format of you@company.com'
|
11
|
+
#validates_presence_of :phone, :message => ' is required.'
|
12
|
+
|
13
|
+
#-------------------------------------------------------------------------------------------------
|
14
|
+
normalize_attributes :name, :city, :state, :postal_code, :country
|
15
|
+
normalize_attribute :address, :with => [:cleanlines, :strip]
|
16
|
+
|
17
|
+
#-------------------------------------------------------------------------------------------------
|
18
|
+
# Country code
|
19
|
+
|
20
|
+
def country_alpha2=(code)
|
21
|
+
if code.blank?
|
22
|
+
write_attribute(:country, nil)
|
23
|
+
write_attribute(:country_alpha2, nil)
|
24
|
+
write_attribute(:country_alpha3, nil)
|
25
|
+
|
26
|
+
elsif (country = Carmen::Country.alpha_2_coded(code))
|
27
|
+
# Only set it if it's a recognized country code
|
28
|
+
write_attribute(:country, country.name)
|
29
|
+
write_attribute(:country_alpha2, code)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Aliases
|
34
|
+
def country_code
|
35
|
+
country_alpha2
|
36
|
+
end
|
37
|
+
def country_code=(code)
|
38
|
+
self.country_alpha2 = code
|
39
|
+
end
|
40
|
+
def state_code
|
41
|
+
state
|
42
|
+
end
|
43
|
+
|
44
|
+
def carmen_country
|
45
|
+
Carmen::Country.alpha_2_coded(country_alpha2)
|
46
|
+
end
|
47
|
+
|
48
|
+
def carmen_state
|
49
|
+
if (country = carmen_country)
|
50
|
+
Address.states_for_country(country).coded(state_code)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
#-------------------------------------------------------------------------------------------------
|
55
|
+
# Country name
|
56
|
+
|
57
|
+
def country=(name)
|
58
|
+
if name.blank?
|
59
|
+
write_attribute(:country, nil)
|
60
|
+
write_attribute(:country_alpha2, nil)
|
61
|
+
write_attribute(:country_alpha3, nil)
|
62
|
+
else
|
63
|
+
name = recognize_country_name_alias(name)
|
64
|
+
if (country = Carmen::Country.named(name))
|
65
|
+
write_attribute(:country, country.name)
|
66
|
+
write_attribute(:country_alpha2, country.alpha_2_code)
|
67
|
+
write_attribute(:country_alpha3, country.alpha_3_code)
|
68
|
+
else
|
69
|
+
write_attribute(:country, nil)
|
70
|
+
write_attribute(:country_alpha2, nil)
|
71
|
+
write_attribute(:country_alpha3, nil)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def recognize_country_name_alias(name)
|
77
|
+
name = case name
|
78
|
+
when 'USA'
|
79
|
+
when 'The Democratic Republic of the Congo', 'Democratic Republic of the Congo'
|
80
|
+
'Congo, the Democratic Republic of the'
|
81
|
+
when 'Republic of Macedonia', 'Macedonia, Republic of', 'Macedonia'
|
82
|
+
'Macedonia, Republic of'
|
83
|
+
else
|
84
|
+
name
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# This should not be different from the value stored in the country attribute, but allows you to
|
89
|
+
# look it up just to make sure they match (or to update country field to match this).
|
90
|
+
def country_name_from_code
|
91
|
+
if (country = Carmen::Country.alpha_2_coded(country_alpha2))
|
92
|
+
country.name
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Aliases
|
97
|
+
def country_name
|
98
|
+
country
|
99
|
+
end
|
100
|
+
def country_name=(name)
|
101
|
+
self.country = name
|
102
|
+
end
|
103
|
+
|
104
|
+
#════════════════════════════════════════════════════════════════════════════════════════════════════
|
105
|
+
# State/province options for country
|
106
|
+
|
107
|
+
# This is useful if want to list the state options allowed for a country in a select box and
|
108
|
+
# restrict entry to only officially listed state options.
|
109
|
+
# It is not required in the postal address for all countries, however. If you only want to show it
|
110
|
+
# if it's required in the postal address, you can make it conditional based on
|
111
|
+
# state_included_in_postal_address?.
|
112
|
+
def self.states_for_country(country)
|
113
|
+
return [] unless country
|
114
|
+
raise ArgumentError.new('expected a Carmen::Country') unless country.is_a? Carmen::Country
|
115
|
+
Carmen::RegionCollection.new(
|
116
|
+
if country.name == 'Kenya'
|
117
|
+
# https://github.com/jim/carmen/issues/227
|
118
|
+
# https://en.wikipedia.org/wiki/Provinces_of_Kenya
|
119
|
+
# Kenya's provinces were replaced by a system of counties in 2013.
|
120
|
+
# https://en.wikipedia.org/wiki/ISO_3166-2:KE confirms that they are "former" provinces.
|
121
|
+
# At the time of this writing, however, it doesn't look like Carmen has been updated to
|
122
|
+
# include the 47 counties listed under https://en.wikipedia.org/wiki/ISO_3166-2:KE.
|
123
|
+
country.subregions.typed('county')
|
124
|
+
elsif country.name == 'France'
|
125
|
+
# https://github.com/jim/carmen/issues/228
|
126
|
+
# https://en.wikipedia.org/wiki/Regions_of_France
|
127
|
+
# In 2016 what had been 27 regions was reduced to 18.
|
128
|
+
# France is divided into 18 administrative regions, including 13 metropolitan regions and 5 overseas regions.
|
129
|
+
# https://en.wikipedia.org/wiki/ISO_3166-2:FR
|
130
|
+
[]
|
131
|
+
else # Needed for New Zealand, Philippines, Indonesia, and possibly others
|
132
|
+
country.subregions.map {|_| _.subregions.any? ? _.subregions : _ }.flatten
|
133
|
+
end
|
134
|
+
)
|
135
|
+
end
|
136
|
+
def states_for_country
|
137
|
+
self.class.states_for_country(carmen_country)
|
138
|
+
end
|
139
|
+
alias_method :state_options, :states_for_country
|
140
|
+
|
141
|
+
def country_with_states?
|
142
|
+
states_for_country.any?
|
143
|
+
end
|
144
|
+
|
145
|
+
# Is the state/province required in a postal address?
|
146
|
+
# If no, perhaps you want to collect it for other reasons (like seeing which people/things are in
|
147
|
+
# the same region). Or for countries where it *may* be included in a postal address but is not
|
148
|
+
# required to be included.
|
149
|
+
def state_required_in_postal_address?
|
150
|
+
[
|
151
|
+
'Australia',
|
152
|
+
'Brazil',
|
153
|
+
'Canada',
|
154
|
+
'Mexico',
|
155
|
+
'United States',
|
156
|
+
'Italy',
|
157
|
+
'Venezuela',
|
158
|
+
].include? country_name
|
159
|
+
end
|
160
|
+
def state_possibly_included_in_postal_address?
|
161
|
+
# https://ux.stackexchange.com/questions/64665/address-form-field-for-region
|
162
|
+
# http://www.bitboost.com/ref/international-address-formats/denmark/
|
163
|
+
# http://www.bitboost.com/ref/international-address-formats/poland/
|
164
|
+
return true if state_required_in_postal_address?
|
165
|
+
return false if [
|
166
|
+
'Algeria',
|
167
|
+
'Argentina',
|
168
|
+
'Austria',
|
169
|
+
'Denmark',
|
170
|
+
'France',
|
171
|
+
'Germany',
|
172
|
+
'Indonesia',
|
173
|
+
'Ireland',
|
174
|
+
'Israel',
|
175
|
+
'Netherlands',
|
176
|
+
'New Zealand',
|
177
|
+
'Poland',
|
178
|
+
'Sweden',
|
179
|
+
'United Kingdom',
|
180
|
+
].include? country_name
|
181
|
+
# Default:
|
182
|
+
country_with_states?
|
183
|
+
end
|
184
|
+
|
185
|
+
# It's not called a "State" in all countries.
|
186
|
+
# In some countries, it could technically be multiple different types of regions:
|
187
|
+
# - In United States, it could be a state or an outlying region or a district or an APO
|
188
|
+
# - In Canada, it could be a province or a territory.
|
189
|
+
# This attempts to return the most common, expected name for this field.
|
190
|
+
# See also: https://ux.stackexchange.com/questions/64665/address-form-field-for-region
|
191
|
+
#
|
192
|
+
# To see what it should be called in all countries known to Carmen:
|
193
|
+
# Country.countries_with_states.map {|country| [country.name, Address.new(country_name: country.name).state_label] }.to_h
|
194
|
+
# => {"Afghanistan"=>"Province",
|
195
|
+
# "Armenia"=>"Province",
|
196
|
+
# "Angola"=>"Province",
|
197
|
+
# "Argentina"=>"Province",
|
198
|
+
# "Austria"=>"State",
|
199
|
+
# "Australia"=>"State",
|
200
|
+
# ...
|
201
|
+
def state_label
|
202
|
+
# In UK, it looks like they (optionally) include the *county* in their addresses. They don't actually have "states" per se.
|
203
|
+
# Reference: http://bitboost.com/ref/international-address-formats/united-kingdom/
|
204
|
+
# Could also limit to Countries (England, Scotland, Wales) and Provinces (Northern Ireland).
|
205
|
+
# Who knows. The UK's subregions are a mess.
|
206
|
+
# If allowing the full list of subregions from https://en.wikipedia.org/wiki/ISO_3166-2:GB,
|
207
|
+
# perhaps Region is a better, more inclusive term.
|
208
|
+
if country_name.in? ['United Kingdom']
|
209
|
+
'Region'
|
210
|
+
elsif state_options.any?
|
211
|
+
state_options[0].type.capitalize
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def state_name
|
216
|
+
carmen_state ? carmen_state.name : state
|
217
|
+
end
|
218
|
+
|
219
|
+
#════════════════════════════════════════════════════════════════════════════════════════════════════
|
220
|
+
|
221
|
+
def empty?
|
222
|
+
[:address, :city, :state, :postal_code, :country].all? {|_|
|
223
|
+
!self[_].present?
|
224
|
+
}
|
225
|
+
end
|
226
|
+
|
227
|
+
def started_filling_out?
|
228
|
+
[:address, :city, :state, :postal_code, :country].any? {|_|
|
229
|
+
self[_].present?
|
230
|
+
}
|
231
|
+
end
|
232
|
+
|
233
|
+
#════════════════════════════════════════════════════════════════════════════════════════════════════
|
234
|
+
# Formatting for humans
|
235
|
+
|
236
|
+
# Lines of a postal address
|
237
|
+
def lines
|
238
|
+
[
|
239
|
+
name,
|
240
|
+
address.to_s.lines.to_a,
|
241
|
+
city_line,
|
242
|
+
country_name,
|
243
|
+
].flatten.reject(&:blank?)
|
244
|
+
end
|
245
|
+
|
246
|
+
# Used by #lines
|
247
|
+
#
|
248
|
+
# Instead of using `state` method (which is really state_code). That's fine for some countries
|
249
|
+
# like US, Canada, Australia but not other countries (presumably).
|
250
|
+
#
|
251
|
+
# TODO: Put postal code and city in a different order, as that countries conventions dictate.
|
252
|
+
# See http://bitboost.com/ref/international-address-formats/new-zealand/
|
253
|
+
#
|
254
|
+
def city_line
|
255
|
+
[
|
256
|
+
#[city, state].reject(&:blank?).join(', '),
|
257
|
+
[city, state_for_postal_address].reject(&:blank?).join(', '),
|
258
|
+
postal_code,
|
259
|
+
].reject(&:blank?).join(' ')
|
260
|
+
end
|
261
|
+
|
262
|
+
def city_state_code
|
263
|
+
[city, state].reject(&:blank?).join(', ')
|
264
|
+
end
|
265
|
+
|
266
|
+
def city_state_name
|
267
|
+
[city, state_name].reject(&:blank?).join(', ')
|
268
|
+
end
|
269
|
+
|
270
|
+
def city_state_country
|
271
|
+
[city_state_name, country_name].join(', ')
|
272
|
+
end
|
273
|
+
|
274
|
+
def state_for_postal_address
|
275
|
+
# Possibly others use a code? But seems safer to default to a name until confirmed that they use
|
276
|
+
# a code.
|
277
|
+
if country_name.in? ['United States', 'Canada', 'Australia']
|
278
|
+
state_code
|
279
|
+
elsif state_possibly_included_in_postal_address?
|
280
|
+
state_name
|
281
|
+
else
|
282
|
+
''
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
#════════════════════════════════════════════════════════════════════════════════════════════════════
|
287
|
+
# Misc. output
|
288
|
+
|
289
|
+
def parts
|
290
|
+
[
|
291
|
+
name,
|
292
|
+
address.to_s.lines.to_a,
|
293
|
+
city,
|
294
|
+
state_name,
|
295
|
+
postal_code,
|
296
|
+
country_name,
|
297
|
+
].flatten.reject(&:blank?)
|
298
|
+
end
|
299
|
+
|
300
|
+
def inspect
|
301
|
+
inspect_with([:id, :name, :address, :city, :state, :postal_code, :country], ['{', '}'])
|
302
|
+
end
|
303
|
+
|
304
|
+
#-------------------------------------------------------------------------------------------------
|
305
|
+
end
|
306
|
+
end
|