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
@@ -0,0 +1,66 @@
|
|
1
|
+
module AddressConcern::AddressAssociations
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
module ClassMethods
|
4
|
+
# Creates a belongs_to +address+ association, named "address" by default but a different name may be
|
5
|
+
# provided. In the Address model, creates an inverse association unless you pass +inverse: false+.
|
6
|
+
#
|
7
|
+
# You can pass options to the belongs_to, like this:
|
8
|
+
# belongs_to_address :work_address, dependent: :destroy
|
9
|
+
#
|
10
|
+
# You can also pass options to the inverse has_one assocation in the Address model, via the
|
11
|
+
# +inverse+ option:
|
12
|
+
# belongs_to_address :home_address, inverse: {foreign_key: :physical_address_id}
|
13
|
+
def belongs_to_address(name = :address, inverse: nil, **options)
|
14
|
+
options.reverse_merge!({
|
15
|
+
class_name: 'Address'
|
16
|
+
})
|
17
|
+
raise "association :#{name} already exists on #{self}" if reflect_on_association(name)
|
18
|
+
belongs_to name, **options
|
19
|
+
#puts %(reflect_on_association(#{name})=#{reflect_on_association(name).inspect})
|
20
|
+
|
21
|
+
unless inverse == false
|
22
|
+
inverse ||= {}
|
23
|
+
inverse.reverse_merge!({
|
24
|
+
name: self.name.underscore.to_sym,
|
25
|
+
inverse_of: name,
|
26
|
+
class_name: self.name,
|
27
|
+
foreign_key: "#{name}_id",
|
28
|
+
})
|
29
|
+
name = inverse.delete(:name)
|
30
|
+
inverse_of = inverse.delete(:inverse_of)
|
31
|
+
Address.class_eval do
|
32
|
+
raise "association :#{name} already exists on #{self}" if reflect_on_association(name)
|
33
|
+
has_one name, inverse_of: inverse_of, **inverse
|
34
|
+
#puts %(reflect_on_association(#{name})=#{reflect_on_association(name).inspect})
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Creates a has_one +address+ association, representing the one and only address associated with the current record
|
40
|
+
def has_address
|
41
|
+
has_one :address, as: :addressable
|
42
|
+
create_addressable_association_on_address
|
43
|
+
end
|
44
|
+
|
45
|
+
# Creates a has_many +addresses+ association, representing all addresses associated with the current record
|
46
|
+
def has_addresses(options = {})
|
47
|
+
has_many :addresses, as: :addressable
|
48
|
+
(options[:types] || ()).each do |type|
|
49
|
+
has_one :"#{type}_address", -> { where({address_type: type}) }, class_name: 'Address', as: :addressable
|
50
|
+
end
|
51
|
+
create_addressable_association_on_address
|
52
|
+
end
|
53
|
+
|
54
|
+
def create_addressable_association_on_address
|
55
|
+
Address.class_eval do
|
56
|
+
unless reflect_on_association(:addressable)
|
57
|
+
belongs_to :addressable, :polymorphic => true
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
ActiveRecord::Base.class_eval do
|
65
|
+
include AddressConcern::AddressAssociations
|
66
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'rails'
|
2
|
+
require 'carmen'
|
3
|
+
require 'active_record'
|
4
|
+
require 'active_record_ignored_attributes'
|
5
|
+
|
6
|
+
Carmen.i18n_backend.append_locale_path File.join(File.dirname(__FILE__), '../config/locale/overlay/en')
|
7
|
+
|
8
|
+
require 'address_concern/version'
|
9
|
+
require 'address_concern/attribute_normalizer'
|
10
|
+
require_relative 'address_concern/address'
|
11
|
+
require_relative 'address_concern/address_associations'
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
module AddressConcern
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
include Rails::Generators::Migration
|
5
|
+
|
6
|
+
|
7
|
+
def self.source_root
|
8
|
+
@source_root ||= File.join(File.dirname(__FILE__), 'templates')
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.next_migration_number(dirname)
|
12
|
+
if ActiveRecord::Base.timestamped_migrations
|
13
|
+
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
14
|
+
else
|
15
|
+
"%.3d" % (current_migration_number(dirname) + 1)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def create_migration_file
|
20
|
+
migration_template 'migration.rb', 'db/migrate/create_addresses.rb'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# This file controls what config variables you want to be able to allow your users
|
2
|
+
# to set, as well as those you'll be able to access from within the application.
|
3
|
+
#
|
4
|
+
# If you want to be able to access a string config[:site_title], for example:
|
5
|
+
#
|
6
|
+
# site_title:
|
7
|
+
# name: Site Title
|
8
|
+
# type: string
|
9
|
+
# default: My Site
|
10
|
+
#
|
11
|
+
# 'name' is the name that appears in the edit form
|
12
|
+
#
|
13
|
+
# 'type' can be 'string' for a text field, 'password' for a password field or 'text' for a text area
|
14
|
+
# 'type' defaults to 'string'
|
15
|
+
#
|
16
|
+
# 'default' is the default value to use if there's no entry in the database. Otherwise, nil will be returned
|
17
|
+
#
|
18
|
+
# Some Examples:
|
19
|
+
#
|
20
|
+
# site_title:
|
21
|
+
# name: Site Title
|
22
|
+
# default: My Site
|
23
|
+
# type: string
|
24
|
+
#
|
25
|
+
# site_description:
|
26
|
+
# name: Description for Google
|
27
|
+
# default: Lots of Awesomeness Here
|
28
|
+
# type: text
|
29
|
+
#
|
30
|
+
# secret:
|
31
|
+
# name: Secret Password for Accessing Secret Areas
|
32
|
+
# default: secret
|
33
|
+
# type: password
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class CreateAddresses < ActiveRecord::Migration[4.2]
|
2
|
+
def self.up
|
3
|
+
create_table :addresses do |t|
|
4
|
+
t.references :addressable, :polymorphic => true
|
5
|
+
t.string :address_type # to allow shipping/billing/etc. address
|
6
|
+
|
7
|
+
t.string :name
|
8
|
+
t.text :address
|
9
|
+
t.string :city
|
10
|
+
t.string :state
|
11
|
+
t.string :postal_code
|
12
|
+
t.string :country
|
13
|
+
t.string :country_alpha2
|
14
|
+
t.string :country_alpha3
|
15
|
+
t.string :email
|
16
|
+
t.string :phone
|
17
|
+
t.timestamps
|
18
|
+
end
|
19
|
+
|
20
|
+
change_table :addresses do |t|
|
21
|
+
t.index :addressable_id
|
22
|
+
t.index :addressable_type
|
23
|
+
t.index :address_type
|
24
|
+
t.index :name
|
25
|
+
t.index :state
|
26
|
+
t.index :country
|
27
|
+
t.index :country_alpha2
|
28
|
+
t.index :country_alpha3
|
29
|
+
t.index :email
|
30
|
+
t.index :phone
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.down
|
35
|
+
drop_table :addresses
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,303 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Address do
|
4
|
+
describe 'setting country by name' do
|
5
|
+
let(:address) { Address.new }
|
6
|
+
specify 'setting to known country' do
|
7
|
+
address.country = 'Iceland'
|
8
|
+
address.country_name.should == 'Iceland'
|
9
|
+
address.country_code.should == 'IS'
|
10
|
+
end
|
11
|
+
|
12
|
+
specify 'setting to unknown country' do
|
13
|
+
# Set it to a known country first to show that it actually *clears* these fields if they were previously set
|
14
|
+
address.country = 'Iceland'
|
15
|
+
|
16
|
+
#expect { expect {
|
17
|
+
address.country = 'Fireland'
|
18
|
+
#}.to change(address, :country_name).to(nil)
|
19
|
+
#}.to change(address, :country_code).to(nil)
|
20
|
+
address.country_name.should eq nil
|
21
|
+
address.country_code.should eq nil
|
22
|
+
|
23
|
+
address.country = 'Northern Ireland'
|
24
|
+
address.country_name.should eq nil
|
25
|
+
address.country_code.should eq nil
|
26
|
+
|
27
|
+
address.country = 'USA'
|
28
|
+
address.country_name.should eq nil
|
29
|
+
address.country_code.should eq nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'setting country by code' do
|
34
|
+
let(:address) { Address.new }
|
35
|
+
specify 'setting to known country' do
|
36
|
+
address.country_code = 'IS'
|
37
|
+
address.country_name.should == 'Iceland'
|
38
|
+
address.country_code.should == 'IS'
|
39
|
+
end
|
40
|
+
|
41
|
+
specify 'setting to unknown country' do
|
42
|
+
# Set it to a known country first to show that it actually *clears* these fields if they were previously set
|
43
|
+
address.country_code = 'IS'
|
44
|
+
|
45
|
+
#expect { expect {
|
46
|
+
address.country = 'FL'
|
47
|
+
#}.to change(address, :country_name).to(nil)
|
48
|
+
#}.to change(address, :country_code).to(nil)
|
49
|
+
address.country_name.should eq nil
|
50
|
+
address.country_code.should eq nil
|
51
|
+
end
|
52
|
+
|
53
|
+
specify 'setting to a country that is part of another country (weird)' do
|
54
|
+
# Not currently possible using country_code=
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe 'country aliases:' do
|
59
|
+
let(:address) { Address.new }
|
60
|
+
['The Democratic Republic of the Congo', 'Democratic Republic of the Congo'].each do |_| specify _ do
|
61
|
+
address.country = _
|
62
|
+
address.country_name.should == 'Congo, The Democratic Republic of the'
|
63
|
+
address.country_name_from_code.should == 'Congo, The Democratic Republic of the'
|
64
|
+
end; end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe 'started_filling_out?' do
|
68
|
+
[:address, :city, :state, :postal_code].each do |attr_name|
|
69
|
+
it "should be true when #{attr_name} (and only #{attr_name}) is present" do
|
70
|
+
Address.new(attr_name => 'something').should be_started_filling_out
|
71
|
+
end
|
72
|
+
end
|
73
|
+
it "should be true when country (and only country) is present" do
|
74
|
+
Address.new(:country => 'Latvia').should be_started_filling_out
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe 'normalization' do
|
79
|
+
describe 'address' do
|
80
|
+
it { should normalize_attribute(:address).from(" Line 1 \n Line 2 \n ").to("Line 1\nLine 2")}
|
81
|
+
[:name, :city, :state, :postal_code, :country].each do |attr_name|
|
82
|
+
it { should normalize_attribute(attr_name) }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe 'parts and lines' do
|
88
|
+
it do
|
89
|
+
address = Address.new(
|
90
|
+
address: '10 Some Road',
|
91
|
+
city: 'Watford', state: 'HRT', postal_code: 'WD25 9JZ',
|
92
|
+
country: 'United Kingdom'
|
93
|
+
)
|
94
|
+
address.parts.should == [
|
95
|
+
'10 Some Road',
|
96
|
+
'Watford',
|
97
|
+
'Hertfordshire',
|
98
|
+
'WD25 9JZ',
|
99
|
+
'United Kingdom'
|
100
|
+
]
|
101
|
+
address.lines.should == [
|
102
|
+
'10 Some Road',
|
103
|
+
'Watford WD25 9JZ',
|
104
|
+
'United Kingdom'
|
105
|
+
]
|
106
|
+
address.city_line.should == 'Watford WD25 9JZ'
|
107
|
+
address.city_state_name.should == 'Watford, Hertfordshire'
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe '#city_state/#city_state_country' do
|
112
|
+
context "when address doesn't have a state" do
|
113
|
+
let(:user) { User.create }
|
114
|
+
subject { user.build_physical_address(address: '123', city: 'Stockholm', country_name: 'Sweden') }
|
115
|
+
it { subject.city_state_code.should == 'Stockholm' }
|
116
|
+
it { subject.city_state_name.should == 'Stockholm' }
|
117
|
+
it { subject.city_state_country.should == 'Stockholm, Sweden' }
|
118
|
+
end
|
119
|
+
context "when address has a state abbrevitation in :state field" do
|
120
|
+
let(:user) { User.create }
|
121
|
+
subject { user.build_physical_address(address: '123', city: 'Nelspruit', state: 'MP', country_name: 'South Africa') }
|
122
|
+
it { subject.city_state_code.should == 'Nelspruit, MP' }
|
123
|
+
it { subject.city_state_name.should == 'Nelspruit, Mpumalanga' }
|
124
|
+
it { subject.city_state_country.should == 'Nelspruit, Mpumalanga, South Africa' }
|
125
|
+
end
|
126
|
+
context "when address has a state abbrevitation in :state field (Denmark)" do
|
127
|
+
let(:user) { User.create }
|
128
|
+
subject { user.build_physical_address(address: '123', city: 'Copenhagen', state: '84', country_name: 'Denmark') }
|
129
|
+
it { subject.city_state_name.should == 'Copenhagen, Hovedstaden' }
|
130
|
+
it { subject.state_name.should == 'Hovedstaden' }
|
131
|
+
end
|
132
|
+
|
133
|
+
# United States
|
134
|
+
context "when address has a state name entered for :state instead of an abbreviation" do
|
135
|
+
let(:user) { User.create }
|
136
|
+
subject { user.build_physical_address(address: '123', city: 'Ocala', state: 'Florida', country_name: 'United States') }
|
137
|
+
it { subject.city_state_code.should == 'Ocala, Florida' }
|
138
|
+
it { subject.city_state_name.should == 'Ocala, Florida' }
|
139
|
+
it { subject.city_state_country.should == 'Ocala, Florida, United States' }
|
140
|
+
end
|
141
|
+
context "when address has a state abbrevitation in :state field" do
|
142
|
+
let(:user) { User.create }
|
143
|
+
subject { user.build_physical_address(address: '123', city: 'Ocala', state: 'FL', country_name: 'United States') }
|
144
|
+
it { subject.city_state_code.should == 'Ocala, FL' }
|
145
|
+
it { subject.city_state_name.should == 'Ocala, Florida' }
|
146
|
+
it { subject.city_state_country.should == 'Ocala, Florida, United States' }
|
147
|
+
end
|
148
|
+
context "when address has a state name entered for :state instead of an abbreviation, but state is for different country" do
|
149
|
+
let(:user) { User.create }
|
150
|
+
subject { user.build_physical_address(address: '123', city: 'Ocala', state: 'FL', country_name: 'Denmark') }
|
151
|
+
it { subject.city_state_code.should == 'Ocala, FL' }
|
152
|
+
it { subject.city_state_name.should == 'Ocala, FL' }
|
153
|
+
it { subject.city_state_country.should == 'Ocala, FL, Denmark' }
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
describe 'same_as?' do
|
158
|
+
it 'should be true when country is only present attribute and it matches' do
|
159
|
+
Address.new(country: 'United States').should be_same_as(
|
160
|
+
Address.new(country: 'United States'))
|
161
|
+
end
|
162
|
+
it 'should be true when country and state are only present attributes and they match' do
|
163
|
+
Address.new(state: 'Washington', country: 'United States').should be_same_as(
|
164
|
+
Address.new(state: 'Washington', country: 'United States'))
|
165
|
+
end
|
166
|
+
it "not should be true when address attribute doesn't match" do
|
167
|
+
Address.new(address: '123 C St.', state: 'Washington', country: 'United States').should_not be_same_as(
|
168
|
+
Address.new(address: '444 Z St.', state: 'Washington', country: 'United States'))
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
describe '#carmen_country' do
|
173
|
+
it { Address.new(country: 'South Africa').carmen_country.should be_a Carmen::Country }
|
174
|
+
end
|
175
|
+
describe '#carmen_state' do
|
176
|
+
it { Address.new(country: 'United States', state: 'OH!').carmen_state.should be_nil }
|
177
|
+
it { Address.new(country: 'United States', state: 'OH').carmen_state.should be_a Carmen::Region }
|
178
|
+
it { Address.new(country: 'United States', state: 'AA').carmen_state.should be_a Carmen::Region }
|
179
|
+
it { Address.new(country: 'South Africa', state: 'MP').carmen_state.should be_a Carmen::Region }
|
180
|
+
end
|
181
|
+
|
182
|
+
describe '#states_for_country, etc.' do
|
183
|
+
it { Address.new(country: 'United States').states_for_country.map(&:code).should include 'AA' }
|
184
|
+
it { Address.new(country: 'United States').states_for_country.map(&:name).should include 'Ohio' }
|
185
|
+
it { Address.new(country: 'United States').states_for_country.map(&:name).should include 'District of Columbia' }
|
186
|
+
it { Address.new(country: 'United States').states_for_country.map(&:name).should include 'Puerto Rico' }
|
187
|
+
it { Address.new(country: 'South Africa').states_for_country.map(&:name).should include 'Mpumalanga' }
|
188
|
+
it { Address.new(country: 'Kenya').states_for_country.typed('province').should be_empty }
|
189
|
+
# At the time of this writing, it doesn't look like Carmen has been updated to
|
190
|
+
# include the 47 counties listed under https://en.wikipedia.org/wiki/ISO_3166-2:KE.
|
191
|
+
#it { Address.new(country: 'Kenya').states_for_country.map(&:name).should include 'Nyeri' }
|
192
|
+
it { Address.new(country: 'Denmark').state_options.should be_many }
|
193
|
+
it { Address.new(country: 'Denmark').state_options.map(&:name).should include 'Sjælland' }
|
194
|
+
it { Address.new(country: 'Denmark').state_possibly_included_in_postal_address?.should eq false }
|
195
|
+
|
196
|
+
# Auckland (AUK) is a subregion of the North Island (N) subregion
|
197
|
+
it { Address.new(country: 'New Zealand').state_options.map(&:code).should include 'AUK' }
|
198
|
+
it { Address.new(country: 'New Zealand').state_options.map(&:code).should_not include 'N' }
|
199
|
+
# Chatham Islands Territory (CIT) is a top-level region
|
200
|
+
it { Address.new(country: 'New Zealand').state_options.map(&:code).should include 'CIT' }
|
201
|
+
|
202
|
+
# Abra (ABR) is a subregion of the Cordillera Administrative Region (CAR) (15) subregion
|
203
|
+
it { Address.new(country: 'Philippines').state_options.map(&:code).should include 'ABR' }
|
204
|
+
it { Address.new(country: 'Philippines').state_options.map(&:code).should_not include '15' }
|
205
|
+
# National Capital Region (00) is a top-level region
|
206
|
+
it { Address.new(country: 'Philippines').state_options.map(&:code).should include '00' }
|
207
|
+
|
208
|
+
# https://en.wikipedia.org/wiki/Provinces_of_Indonesia
|
209
|
+
# The provinces are officially grouped into seven geographical units
|
210
|
+
# Jawa Barat (JB) is a subregion of the Jawa (JW) subregion
|
211
|
+
it { Address.new(country: 'Indonesia').state_options.map(&:code).should include 'JB' }
|
212
|
+
it { Address.new(country: 'Indonesia').state_options.map(&:code).should_not include 'JW' }
|
213
|
+
# The province is not called "Jakarta Raya" according to
|
214
|
+
# https://en.wikipedia.org/wiki/ISO_3166-2:ID and https://en.wikipedia.org/wiki/Jakarta — it's
|
215
|
+
# called 'DKI Jakarta', which is short for 'Daerah Khusus Ibukota Jakarta' ('Special Capital
|
216
|
+
# City District of Jakarta'),
|
217
|
+
it { Address.new(country: 'Indonesia').state_options.map(&:name).should include 'DKI Jakarta' }
|
218
|
+
|
219
|
+
# At the time of this writing, it doesn't look like Carmen has been updated to reflect the new 18
|
220
|
+
# regions of France.
|
221
|
+
it { Address.new(country: 'France').state_options.size.should eq 0 }
|
222
|
+
#it { Address.new(country: 'France').state_options.size.should eq 18 }
|
223
|
+
#it { Address.new(country: 'France').state_options.map(&:name).should include 'Auvergne-Rhône-Alpes' }
|
224
|
+
end
|
225
|
+
|
226
|
+
describe 'associations' do
|
227
|
+
# To do (or maybe not even necessary—seems to work with only the has_one side of the association):
|
228
|
+
#describe 'when we have a polymorphic belongs_to :addressable in Address' do
|
229
|
+
#belongs_to :addressable, :polymorphic => true
|
230
|
+
|
231
|
+
describe 'Company has_one :address' do
|
232
|
+
let(:company) { Company.create }
|
233
|
+
|
234
|
+
it do
|
235
|
+
company.address.should == nil
|
236
|
+
address = company.build_address(address: '1')
|
237
|
+
company.save!
|
238
|
+
company.reload.address.should == address
|
239
|
+
address.addressable.should == company
|
240
|
+
end
|
241
|
+
|
242
|
+
end
|
243
|
+
|
244
|
+
describe 'User has_many :addresses' do
|
245
|
+
let(:user) { User.create }
|
246
|
+
|
247
|
+
it do
|
248
|
+
user.addresses.should == []
|
249
|
+
address_1 = user.addresses.build(address: '1')
|
250
|
+
address_2 = user.addresses.build(address: '2')
|
251
|
+
user.save!; user.reload
|
252
|
+
user.addresses.should == [address_1, address_2]
|
253
|
+
end
|
254
|
+
|
255
|
+
specify 'should able to set and retrieve a specific address by type (shipping or billing)' do
|
256
|
+
physical_address = user.build_physical_address(address: 'Physical')
|
257
|
+
shipping_address = user.build_shipping_address(address: 'Shipping')
|
258
|
+
billing_address = user.build_billing_address( address: 'Billing')
|
259
|
+
vacation_address = user.addresses.build(address: 'Vacation', :address_type => 'Vacation')
|
260
|
+
user.save!; user.reload
|
261
|
+
user.physical_address.should == physical_address
|
262
|
+
user.shipping_address.should == shipping_address
|
263
|
+
user.billing_address. should == billing_address
|
264
|
+
user.addresses.to_set.should == [physical_address, shipping_address, billing_address, vacation_address].to_set
|
265
|
+
physical_address.addressable.should == user
|
266
|
+
shipping_address.addressable.should == user
|
267
|
+
billing_address .addressable.should == user
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
describe 'Employee belongs_to :home_address' do
|
272
|
+
subject!(:employee) { Employee.create! }
|
273
|
+
|
274
|
+
it do
|
275
|
+
employee.home_address.should == nil
|
276
|
+
employee.work_address.should == nil
|
277
|
+
home_address = employee.build_home_address(address: '1')
|
278
|
+
work_address = employee.build_work_address(address: '2')
|
279
|
+
employee.save!
|
280
|
+
employee.reload.home_address.should == home_address
|
281
|
+
employee.reload.work_address.should == work_address
|
282
|
+
home_address.employee_home.should == employee
|
283
|
+
work_address.employee_work.should == employee
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
describe 'Child belongs_to :secret_hideout' do
|
288
|
+
subject!(:child) { Child.create! }
|
289
|
+
|
290
|
+
it do
|
291
|
+
child.address. should == nil
|
292
|
+
child.secret_hideout.should == nil
|
293
|
+
address = child.build_address(address: '2')
|
294
|
+
secret_hideout = child.build_secret_hideout(address: '1')
|
295
|
+
child.save!
|
296
|
+
child.reload.address. should == address
|
297
|
+
child.reload.secret_hideout.should == secret_hideout
|
298
|
+
address. child. should == child
|
299
|
+
secret_hideout.child_for_secret_hideout.should == child
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
require 'bundler/setup'
|
3
|
+
Bundler.require(:default, :development)
|
4
|
+
|
5
|
+
#---------------------------------------------------------------------------------------------------
|
6
|
+
|
7
|
+
__DIR__ = Pathname.new(__FILE__).dirname
|
8
|
+
$LOAD_PATH.unshift __DIR__
|
9
|
+
$LOAD_PATH.unshift __DIR__ + '../lib'
|
10
|
+
|
11
|
+
#---------------------------------------------------------------------------------------------------
|
12
|
+
# ActiveRecord
|
13
|
+
|
14
|
+
require 'active_record'
|
15
|
+
|
16
|
+
log_file_path = __DIR__ + 'test.log'
|
17
|
+
log_file_path.truncate(0) rescue nil
|
18
|
+
ActiveRecord::Base.logger = Logger.new(log_file_path)
|
19
|
+
|
20
|
+
driver = (ENV["DB"] or "sqlite3").downcase
|
21
|
+
database_config = YAML::load(File.open(__DIR__ + "support/database.#{driver}.yml"))
|
22
|
+
ActiveRecord::Base.establish_connection(database_config)
|
23
|
+
|
24
|
+
require __DIR__ + 'support/schema'
|
25
|
+
require 'generators/address_concern/templates/migration'
|
26
|
+
CreateAddresses.up
|
27
|
+
|
28
|
+
#---------------------------------------------------------------------------------------------------
|
29
|
+
# RSpec
|
30
|
+
|
31
|
+
require 'rspec'
|
32
|
+
|
33
|
+
require 'active_record_ignored_attributes/matchers'
|
34
|
+
|
35
|
+
|
36
|
+
RSpec.configure do |config|
|
37
|
+
config.include AttributeNormalizer::RSpecMatcher #, :type => :models
|
38
|
+
config.expect_with(:rspec) { |c| c.syntax = :should }
|
39
|
+
config.example_status_persistence_file_path = "tmp/rspec_status.txt"
|
40
|
+
end
|
41
|
+
|
42
|
+
require 'address_concern'
|
43
|
+
|
44
|
+
require_relative 'support/models/application_record'
|
45
|
+
require_relative 'support/models/address'
|
46
|
+
|
47
|
+
# Requires supporting ruby files in spec/support/
|
48
|
+
Dir[__DIR__ + 'support/**/*.rb'].each do |f|
|
49
|
+
require f
|
50
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
ActiveRecord::Schema.define do
|
2
|
+
create_table :users, :force => true do |t|
|
3
|
+
t.string :name
|
4
|
+
end
|
5
|
+
create_table :employees, :force => true do |t|
|
6
|
+
t.string :name
|
7
|
+
t.belongs_to :physical_address
|
8
|
+
t.belongs_to :work_address
|
9
|
+
end
|
10
|
+
create_table :companies, :force => true do |t|
|
11
|
+
t.string :name
|
12
|
+
end
|
13
|
+
create_table :children, :force => true do |t|
|
14
|
+
t.string :name
|
15
|
+
t.belongs_to :address
|
16
|
+
t.belongs_to :secret_hideout
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
data/tmp/.gitkeep
ADDED
File without changes
|