good_migrations 0.0.2 → 0.1.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.
Files changed (41) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ruby.yml +32 -0
  3. data/.gitignore +0 -1
  4. data/CHANGELOG.md +10 -0
  5. data/Gemfile +1 -1
  6. data/Gemfile.lock +113 -0
  7. data/LICENSE.txt +1 -1
  8. data/README.md +21 -3
  9. data/Rakefile +3 -2
  10. data/example/Gemfile +5 -5
  11. data/example/Rakefile +2 -2
  12. data/example/app/assets/config/manifest.js +0 -0
  13. data/example/app/models/pant.rb +0 -1
  14. data/example/bin/rails +4 -0
  15. data/example/bin/rake +4 -0
  16. data/example/config.ru +1 -1
  17. data/example/config/application.rb +7 -2
  18. data/example/config/boot.rb +13 -11
  19. data/example/config/environment.rb +1 -1
  20. data/example/config/environments/development.rb +3 -3
  21. data/example/config/environments/production.rb +1 -1
  22. data/example/config/environments/test.rb +2 -2
  23. data/example/config/initializers/secret_token.rb +1 -1
  24. data/example/config/initializers/session_store.rb +1 -1
  25. data/example/db/migrate/20160202162849_create_pants.rb +1 -1
  26. data/example/db/migrate/20160202163803_change_pants.rb +2 -1
  27. data/example/db/migrate/20160202182520_change_pants_dangerously.rb +1 -1
  28. data/example/lib/tasks/load_pants.rake +5 -0
  29. data/example/script/rails +3 -3
  30. data/example/test/performance/browsing_test.rb +3 -3
  31. data/example/test/test_helper.rb +2 -2
  32. data/good_migrations.gemspec +16 -15
  33. data/lib/good_migrations.rb +2 -0
  34. data/lib/good_migrations/load_error.rb +1 -1
  35. data/lib/good_migrations/patches_autoloader.rb +63 -0
  36. data/lib/good_migrations/prevents_app_load.rb +48 -0
  37. data/lib/good_migrations/railtie.rb +1 -1
  38. data/lib/good_migrations/version.rb +1 -1
  39. data/tasks/good_migrations.rake +9 -54
  40. metadata +39 -17
  41. data/.travis.yml +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 05eb20b7481ddae6720347b0c84275997ff53e72
4
- data.tar.gz: b7c85f764f8f2c22a3988517f2c272cdb59d0016
2
+ SHA256:
3
+ metadata.gz: 957989ed1010171743f14af193d62b5bfbb820e59ad79b42ca16d6b8b51ca948
4
+ data.tar.gz: 89dc256beca58029d4de2c142834a3069b7b165959055bc4f7ab1721ffea6c82
5
5
  SHA512:
6
- metadata.gz: b79f08edebb75e97c2358064c31d8c5d2de7e4cb483b5e4f7e61a4fe04b6550156c271995249af7327a66b1f5767269830ec0fe01b7144a4fcaa6a257d244689
7
- data.tar.gz: 285bfb5be43c16860c0e6bff42c5e024d24199d4a9a84e9de1f946d04a979bbac87156c0603124c87aac80aecef81f0cd47690daf699bf27c73f2770ad0465fc
6
+ metadata.gz: 5a2e09ff0b2bf6473ececfa8ca0905eae9a974cd81ff5ea76626e7b5e56693169040472a577551aa44976e2d412e957043a31d47e0ca12b405c8b30a16f506cc
7
+ data.tar.gz: f2b50907f8826e6c76c03b933a1571b5b523ebb7087ab4854fddb300c27d5ba64d5f75e53f2d5639234bd8de07adff2702ceb0ae61d37744fcd7737ccb0c3323
@@ -0,0 +1,32 @@
1
+ # This workflow uses actions that are not certified by GitHub.
2
+ # They are provided by a third-party and are governed by
3
+ # separate terms of service, privacy policy, and support
4
+ # documentation.
5
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
+
8
+ name: Ruby
9
+
10
+ on:
11
+ push:
12
+ branches: [ main ]
13
+ pull_request:
14
+ branches: [ main ]
15
+
16
+ jobs:
17
+ test:
18
+
19
+ runs-on: ubuntu-latest
20
+ strategy:
21
+ matrix:
22
+ ruby-version: ['2.7', '3.0']
23
+
24
+ steps:
25
+ - uses: actions/checkout@v2
26
+ - name: Set up Ruby
27
+ uses: ruby/setup-ruby@v1
28
+ with:
29
+ ruby-version: ${{ matrix.ruby-version }}
30
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
31
+ - name: Run tests
32
+ run: bundle exec rake
data/.gitignore CHANGED
@@ -1,6 +1,5 @@
1
1
  /.bundle/
2
2
  /.yardoc
3
- /Gemfile.lock
4
3
  /_yardoc/
5
4
  /coverage/
6
5
  /doc/
data/CHANGELOG.md ADDED
@@ -0,0 +1,10 @@
1
+ # CHANGELOG
2
+
3
+ ## 0.1.0
4
+
5
+ * Add support for zeitwerk@2.5 & higher
6
+ * Disable the autoloader patch after migrations finish
7
+
8
+ ## 0.0.2
9
+
10
+ * Support classic autoloader
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in good_migrations.gemspec
4
4
  gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,113 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ good_migrations (0.1.0)
5
+ activerecord (>= 3.1)
6
+ railties (>= 3.1)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ actionpack (6.1.4)
12
+ actionview (= 6.1.4)
13
+ activesupport (= 6.1.4)
14
+ rack (~> 2.0, >= 2.0.9)
15
+ rack-test (>= 0.6.3)
16
+ rails-dom-testing (~> 2.0)
17
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
18
+ actionview (6.1.4)
19
+ activesupport (= 6.1.4)
20
+ builder (~> 3.1)
21
+ erubi (~> 1.4)
22
+ rails-dom-testing (~> 2.0)
23
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
24
+ activemodel (6.1.4)
25
+ activesupport (= 6.1.4)
26
+ activerecord (6.1.4)
27
+ activemodel (= 6.1.4)
28
+ activesupport (= 6.1.4)
29
+ activesupport (6.1.4)
30
+ concurrent-ruby (~> 1.0, >= 1.0.2)
31
+ i18n (>= 1.6, < 2)
32
+ minitest (>= 5.1)
33
+ tzinfo (~> 2.0)
34
+ zeitwerk (~> 2.3)
35
+ ast (2.4.2)
36
+ builder (3.2.4)
37
+ coderay (1.1.3)
38
+ concurrent-ruby (1.1.9)
39
+ crass (1.0.6)
40
+ erubi (1.10.0)
41
+ i18n (1.8.10)
42
+ concurrent-ruby (~> 1.0)
43
+ loofah (2.10.0)
44
+ crass (~> 1.0.2)
45
+ nokogiri (>= 1.5.9)
46
+ method_source (1.0.0)
47
+ mini_portile2 (2.5.3)
48
+ minitest (5.14.4)
49
+ nokogiri (1.11.7)
50
+ mini_portile2 (~> 2.5.0)
51
+ racc (~> 1.4)
52
+ parallel (1.20.1)
53
+ parser (3.0.1.1)
54
+ ast (~> 2.4.1)
55
+ pry (0.14.1)
56
+ coderay (~> 1.1)
57
+ method_source (~> 1.0)
58
+ racc (1.5.2)
59
+ rack (2.2.3)
60
+ rack-test (1.1.0)
61
+ rack (>= 1.0, < 3)
62
+ rails-dom-testing (2.0.3)
63
+ activesupport (>= 4.2.0)
64
+ nokogiri (>= 1.6)
65
+ rails-html-sanitizer (1.3.0)
66
+ loofah (~> 2.3)
67
+ railties (6.1.4)
68
+ actionpack (= 6.1.4)
69
+ activesupport (= 6.1.4)
70
+ method_source
71
+ rake (>= 0.13)
72
+ thor (~> 1.0)
73
+ rainbow (3.0.0)
74
+ rake (13.0.3)
75
+ regexp_parser (2.1.1)
76
+ rexml (3.2.5)
77
+ rubocop (1.17.0)
78
+ parallel (~> 1.10)
79
+ parser (>= 3.0.0.0)
80
+ rainbow (>= 2.2.2, < 4.0)
81
+ regexp_parser (>= 1.8, < 3.0)
82
+ rexml
83
+ rubocop-ast (>= 1.7.0, < 2.0)
84
+ ruby-progressbar (~> 1.7)
85
+ unicode-display_width (>= 1.4.0, < 3.0)
86
+ rubocop-ast (1.7.0)
87
+ parser (>= 3.0.1.1)
88
+ rubocop-performance (1.11.2)
89
+ rubocop (>= 1.7.0, < 2.0)
90
+ rubocop-ast (>= 0.4.0)
91
+ ruby-progressbar (1.11.0)
92
+ standard (1.1.2)
93
+ rubocop (= 1.17.0)
94
+ rubocop-performance (= 1.11.2)
95
+ thor (1.1.0)
96
+ tzinfo (2.0.4)
97
+ concurrent-ruby (~> 1.0)
98
+ unicode-display_width (2.0.0)
99
+ zeitwerk (2.4.2)
100
+
101
+ PLATFORMS
102
+ ruby
103
+
104
+ DEPENDENCIES
105
+ bundler
106
+ good_migrations!
107
+ minitest
108
+ pry
109
+ rake
110
+ standard
111
+
112
+ BUNDLED WITH
113
+ 2.2.15
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2016 Test Double, LLC
3
+ Copyright (c) 2016-2021 Test Double, Inc.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of
6
6
  this software and associated documentation files (the "Software"), to deal in
data/README.md CHANGED
@@ -1,14 +1,16 @@
1
1
  # good_migrations
2
2
 
3
- [![Build Status](https://travis-ci.org/testdouble/good-migrations.svg?branch=master)](https://travis-ci.org/testdouble/good-migrations)
4
-
5
3
  This gem prevents Rails from auto-loading app code while it's running migrations,
6
4
  preventing the common mistake of referencing ActiveRecord models from migration
7
5
  code.
8
6
 
9
7
  ## Usage
10
8
 
11
- Add good_migrations to your gemfile:
9
+ **HEADS UP: zeitwerk 2.5.0 is not yet released, so if you're using zeitwerk at
10
+ all, the gem won't be able to ensure your migrations are safe and you'll see a
11
+ warning to that effect**
12
+
13
+ Add good_migrations to your Gemfile:
12
14
 
13
15
  ``` ruby
14
16
  gem 'good_migrations'
@@ -16,6 +18,15 @@ gem 'good_migrations'
16
18
 
17
19
  And you're done! That's it.
18
20
 
21
+ ## Prerequisites
22
+
23
+ This gem requires that your app uses either of these autoloader strategies:
24
+
25
+ * The classic `ActiveSupport::Dependencies` autoloader (e.g. `config.autoloader
26
+ = :classic`), which is going away with Rails 7
27
+ * Version 2.5 or higher of the zeitwerk autoloader (e.g. `config.autoloader =
28
+ :zeitwerk`) If your app uses an earlier version of zeitwerk, you'll see a
29
+ warning every time `db:migrate` is run
19
30
 
20
31
  ## Background
21
32
 
@@ -63,3 +74,10 @@ have a few options:
63
74
  Credit for figuring out where to hook into the ActiveSupport autoloader goes
64
75
  to [@tenderlove](https://github.com/tenderlove) for [this
65
76
  gist](https://gist.github.com/tenderlove/44447d1b1e466a28eb3f).
77
+
78
+ ## Caveats
79
+
80
+ Because this gem works by monkey-patching the ActiveSupport auto-loader, it will
81
+ not work if your Rails environment (development, by default) is configured to
82
+ eager load your application's classes (see:
83
+ [config.eager_load](http://edgeguides.rubyonrails.org/configuring.html#rails-general-configuration)).
data/Rakefile CHANGED
@@ -1,10 +1,11 @@
1
1
  require "bundler/gem_tasks"
2
2
  require "rake/testtask"
3
+ require "standard/rake"
3
4
 
4
5
  Rake::TestTask.new(:test) do |t|
5
6
  t.libs << "test"
6
7
  t.libs << "lib"
7
- t.test_files = FileList['test/**/*_test.rb']
8
+ t.test_files = FileList["test/**/*_test.rb"]
8
9
  end
9
10
 
10
- task :default => :test
11
+ task default: ["standard:fix", :test]
data/example/Gemfile CHANGED
@@ -1,9 +1,9 @@
1
- source 'http://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
- rails_version = ENV['RAILS_VERSION'] || '3.1.0'
4
- gem 'rails', rails_version
3
+ gem "rails", "~> 6.1"
5
4
 
6
- gem 'good_migrations', :path => '..'
5
+ gem "good_migrations", path: ".."
7
6
 
8
- gem 'sqlite3-ruby', :require => 'sqlite3'
7
+ gem "sqlite3"
9
8
 
9
+ gem "zeitwerk", github: "fxn/zeitwerk"
data/example/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
1
  # Add your own tasks in files placed in lib/tasks ending in .rake,
2
2
  # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
3
 
4
- require File.expand_path('../config/application', __FILE__)
5
- require 'rake'
4
+ require File.expand_path("../config/application", __FILE__)
5
+ require "rake"
6
6
 
7
7
  Example::Application.load_tasks
File without changes
@@ -1,3 +1,2 @@
1
1
  class Pant < ActiveRecord::Base
2
2
  end
3
-
data/example/bin/rails ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ APP_PATH = File.expand_path("../config/application", __dir__)
3
+ require_relative "../config/boot"
4
+ require "rails/commands"
data/example/bin/rake ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative "../config/boot"
3
+ require "rake"
4
+ Rake.application.run
data/example/config.ru CHANGED
@@ -1,4 +1,4 @@
1
1
  # This file is used by Rack-based servers to start the application.
2
2
 
3
- require ::File.expand_path('../config/environment', __FILE__)
3
+ require ::File.expand_path("../config/environment", __FILE__)
4
4
  run Example::Application
@@ -1,6 +1,6 @@
1
- require File.expand_path('../boot', __FILE__)
1
+ require File.expand_path("../boot", __FILE__)
2
2
 
3
- require 'rails/all'
3
+ require "rails/all"
4
4
 
5
5
  # If you have a Gemfile, require the gems listed there, including any gems
6
6
  # you've limited to :test, :development, or :production.
@@ -8,6 +8,9 @@ Bundler.require(:default, Rails.env) if defined?(Bundler)
8
8
 
9
9
  module Example
10
10
  class Application < Rails::Application
11
+ if config.respond_to?("eager_load=")
12
+ config.eager_load = false
13
+ end
11
14
  # Settings in config/environments/* take precedence over those specified here.
12
15
  # Application configuration should go into files in config/initializers
13
16
  # -- all .rb files in that directory are automatically loaded.
@@ -38,5 +41,7 @@ module Example
38
41
 
39
42
  # Configure sensitive parameters which will be filtered from the log file.
40
43
  config.filter_parameters += [:password]
44
+
45
+ config.autoloader = ENV["AUTOLOADER"] == "zeitwerk" ? :zeitwerk : :classic
41
46
  end
42
47
  end
@@ -1,13 +1,15 @@
1
- require 'rubygems'
1
+ require "rubygems"
2
2
 
3
3
  # Set up gems listed in the Gemfile.
4
- gemfile = File.expand_path('../../Gemfile', __FILE__)
5
- begin
6
- ENV['BUNDLE_GEMFILE'] = gemfile
7
- require 'bundler'
8
- Bundler.setup
9
- rescue Bundler::GemNotFound => e
10
- STDERR.puts e.message
11
- STDERR.puts "Try running `bundle install`."
12
- exit!
13
- end if File.exist?(gemfile)
4
+ gemfile = File.expand_path("../../Gemfile", __FILE__)
5
+ if File.exist?(gemfile)
6
+ begin
7
+ ENV["BUNDLE_GEMFILE"] = gemfile
8
+ require "bundler"
9
+ Bundler.setup
10
+ rescue Bundler::GemNotFound => e
11
+ warn e.message
12
+ warn "Try running `bundle install`."
13
+ exit!
14
+ end
15
+ end
@@ -1,5 +1,5 @@
1
1
  # Load the rails application
2
- require File.expand_path('../application', __FILE__)
2
+ require File.expand_path("../application", __FILE__)
3
3
 
4
4
  # Initialize the rails application
5
5
  Example::Application.initialize!
@@ -10,8 +10,7 @@ Example::Application.configure do
10
10
  config.whiny_nils = true
11
11
 
12
12
  # Show full error reports and disable caching
13
- config.consider_all_requests_local = true
14
- config.action_view.debug_rjs = true
13
+ config.consider_all_requests_local = true
15
14
  config.action_controller.perform_caching = false
16
15
 
17
16
  # Don't care if the mailer can't send
@@ -22,5 +21,6 @@ Example::Application.configure do
22
21
 
23
22
  # Only use best-standards-support built into browsers
24
23
  config.action_dispatch.best_standards_support = :builtin
25
- end
26
24
 
25
+ config.active_record.migration_error = false
26
+ end
@@ -6,7 +6,7 @@ Example::Application.configure do
6
6
  config.cache_classes = true
7
7
 
8
8
  # Full error reports are disabled and caching is turned on
9
- config.consider_all_requests_local = false
9
+ config.consider_all_requests_local = false
10
10
  config.action_controller.perform_caching = true
11
11
 
12
12
  # Specifies the header that your server uses for sending files
@@ -11,14 +11,14 @@ Example::Application.configure do
11
11
  config.whiny_nils = true
12
12
 
13
13
  # Show full error reports and disable caching
14
- config.consider_all_requests_local = true
14
+ config.consider_all_requests_local = true
15
15
  config.action_controller.perform_caching = false
16
16
 
17
17
  # Raise exceptions instead of rendering exception templates
18
18
  config.action_dispatch.show_exceptions = false
19
19
 
20
20
  # Disable request forgery protection in test environment
21
- config.action_controller.allow_forgery_protection = false
21
+ config.action_controller.allow_forgery_protection = false
22
22
 
23
23
  # Tell Action Mailer not to deliver emails to the real world.
24
24
  # The :test delivery method accumulates sent emails in the
@@ -4,4 +4,4 @@
4
4
  # If you change this key, all old signed cookies will become invalid!
5
5
  # Make sure the secret is at least 30 characters and all random,
6
6
  # no regular words or you'll be exposed to dictionary attacks.
7
- Example::Application.config.secret_token = '5b687ab969ef4f33a41125ae95e73c368d1c391045639df9a1690221b13f8b8cbeb515db9cf5990548af5c309b8d3ab206648837001866cdf854278030285e3c'
7
+ Example::Application.config.secret_token = "5b687ab969ef4f33a41125ae95e73c368d1c391045639df9a1690221b13f8b8cbeb515db9cf5990548af5c309b8d3ab206648837001866cdf854278030285e3c"
@@ -1,6 +1,6 @@
1
1
  # Be sure to restart your server when you modify this file.
2
2
 
3
- Example::Application.config.session_store :cookie_store, :key => '_example_session'
3
+ Example::Application.config.session_store :cookie_store, key: "_example_session"
4
4
 
5
5
  # Use the database for sessions instead of the cookie-based default,
6
6
  # which shouldn't be used to store highly confidential information
@@ -1,4 +1,4 @@
1
- class CreatePants < ActiveRecord::Migration
1
+ class CreatePants < ActiveRecord::Migration[4.2]
2
2
  def change
3
3
  create_table :pants do |t|
4
4
  t.integer :length
@@ -1,6 +1,7 @@
1
- class ChangePants < ActiveRecord::Migration
1
+ class ChangePants < ActiveRecord::Migration[4.2]
2
2
  class Pant < ActiveRecord::Base
3
3
  end
4
+
4
5
  def change
5
6
  Pant.all.each do |pant|
6
7
  # do a migration depending on the redefined Pant model
@@ -1,4 +1,4 @@
1
- class ChangePantsDangerously < ActiveRecord::Migration
1
+ class ChangePantsDangerously < ActiveRecord::Migration[4.2]
2
2
  def up
3
3
  Pant.find_each do |pant|
4
4
  # uh oh!
@@ -0,0 +1,5 @@
1
+ # Imagine this being run immediately after a migrate, and SHOULD be allowed
2
+ # to load from app/ because it's not a migration
3
+ task load_pants: :environment do
4
+ puts "This many pants: #{Pant.count} pants"
5
+ end
data/example/script/rails CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
3
 
4
- APP_PATH = File.expand_path('../../config/application', __FILE__)
5
- require File.expand_path('../../config/boot', __FILE__)
6
- require 'rails/commands'
4
+ APP_PATH = File.expand_path("../../config/application", __FILE__)
5
+ require File.expand_path("../../config/boot", __FILE__)
6
+ require "rails/commands"
@@ -1,9 +1,9 @@
1
- require 'test_helper'
2
- require 'rails/performance_test_help'
1
+ require "test_helper"
2
+ require "rails/performance_test_help"
3
3
 
4
4
  # Profiling results for each test method are written to tmp/performance.
5
5
  class BrowsingTest < ActionDispatch::PerformanceTest
6
6
  def test_homepage
7
- get '/'
7
+ get "/"
8
8
  end
9
9
  end
@@ -1,6 +1,6 @@
1
1
  ENV["RAILS_ENV"] = "test"
2
- require File.expand_path('../../config/environment', __FILE__)
3
- require 'rails/test_help'
2
+ require File.expand_path("../../config/environment", __FILE__)
3
+ require "rails/test_help"
4
4
 
5
5
  class ActiveSupport::TestCase
6
6
  # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
@@ -1,28 +1,29 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
1
+ lib = File.expand_path("../lib", __FILE__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'good_migrations/version'
3
+ require "good_migrations/version"
5
4
 
6
5
  Gem::Specification.new do |spec|
7
- spec.name = "good_migrations"
8
- spec.version = GoodMigrations::VERSION
9
- spec.authors = ["Justin Searls", "Kevin Baribeau"]
10
- spec.email = ["searls@gmail.com", "kevin.baribeau@gmail.com"]
6
+ spec.name = "good_migrations"
7
+ spec.version = GoodMigrations::VERSION
8
+ spec.authors = ["Justin Searls", "Kevin Baribeau"]
9
+ spec.email = ["searls@gmail.com", "kevin.baribeau@gmail.com"]
11
10
 
12
- spec.summary = %q{Prevents Rails from auto-loading app code in database migrations}
13
- spec.description = %q{Referencing code in app/ from a database migration risks breaking the migration when your app code changes; this gem prevents that mistake}
14
- spec.homepage = "https://github.com/testdouble/good-migrations"
11
+ spec.summary = "Prevents Rails from auto-loading app code in database migrations"
12
+ spec.description = "Referencing code in app/ from a database migration risks breaking the migration when your app code changes; this gem prevents that mistake"
13
+ spec.homepage = "https://github.com/testdouble/good-migrations"
14
+ spec.license = "MIT"
15
15
 
16
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
- spec.bindir = "exe"
18
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = "exe"
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_dependency "railties", ">= 3.1"
22
22
  spec.add_dependency "activerecord", ">= 3.1"
23
23
 
24
- spec.add_development_dependency "bundler", "~> 1.10"
25
- spec.add_development_dependency "rake", "~> 10.0"
24
+ spec.add_development_dependency "bundler"
25
+ spec.add_development_dependency "rake"
26
26
  spec.add_development_dependency "minitest"
27
27
  spec.add_development_dependency "pry"
28
+ spec.add_development_dependency "standard"
28
29
  end
@@ -1,3 +1,5 @@
1
1
  require "good_migrations/version"
2
2
  require "good_migrations/load_error"
3
+ require "good_migrations/patches_autoloader"
4
+ require "good_migrations/prevents_app_load"
3
5
  require "good_migrations/railtie" if defined?(Rails)
@@ -1,4 +1,4 @@
1
1
  module GoodMigrations
2
- class LoadError < ::LoadError
2
+ class LoadError < RuntimeError
3
3
  end
4
4
  end
@@ -0,0 +1,63 @@
1
+ module GoodMigrations
2
+ class PatchesAutoloader
3
+ def self.instance
4
+ @instance ||= new
5
+ end
6
+
7
+ def initialize
8
+ @disabled = false
9
+ end
10
+
11
+ def disabled?
12
+ @disabled
13
+ end
14
+
15
+ def patch!
16
+ if Rails.singleton_class.method_defined?(:autoloaders) &&
17
+ Rails.autoloaders.zeitwerk_enabled?
18
+ if Rails.autoloaders.main.respond_to?(:on_load) &&
19
+ Rails.autoloaders.main.method(:on_load).arity <= 0
20
+ @disabled = false
21
+ Rails.autoloaders.each do |loader|
22
+ loader.on_load do |_, _, path|
23
+ if GoodMigrations::PreventsAppLoad.app_path?(path) &&
24
+ !GoodMigrations::PatchesAutoloader.instance.disabled?
25
+ GoodMigrations::PreventsAppLoad.prevent_load!(path)
26
+ end
27
+ end
28
+ end
29
+ else
30
+ warn <<~UNSUPPORTED
31
+ WARNING: good_migrations is unable to ensure that your migrations are
32
+ not inadvertently loading application code, because your application
33
+ uses the zeitwerk autoloader (`config.autoloader = :zeitwerk`), but
34
+ is using a version prior to zeitwerk 2.5.0, which adds an on_load
35
+ hook that good_migrations can latch onto.
36
+
37
+ Solution: Ensure that zeitwerk isn't pinned below 2.5.0 in your
38
+ Gemfile and try running `bundle update zeitwerk`.
39
+
40
+ UNSUPPORTED
41
+ end
42
+ else
43
+ @disabled = false
44
+ ActiveSupport::Dependencies.class_eval do
45
+ extend Module.new {
46
+ def load_file(path, const_paths = loadable_constants_for_path(path))
47
+ if GoodMigrations::PreventsAppLoad.app_path?(path) &&
48
+ !GoodMigrations::PatchesAutoloader.instance.disabled?
49
+ GoodMigrations::PreventsAppLoad.prevent_load!(path)
50
+ else
51
+ super
52
+ end
53
+ end
54
+ }
55
+ end
56
+ end
57
+ end
58
+
59
+ def unpatch!
60
+ @disabled = true
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,48 @@
1
+ module GoodMigrations
2
+ class PreventsAppLoad
3
+ def self.app_path?(path)
4
+ path.starts_with? File.join(Rails.application.root, "app")
5
+ end
6
+
7
+ def self.prevent_load!(path)
8
+ raise GoodMigrations::LoadError, <<~ERROR
9
+ Rails attempted to auto-load:
10
+
11
+ #{path}
12
+
13
+ Which is in your project's `app/` directory. The good_migrations
14
+ gem was designed to prevent this, because migrations are intended
15
+ to be immutable and safe-to-run for the life of your project, but
16
+ code in `app/` is liable to change at any time.
17
+
18
+ The most common reason for this error is that you may be referencing an
19
+ ActiveRecord model inside the migration in order to use the ActiveRecord API
20
+ to implement a data migration by querying and updating objects.
21
+
22
+ For instance, if you want to access a model "User" in your migration, it's safer
23
+ to redefine the class inside the migration instead, like this:
24
+
25
+ class MakeUsersOlder < ActiveRecord::Migration
26
+ class User < ActiveRecord::Base
27
+ # Define whatever you need on the User beyond what AR adds automatically
28
+ end
29
+
30
+ def up
31
+ User.find_each do |user|
32
+ user.update!(:age => user.age + 1)
33
+ end
34
+ end
35
+
36
+ def down
37
+ #...
38
+ end
39
+ end
40
+
41
+ For more information, visit:
42
+
43
+ https://github.com/testdouble/good-migrations
44
+
45
+ ERROR
46
+ end
47
+ end
48
+ end
@@ -3,7 +3,7 @@ require "active_record/railtie"
3
3
  module GoodMigrations
4
4
  class Railtie < Rails::Railtie
5
5
  rake_tasks do
6
- Dir[File.join(File.dirname(__FILE__), '../../tasks/*.rake')].each do |file|
6
+ Dir[File.join(File.dirname(__FILE__), "../../tasks/*.rake")].each do |file|
7
7
  load file
8
8
  end
9
9
  end
@@ -1,3 +1,3 @@
1
1
  module GoodMigrations
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -1,63 +1,18 @@
1
- require 'active_support/dependencies'
2
- require 'good_migrations'
1
+ require "active_support/dependencies"
2
+ require "good_migrations"
3
3
 
4
4
  namespace :good_migrations do
5
5
  task :disable_autoload do
6
- next if ENV['GOOD_MIGRATIONS'] == "skip"
7
- ActiveSupport::Dependencies.class_eval do
8
- extend Module.new {
9
- def load_file(path, const_paths = loadable_constants_for_path(path))
10
- if path.starts_with? File.join(Rails.application.root, 'app')
11
- raise GoodMigrations::LoadError, <<-ERROR
12
- Rails attempted to auto-load:
13
-
14
- #{path}
15
-
16
- Which is in your project's `app/` directory. The good_migrations
17
- gem was designed to prevent this, because migrations are intended
18
- to be immutable and safe-to-run for the life of your project, but
19
- code in `app/` is liable to change at any time.
20
-
21
- The most common reason for this error is that you may be referencing an
22
- ActiveRecord model inside the migration in order to use the ActiveRecord API
23
- to implement a data migration by querying and updating objects.
24
-
25
- For instance, if you want to access a model "User" in your migration, it's safer
26
- to redefine the class inside the migration instead, like this:
27
-
28
- class MakeUsersOlder < ActiveRecord::Migration
29
- class User < ActiveRecord::Base
30
- # Define whatever you need on the User beyond what AR adds automatically
31
- end
32
-
33
- def up
34
- User.find_each do |user|
35
- user.update!(:age => user.age + 1)
36
- end
6
+ next if ENV["GOOD_MIGRATIONS"] == "skip"
7
+ GoodMigrations::PatchesAutoloader.instance.patch!
37
8
  end
38
9
 
39
- def down
40
- #...
10
+ task :reenable_autoload do
11
+ next if ENV["GOOD_MIGRATIONS"] == "skip"
12
+ GoodMigrations::PatchesAutoloader.instance.unpatch!
41
13
  end
42
14
  end
43
15
 
44
- For more information, visit:
45
-
46
- https://github.com/testdouble/good-migrations
47
-
48
- ERROR
49
- else
50
- super
51
- end
52
- end
53
- }
54
- end
55
- end
16
+ Rake::Task["db:migrate"].enhance(["good_migrations:disable_autoload"]) do
17
+ Rake::Task["good_migrations:reenable_autoload"].invoke
56
18
  end
57
-
58
- Rake.application.in_namespace('db:migrate') do |namespace|
59
- ([Rake::Task['db:migrate']] + namespace.tasks).each do |task|
60
- task.prerequisites << "good_migrations:disable_autoload"
61
- end
62
- end
63
-
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: good_migrations
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Searls
8
8
  - Kevin Baribeau
9
- autorequire:
9
+ autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2016-02-02 00:00:00.000000000 Z
12
+ date: 2021-06-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: railties
@@ -43,30 +43,30 @@ dependencies:
43
43
  name: bundler
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - "~>"
46
+ - - ">="
47
47
  - !ruby/object:Gem::Version
48
- version: '1.10'
48
+ version: '0'
49
49
  type: :development
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
- - - "~>"
53
+ - - ">="
54
54
  - !ruby/object:Gem::Version
55
- version: '1.10'
55
+ version: '0'
56
56
  - !ruby/object:Gem::Dependency
57
57
  name: rake
58
58
  requirement: !ruby/object:Gem::Requirement
59
59
  requirements:
60
- - - "~>"
60
+ - - ">="
61
61
  - !ruby/object:Gem::Version
62
- version: '10.0'
62
+ version: '0'
63
63
  type: :development
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
- - - "~>"
67
+ - - ">="
68
68
  - !ruby/object:Gem::Version
69
- version: '10.0'
69
+ version: '0'
70
70
  - !ruby/object:Gem::Dependency
71
71
  name: minitest
72
72
  requirement: !ruby/object:Gem::Requirement
@@ -95,6 +95,20 @@ dependencies:
95
95
  - - ">="
96
96
  - !ruby/object:Gem::Version
97
97
  version: '0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: standard
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
98
112
  description: Referencing code in app/ from a database migration risks breaking the
99
113
  migration when your app code changes; this gem prevents that mistake
100
114
  email:
@@ -104,9 +118,11 @@ executables: []
104
118
  extensions: []
105
119
  extra_rdoc_files: []
106
120
  files:
121
+ - ".github/workflows/ruby.yml"
107
122
  - ".gitignore"
108
- - ".travis.yml"
123
+ - CHANGELOG.md
109
124
  - Gemfile
125
+ - Gemfile.lock
110
126
  - LICENSE.txt
111
127
  - README.md
112
128
  - Rakefile
@@ -116,10 +132,13 @@ files:
116
132
  - example/Gemfile
117
133
  - example/README
118
134
  - example/Rakefile
135
+ - example/app/assets/config/manifest.js
119
136
  - example/app/controllers/application_controller.rb
120
137
  - example/app/helpers/application_helper.rb
121
138
  - example/app/models/pant.rb
122
139
  - example/app/views/layouts/application.html.erb
140
+ - example/bin/rails
141
+ - example/bin/rake
123
142
  - example/config.ru
124
143
  - example/config/application.rb
125
144
  - example/config/boot.rb
@@ -141,6 +160,7 @@ files:
141
160
  - example/db/seeds.rb
142
161
  - example/doc/README_FOR_APP
143
162
  - example/lib/tasks/.gitkeep
163
+ - example/lib/tasks/load_pants.rake
144
164
  - example/public/404.html
145
165
  - example/public/422.html
146
166
  - example/public/500.html
@@ -162,13 +182,16 @@ files:
162
182
  - good_migrations.gemspec
163
183
  - lib/good_migrations.rb
164
184
  - lib/good_migrations/load_error.rb
185
+ - lib/good_migrations/patches_autoloader.rb
186
+ - lib/good_migrations/prevents_app_load.rb
165
187
  - lib/good_migrations/railtie.rb
166
188
  - lib/good_migrations/version.rb
167
189
  - tasks/good_migrations.rake
168
190
  homepage: https://github.com/testdouble/good-migrations
169
- licenses: []
191
+ licenses:
192
+ - MIT
170
193
  metadata: {}
171
- post_install_message:
194
+ post_install_message:
172
195
  rdoc_options: []
173
196
  require_paths:
174
197
  - lib
@@ -183,9 +206,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
183
206
  - !ruby/object:Gem::Version
184
207
  version: '0'
185
208
  requirements: []
186
- rubyforge_project:
187
- rubygems_version: 2.4.5.1
188
- signing_key:
209
+ rubygems_version: 3.2.15
210
+ signing_key:
189
211
  specification_version: 4
190
212
  summary: Prevents Rails from auto-loading app code in database migrations
191
213
  test_files: []
data/.travis.yml DELETED
@@ -1,11 +0,0 @@
1
- language: ruby
2
- sudo: false
3
- rvm:
4
- - 2.2.3
5
- before_script:
6
- - cd example && bundle install
7
- env:
8
- - RAILS_ENV=3.1.0
9
- - RAILS_ENV=4.0.0
10
- - RAILS_ENV=4.2.0
11
- - RAILS_ENV=5.0.0.beta2