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.
@@ -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,9 @@
1
+ require 'attribute_normalizer'
2
+ require 'facets/string/cleanlines'
3
+
4
+ AttributeNormalizer.configure do |config|
5
+ config.normalizers[:cleanlines] = lambda do |input, options|
6
+ input.to_s.cleanlines.to_a.join("\n")
7
+ end
8
+ end
9
+
@@ -0,0 +1,5 @@
1
+ module AddressConcern
2
+ def self.version
3
+ "2.0.0"
4
+ end
5
+ 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
@@ -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,3 @@
1
+ adapter: mysql2
2
+ database: address_concern_test
3
+ username: root
@@ -0,0 +1,2 @@
1
+ adapter: sqlite3
2
+ database: ":memory:"
@@ -0,0 +1,3 @@
1
+ class Address < ApplicationRecord
2
+ include AddressConcern::Address
3
+ end
@@ -0,0 +1,3 @@
1
+ class ApplicationRecord < ActiveRecord::Base
2
+ self.abstract_class = true
3
+ end
@@ -0,0 +1,4 @@
1
+ class Child < ApplicationRecord
2
+ belongs_to_address
3
+ belongs_to_address :secret_hideout, inverse: {name: :child_for_secret_hideout}
4
+ end
@@ -0,0 +1,3 @@
1
+ class Company < ApplicationRecord
2
+ has_address
3
+ end
@@ -0,0 +1,4 @@
1
+ class Employee < ApplicationRecord
2
+ belongs_to_address :home_address, foreign_key: :physical_address_id, inverse: {name: :employee_home, foreign_key: :physical_address_id}
3
+ belongs_to_address :work_address, dependent: :destroy, inverse: {name: :employee_work}
4
+ end
@@ -0,0 +1,3 @@
1
+ class User < ApplicationRecord
2
+ has_addresses :types => [:physical, :shipping, :billing]
3
+ 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