immigrant 0.1.6 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,47 @@
1
+ # Immigrant
2
+ [<img src="https://secure.travis-ci.org/jenseng/immigrant.png?rvm=1.9.3" />](http://travis-ci.org/jenseng/immigrant)
3
+
4
+ Immigrant gives [Foreigner](https://github.com/matthuhiggins/foreigner) a
5
+ migration generator so you can effortlessly add missing foreign keys. This is
6
+ particularly helpful when you decide to add keys to an established Rails app.
7
+
8
+ Like Foreigner, Immigrant requires Rails 3.0 or greater.
9
+
10
+ ## Installation
11
+
12
+ Add the following to your Gemfile:
13
+
14
+ ```ruby
15
+ gem 'immigrant'
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```bash
21
+ rails generate immigration AddKeys
22
+ ```
23
+
24
+ This will create a migration named AddKeys which will have `add_foreign_key`
25
+ statements for any missing foreign keys. Immigrant infers missing ones by
26
+ evaluating the associations in your models (e.g. `belongs_to`, `has_many`, etc.).
27
+ Only missing keys will be added; existing ones will never be altered or
28
+ removed.
29
+
30
+ ## Considerations
31
+
32
+ If the data in your tables is bad, then the migration will fail to run
33
+ (obviously). IOW, ensure you don't have orphaned records **before** you try to
34
+ add foreign keys.
35
+
36
+ ## Known Issues
37
+
38
+ Immigrant currently only looks for foreign keys in `ActiveRecord::Base`'s
39
+ database. So if a model is using a different database connection and it has
40
+ foreign keys, Immigrant will incorrectly include them again in the generated
41
+ migration.
42
+
43
+ ## [Changelog](CHANGELOG.md)
44
+
45
+ ## License
46
+
47
+ Copyright (c) 2012-2014 Jon Jensen, released under the MIT license
@@ -10,10 +10,10 @@ class ImmigrationGenerator < ActiveRecord::Generators::Base
10
10
  $stderr.puts "NOTICE: #{key.options[:name]} has ON DELETE CASCADE. You should remove the :dependent option from the association to take advantage of this."
11
11
  end
12
12
  if @keys.present?
13
- template = ActiveRecord::VERSION::STRING < "3.1." ? "immigration-pre-3.1.rb" : "immigration.rb"
13
+ template = ActiveRecord::VERSION::STRING < "3.1." ? 'immigration-pre-3.1.rb.erb' : 'immigration.rb.erb'
14
14
  migration_template template, "db/migrate/#{file_name}.rb"
15
15
  else
16
- puts "Nothing to do"
16
+ puts 'Nothing to do'
17
17
  end
18
18
  end
19
19
 
data/lib/immigrant.rb CHANGED
@@ -39,11 +39,7 @@ module Immigrant
39
39
  end
40
40
 
41
41
  def model_classes
42
- classes = []
43
- ActiveRecord::Base.descendants.each do |model|
44
- classes << model.name.constantize
45
- end
46
- classes
42
+ ActiveRecord::Base.descendants
47
43
  end
48
44
 
49
45
  def model_keys(classes)
@@ -113,6 +109,7 @@ module Immigrant
113
109
  end
114
110
 
115
111
  def infer_belongs_to_keys(klass, reflection)
112
+ return [] if reflection.name == :left_side # redundant and unusable reflection automagically created by HABTM
116
113
  [
117
114
  Foreigner::ConnectionAdapters::ForeignKeyDefinition.new(
118
115
  klass.table_name,
data/test/helper.rb CHANGED
@@ -2,7 +2,7 @@ require 'rubygems'
2
2
  require 'bundler/setup'
3
3
  Bundler.require(:default)
4
4
 
5
- require 'test/unit'
5
+ require 'minitest/autorun'
6
6
  require 'active_record'
7
7
 
8
8
  require 'foreigner'
@@ -17,15 +17,16 @@ class ImmigrantTest < ActiveSupport::TestCase
17
17
  if ActiveRecord::VERSION::STRING >= '4.'
18
18
  # support old 3.x syntax for the sake of concise tests
19
19
  [:belongs_to, :has_one, :has_many, :has_and_belongs_to_many].each do |method|
20
- instance_eval <<-CODE
21
- def self.#{method}(assoc, options = {})
22
- args = [assoc]
23
- scope = options.extract!(:conditions, :order)
24
- if scope
25
- args.push lambda{ where(scope[:conditions]).order(scope[:order]) }
20
+ instance_eval <<-CODE, __FILE__, __LINE__ + 1
21
+ def self.#{method}(assoc, scope = nil, options = {})
22
+ if scope.is_a?(Hash)
23
+ options = scope
24
+ scope_opts = options.extract!(:conditions, :order)
25
+ scope = if scope_opts && scope_opts.present?
26
+ lambda{ |_| where(scope_opts[:conditions]).order(scope_opts[:order]) }
27
+ end
26
28
  end
27
- args.push options
28
- super *args
29
+ super assoc, scope, options
29
30
  end
30
31
  CODE
31
32
  end
@@ -44,18 +45,30 @@ class ImmigrantTest < ActiveSupport::TestCase
44
45
  def teardown
45
46
  subclasses = ActiveSupport::DescendantsTracker.direct_descendants(MockModel)
46
47
  subclasses.each do |subclass|
47
- ImmigrantTest.send(:remove_const, subclass.to_s.sub(/.*::/, ''))
48
+ Object.send(:remove_const, subclass.to_s)
48
49
  end
49
50
  subclasses.replace([])
51
+ # also need to clear out other things under AR::Base, because as of
52
+ # 4.1 there are automagical anonymous classes due to HABTM
53
+ subclasses = ActiveSupport::DescendantsTracker.direct_descendants(ActiveRecord::Base)
54
+ subclasses.replace([MockModel])
55
+ end
56
+
57
+ def given(code)
58
+ # ugly little hack to get these temp classes not namespaced, so
59
+ # that generated HM/BT from HABTM will find the right class
60
+ Object.class_eval code
50
61
  end
51
62
 
52
63
  # basic scenarios
53
64
 
54
65
  test 'belongs_to should generate a foreign key' do
55
- class Author < MockModel; end
56
- class Book < MockModel
57
- belongs_to :guy, :class_name => 'Author', :foreign_key => 'author_id'
58
- end
66
+ given <<-CODE
67
+ class Author < MockModel; end
68
+ class Book < MockModel
69
+ belongs_to :guy, :class_name => 'Author', :foreign_key => 'author_id'
70
+ end
71
+ CODE
59
72
 
60
73
  keys = Immigrant.infer_keys([]).first
61
74
  assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
@@ -69,10 +82,12 @@ class ImmigrantTest < ActiveSupport::TestCase
69
82
  end
70
83
 
71
84
  test 'has_one should generate a foreign key' do
72
- class Author < MockModel
73
- has_one :piece_de_resistance, :class_name => 'Book', :order => "id DESC"
74
- end
75
- class Book < MockModel; end
85
+ given <<-CODE
86
+ class Author < MockModel
87
+ has_one :piece_de_resistance, :class_name => 'Book', :order => "id DESC"
88
+ end
89
+ class Book < MockModel; end
90
+ CODE
76
91
 
77
92
  keys = Immigrant.infer_keys([]).first
78
93
  assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
@@ -86,10 +101,12 @@ class ImmigrantTest < ActiveSupport::TestCase
86
101
  end
87
102
 
88
103
  test 'has_one :dependent => :delete should generate a foreign key with :dependent => :delete' do
89
- class Author < MockModel
90
- has_one :book, :order => "id DESC", :dependent => :delete
91
- end
92
- class Book < MockModel; end
104
+ given <<-CODE
105
+ class Author < MockModel
106
+ has_one :book, :order => "id DESC", :dependent => :delete
107
+ end
108
+ class Book < MockModel; end
109
+ CODE
93
110
 
94
111
  keys = Immigrant.infer_keys([]).first
95
112
  assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
@@ -103,10 +120,12 @@ class ImmigrantTest < ActiveSupport::TestCase
103
120
  end
104
121
 
105
122
  test 'has_many should generate a foreign key' do
106
- class Author < MockModel
107
- has_many :babies, :class_name => 'Book'
108
- end
109
- class Book < MockModel; end
123
+ given <<-CODE
124
+ class Author < MockModel
125
+ has_many :babies, :class_name => 'Book'
126
+ end
127
+ class Book < MockModel; end
128
+ CODE
110
129
 
111
130
  keys = Immigrant.infer_keys([]).first
112
131
  assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
@@ -120,10 +139,12 @@ class ImmigrantTest < ActiveSupport::TestCase
120
139
  end
121
140
 
122
141
  test 'has_many :dependent => :delete_all should generate a foreign key with :dependent => :delete' do
123
- class Author < MockModel
124
- has_many :books, :dependent => :delete_all
125
- end
126
- class Book < MockModel; end
142
+ given <<-CODE
143
+ class Author < MockModel
144
+ has_many :books, :dependent => :delete_all
145
+ end
146
+ class Book < MockModel; end
147
+ CODE
127
148
 
128
149
  keys = Immigrant.infer_keys([]).first
129
150
  assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
@@ -137,10 +158,12 @@ class ImmigrantTest < ActiveSupport::TestCase
137
158
  end
138
159
 
139
160
  test 'has_and_belongs_to_many should generate two foreign keys' do
140
- class Author < MockModel
141
- has_and_belongs_to_many :fans
142
- end
143
- class Fan < MockModel; end
161
+ given <<-CODE
162
+ class Author < MockModel
163
+ has_and_belongs_to_many :fans
164
+ end
165
+ class Fan < MockModel; end
166
+ CODE
144
167
 
145
168
  keys = Immigrant.infer_keys([]).first
146
169
  assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
@@ -158,10 +181,12 @@ class ImmigrantTest < ActiveSupport::TestCase
158
181
  end
159
182
 
160
183
  test 'has_and_belongs_to_many should respect the join_table' do
161
- class Author < MockModel
162
- has_and_belongs_to_many :fans, :join_table => :lols_wuts
163
- end
164
- class Fan < MockModel; end
184
+ given <<-CODE
185
+ class Author < MockModel
186
+ has_and_belongs_to_many :fans, :join_table => :lols_wuts
187
+ end
188
+ class Fan < MockModel; end
189
+ CODE
165
190
 
166
191
  keys = Immigrant.infer_keys([]).first
167
192
  assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
@@ -179,13 +204,15 @@ class ImmigrantTest < ActiveSupport::TestCase
179
204
  end
180
205
 
181
206
  test 'conditional has_one/has_many associations should ignore :dependent' do
182
- class Author < MockModel
183
- has_many :articles, :conditions => "published", :dependent => :delete_all
184
- has_one :favorite_book, :class_name => 'Book',
185
- :conditions => "most_awesome", :dependent => :delete
186
- end
187
- class Book < MockModel; end
188
- class Article < MockModel; end
207
+ given <<-CODE
208
+ class Author < MockModel
209
+ has_many :articles, :conditions => "published", :dependent => :delete_all
210
+ has_one :favorite_book, :class_name => 'Book',
211
+ :conditions => "most_awesome", :dependent => :delete
212
+ end
213
+ class Book < MockModel; end
214
+ class Article < MockModel; end
215
+ CODE
189
216
 
190
217
  keys = Immigrant.infer_keys([]).first
191
218
  assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
@@ -203,13 +230,15 @@ class ImmigrantTest < ActiveSupport::TestCase
203
230
  end
204
231
 
205
232
  test 'primary_key should be respected' do
206
- class User < MockModel
207
- has_many :emails, :primary_key => :email, :foreign_key => :to,
208
- :dependent => :destroy
209
- end
210
- class Email < MockModel
211
- belongs_to :user, :primary_key => :email, :foreign_key => :to
212
- end
233
+ given <<-CODE
234
+ class User < MockModel
235
+ has_many :emails, :primary_key => :email, :foreign_key => :to,
236
+ :dependent => :destroy
237
+ end
238
+ class Email < MockModel
239
+ belongs_to :user, :primary_key => :email, :foreign_key => :to
240
+ end
241
+ CODE
213
242
 
214
243
  keys = Immigrant.infer_keys([]).first
215
244
  assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
@@ -225,11 +254,13 @@ class ImmigrantTest < ActiveSupport::TestCase
225
254
  # (no) duplication
226
255
 
227
256
  test 'STI should not generate duplicate foreign keys' do
228
- class Company < MockModel; end
229
- class Employee < MockModel
230
- belongs_to :company
231
- end
232
- class Manager < Employee; end
257
+ given <<-CODE
258
+ class Company < MockModel; end
259
+ class Employee < MockModel
260
+ belongs_to :company
261
+ end
262
+ class Manager < Employee; end
263
+ CODE
233
264
 
234
265
  assert(Manager.reflections.present?)
235
266
  keys = Immigrant.infer_keys([]).first
@@ -244,12 +275,14 @@ class ImmigrantTest < ActiveSupport::TestCase
244
275
  end
245
276
 
246
277
  test 'complementary associations should not generate duplicate foreign keys' do
247
- class Author < MockModel
248
- has_many :books
249
- end
250
- class Book < MockModel
251
- belongs_to :author
252
- end
278
+ given <<-CODE
279
+ class Author < MockModel
280
+ has_many :books
281
+ end
282
+ class Book < MockModel
283
+ belongs_to :author
284
+ end
285
+ CODE
253
286
 
254
287
  keys = Immigrant.infer_keys([]).first
255
288
  assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
@@ -263,12 +296,14 @@ class ImmigrantTest < ActiveSupport::TestCase
263
296
  end
264
297
 
265
298
  test 'redundant associations should not generate duplicate foreign keys' do
266
- class Author < MockModel
267
- has_many :books
268
- has_many :favorite_books, :class_name => 'Book', :conditions => "awesome"
269
- has_many :bad_books, :class_name => 'Book', :conditions => "amateur_hour"
270
- end
271
- class Book < MockModel; end
299
+ given <<-CODE
300
+ class Author < MockModel
301
+ has_many :books
302
+ has_many :favorite_books, :class_name => 'Book', :conditions => "awesome"
303
+ has_many :bad_books, :class_name => 'Book', :conditions => "amateur_hour"
304
+ end
305
+ class Book < MockModel; end
306
+ CODE
272
307
 
273
308
  keys = Immigrant.infer_keys([]).first
274
309
  assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
@@ -297,13 +332,15 @@ class ImmigrantTest < ActiveSupport::TestCase
297
332
  )
298
333
  ]
299
334
 
300
- class Author < MockModel
301
- has_many :articles
302
- has_one :favorite_book, :class_name => 'Book',
303
- :conditions => "most_awesome"
304
- end
305
- class Book < MockModel; end
306
- class Article < MockModel; end
335
+ given <<-CODE
336
+ class Author < MockModel
337
+ has_many :articles
338
+ has_one :favorite_book, :class_name => 'Book',
339
+ :conditions => "most_awesome"
340
+ end
341
+ class Book < MockModel; end
342
+ class Article < MockModel; end
343
+ CODE
307
344
 
308
345
  keys = Immigrant.infer_keys(database_keys).first
309
346
  assert_equal([], keys)
@@ -311,15 +348,17 @@ class ImmigrantTest < ActiveSupport::TestCase
311
348
 
312
349
  if ActiveRecord::VERSION::STRING < '4.'
313
350
  test 'finder_sql associations should not generate foreign keys' do
314
- class Author < MockModel
315
- has_many :books, :finder_sql => <<-SQL
316
- SELECT *
317
- FROM books
318
- WHERE author_id = \#{id}
319
- ORDER BY RANDOM() LIMIT 5'
320
- SQL
321
- end
322
- class Book < MockModel; end
351
+ given <<-CODE
352
+ class Author < MockModel
353
+ has_many :books, :finder_sql => <<-SQL
354
+ SELECT *
355
+ FROM books
356
+ WHERE author_id = \\\#{id}
357
+ ORDER BY RANDOM() LIMIT 5'
358
+ SQL
359
+ end
360
+ class Book < MockModel; end
361
+ CODE
323
362
 
324
363
  keys = Immigrant.infer_keys([]).first
325
364
  assert_equal([], keys)
@@ -327,33 +366,37 @@ class ImmigrantTest < ActiveSupport::TestCase
327
366
  end
328
367
 
329
368
  test 'polymorphic associations should not generate foreign keys' do
330
- class Property < MockModel
331
- belongs_to :owner, :polymorphic => true
332
- end
333
- class Person < MockModel
334
- has_many :properties, :as => :owner
335
- end
336
- class Corporation < MockModel
337
- has_many :properties, :as => :owner
338
- end
369
+ given <<-CODE
370
+ class Property < MockModel
371
+ belongs_to :owner, :polymorphic => true
372
+ end
373
+ class Person < MockModel
374
+ has_many :properties, :as => :owner
375
+ end
376
+ class Corporation < MockModel
377
+ has_many :properties, :as => :owner
378
+ end
379
+ CODE
339
380
 
340
381
  keys = Immigrant.infer_keys([]).first
341
382
  assert_equal([], keys)
342
383
  end
343
384
 
344
385
  test 'has_many :through should not generate foreign keys' do
345
- class Author < MockModel
346
- has_many :authors_fans
347
- has_many :fans, :through => :authors_fans
348
- end
349
- class AuthorsFan < MockModel
350
- belongs_to :author
351
- belongs_to :fan
352
- end
353
- class Fan < MockModel
354
- has_many :authors_fans
355
- has_many :authors, :through => :authors_fans
356
- end
386
+ given <<-CODE
387
+ class Author < MockModel
388
+ has_many :authors_fans
389
+ has_many :fans, :through => :authors_fans
390
+ end
391
+ class AuthorsFan < MockModel
392
+ belongs_to :author
393
+ belongs_to :fan
394
+ end
395
+ class Fan < MockModel
396
+ has_many :authors_fans
397
+ has_many :authors, :through => :authors_fans
398
+ end
399
+ CODE
357
400
 
358
401
  keys = Immigrant.infer_keys([]).first
359
402
  assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
@@ -371,11 +414,13 @@ class ImmigrantTest < ActiveSupport::TestCase
371
414
  end
372
415
 
373
416
  test 'broken associations should not cause errors' do
374
- class Author < MockModel; end
375
- class Book < MockModel
376
- belongs_to :author
377
- belongs_to :invalid
378
- end
417
+ given <<-CODE
418
+ class Author < MockModel; end
419
+ class Book < MockModel
420
+ belongs_to :author
421
+ belongs_to :invalid
422
+ end
423
+ CODE
379
424
 
380
425
  keys = Immigrant.infer_keys([]).first
381
426
  assert_nothing_raised { keys.map { |key| key.to_ruby(:add) } }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: immigrant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.7
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-03-10 00:00:00.000000000 Z
12
+ date: 2014-04-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -48,16 +48,13 @@ description: Adds a generator for creating a foreign key migration based on your
48
48
  email: jenseng@gmail.com
49
49
  executables: []
50
50
  extensions: []
51
- extra_rdoc_files:
52
- - README.rdoc
51
+ extra_rdoc_files: []
53
52
  files:
54
53
  - LICENSE.txt
55
54
  - Rakefile
56
- - README.rdoc
55
+ - README.md
57
56
  - lib/generators/USAGE
58
57
  - lib/generators/immigration_generator.rb
59
- - lib/generators/templates/immigration-pre-3.1.rb
60
- - lib/generators/templates/immigration.rb
61
58
  - lib/immigrant/foreign_key_definition.rb
62
59
  - lib/immigrant/loader.rb
63
60
  - lib/immigrant/railtie.rb
data/README.rdoc DELETED
@@ -1,41 +0,0 @@
1
- = Immigrant
2
- {<img src="https://secure.travis-ci.org/jenseng/immigrant.png?rvm=1.9.3" />}[http://travis-ci.org/jenseng/immigrant]
3
-
4
- Immigrant gives {Foreigner}[https://github.com/matthuhiggins/foreigner] a
5
- migration generator so you can effortlessly add missing foreign keys. This is
6
- particularly helpful when you decide to add keys to an established Rails app.
7
-
8
- Like Foreigner, Immigrant requires Rails 3.0 or greater.
9
-
10
- == Installation
11
-
12
- Add the following to your Gemfile:
13
-
14
- gem 'immigrant'
15
-
16
- == Usage
17
-
18
- rails generate immigration AddKeys
19
-
20
- This will create a migration named AddKeys which will have add_foreign_key
21
- statements for any missing foreign keys. Immigrant infers missing ones by
22
- evaluating the associations in your models (e.g. belongs_to, has_many, etc.).
23
- Only missing keys will be added; existing ones will never be altered or
24
- removed.
25
-
26
- == Considerations
27
-
28
- If the data in your tables is bad, then the migration will fail to run
29
- (obviously). IOW, ensure you don't have orphaned records *before* you try to
30
- add foreign keys.
31
-
32
- == Known Issues
33
-
34
- Immigrant currently only looks for foreign keys in ActiveRecord::Base's
35
- database. So if a model is using a different database connection and it has
36
- foreign keys, Immigrant will incorrectly include them again in the generated
37
- migration.
38
-
39
- == License
40
-
41
- Copyright (c) 2013 Jon Jensen, released under the MIT license
@@ -1,13 +0,0 @@
1
- class <%= migration_class_name %> < ActiveRecord::Migration
2
- def self.up
3
- <% @keys.each do |key| -%>
4
- <%= key.to_ruby(:add) %>
5
- <%- end -%>
6
- end
7
-
8
- def self.down
9
- <% @keys.each do |key| -%>
10
- <%= key.to_ruby(:remove) %>
11
- <%- end -%>
12
- end
13
- end
@@ -1,7 +0,0 @@
1
- class <%= migration_class_name %> < ActiveRecord::Migration
2
- def change
3
- <% @keys.each do |key| -%>
4
- <%= key.to_ruby(:add) %>
5
- <%- end -%>
6
- end
7
- end