address_concern 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|