• Stars
    star
    294
  • Rank 136,220 (Top 3 %)
  • Language
    Ruby
  • License
    MIT License
  • Created over 8 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Prevent Rails from auto-loading app/ code when running database migrations

good_migrations

This gem prevents Rails from auto-loading app code while it's running migrations, preventing the common mistake of referencing ActiveRecord models from migration code.

Usage

Add good_migrations to your Gemfile:

gem 'good_migrations'

And you're done! That's it.

Prerequisites

This gem requires that your app uses either of these autoloader strategies:

  • The classic ActiveSupport::Dependencies autoloader (e.g. config.autoloader = :classic), which is going away with Rails 7
  • Version 2.5 or higher of the Zeitwerk autoloader (e.g. config.autoloader = :zeitwerk) If your app uses an earlier version of zeitwerk, you'll see a warning every time db:migrate is run

Background

Over the life of your Ruby on Rails application, your app's models will change dramatically, but according to the Rails guides, your migrations shouldn't:

In general, editing existing migrations is not a good idea. You will be creating extra work for yourself and your co-workers and cause major headaches if the existing version of the migration has already been run on production machines. Instead, you should write a new migration that performs the changes you require.

That means that if your migrations reference the ActiveRecord model objects you've defined in app/models, your old migrations are likely to break. That's not good.

By adding this gem to your project's Gemfile, autoloading paths inside 'app/' while running any of the db:migrate Rake tasks will raise an error, explaining the dangers inherent.

Some will reply, "who cares if old migrations are broken? I can still run rake db:setup because I have a db/schema.rb file". The problem with this approach is that, so long as some migrations aren't runnable, the db/schema.rb can't be regenerated from scratch and its veracity can no longer be trusted. In practice, we've seen numerous projects accumulate cruft in db/schema.rb as the result of erroneous commits to work-in-progress migrations, leading to the development and test databases falling out of sync with production. That's not good!

For more background, see the last section of this blog post on healthy migration habits

Adding to an existing app

If you add good_migrations to an existing application and any of those migrations relied on auto-loading code from app/, then you'll see errors raised whenever those migrations are run.

You have several options if this happens:

  • If you're confident that every long-lasting environment has run the latest migrations, you could consider squashing your existing migrations into a single migration file that reflects the current state of your schema. This is a tricky procedure to pull off in complex apps, and can require extra coordination in cases where a high number of contributors are working on the application simultaneously. The squasher gem may be able to help.
  • You can rewrite those past migrations to inline any application code inside the migration's namespace. One way to do this is to run migrations until they fail, check out the git ref of the failing migration so the codebase is rewound to where it was at the time the migration was written, and finally inline the necessary app code to get the migration passing before checking out your primary branch. Rewriting any migration introduces risk of the resulting schema diverging from production, so this requires significant care and attention
  • If neither of the above options are feasible, you can configure the good_migrations gem to ignore migrations prior to a specified date with the permit_autoloading_before option, which will effectively disable the gem's auto-loading prevention for all migrations prior to a specified time

Configuration

To configure the gem, call GoodMigrations.config at some point as Rails is loading (a good idea would be an initializer like config/initializers/good_migrations.rb)

GoodMigrations.config do |config|
  # Setting `permit_autoloading_before` will DISABLE good_migrations for
  # any migrations before the given time. Don't set this unless you need to!
  #
  # Accepts parseable time strings as well as `Date` & `Time` objects
  # config.permit_autoloading_before = "20140728132502"
end

Working around good_migrations

The gem only prevents auto-loading, so you can always can explicitly require the app code that you need in your migration.

If needed, it is possible to run a command with good_migrations disabled by running the command with the env var GOOD_MIGRATIONS=skip.

Acknowledgements

Credit for figuring out where to hook into the ActiveSupport autoloader goes to @tenderlove for this gist. And thanks to @fxn for implementing the hook necessary for zeitwerk support to be possible.

Caveats

Because this gem works by augmenting the auto-loader, it will not work if your Rails environment (development, by default) is configured to eager load your application's classes (see: config.eager_load).

More Repositories

1

standard

๐ŸŒŸ Ruby Style Guide, with linter & automatic code fixer
Ruby
2,104
star
2

testdouble.js

A minimal test double library for TDD with JavaScript
JavaScript
1,407
star
3

suture

๐Ÿฅ A Ruby gem that helps you refactor your legacy code
Ruby
1,401
star
4

contributing-tests

1,104
star
5

scripty

Because no one should be shell-scripting inside a JSON file.
JavaScript
957
star
6

test-smells

A workbook repository of example test smells and what to do about them.
JavaScript
421
star
7

jasmine-rails

A Jasmine runner for rails projects that's got you covered in both the terminal and the browser
JavaScript
378
star
8

referral

๐Ÿ•ต๏ธโ€โ™€๏ธ Find, filter, and sort your Ruby code's definitions & references
Ruby
343
star
9

cypress-rails

Helps you write Cypress tests of your Rails app
Ruby
312
star
10

mocktail

๐Ÿฅƒ Take your Ruby, and make it a double!
Ruby
273
star
11

static-rails

Build & serve static sites (e.g. Jekyll, Hugo) from your Rails app
Ruby
149
star
12

maybe_later

Run code after the current Rack response or Rails action completes
Ruby
132
star
13

time_up

โฑ Create and manage multiple timers to tell where your Ruby code's time is going
Ruby
117
star
14

teenytest

A very simple, zero-config test runner for Node.js
JavaScript
97
star
15

test_data

A fast & reliable system for managing your Rails application's test data
Ruby
95
star
16

put

Ruby
92
star
17

theredoc

Makes your multi-line JavaScript strings look good
JavaScript
79
star
18

quibble

Makes it easy to replace require'd dependencies.
JavaScript
78
star
19

react-decoupler

JavaScript
55
star
20

noncommittal

A gem that ensures test isolation by preventing your Rails tests from committing to the database
Ruby
46
star
21

real-world-testing-video

testdouble/real-world-testing + screencasts
JavaScript
40
star
22

clojurescript.csv

A ClojureScript library for reading and writing CSV
Clojure
37
star
23

testdouble-jest

A testdouble.js extension to add support for Jest module mocking
JavaScript
37
star
24

grunt-markdown-blog

Grunt task for building a blog with markdown posts & underscore templates
CoffeeScript
36
star
25

ought

A dumb assertion library with smart diffs for JavaScript
JavaScript
34
star
26

cypress-capybara

Capybara finders re-implemented as custom Cypress commands
JavaScript
33
star
27

minitest-suite

Re-order your Minitest suite into logical sub-suites/groups
Ruby
32
star
28

rust-ffi-example

An example project that shows how to use FFI between Rust and Unity.
Rust
31
star
29

gem_dating

How old is that anyway?
Ruby
29
star
30

rspec-graphql_response

Verify ruby-graphql responses with a :graphql spec type
Ruby
25
star
31

ecto_resource

A simple module to clear up the boilerplate of CRUD resources in Phoenix context files.
Elixir
22
star
32

java-testing-example

An example project that's configured for JUnit and Mocha
Java
20
star
33

real-world-testing

Workshop for Testing JavaScripts
JavaScript
17
star
34

unusual-spending

A code kata for outside-in TDD in Node.js
JavaScript
16
star
35

webpacker-assets-demo

A demo repo to show how to reference images and styles when using Webpacker instead of Sprockets
Ruby
13
star
36

javascript-testing-tactics

The Missing Manual for writing great JavaScript Testing
13
star
37

magic_email_demo

An exampleย Rails app that implements passwordless authentication by emailing a magic link
Ruby
12
star
38

scheduled-merge

Merge PRs on a specified date using Labels
JavaScript
12
star
39

rust-ffi-complex-example

Follow-up project to shows how to use complex data structures between Unity and Rust.
Rust
12
star
40

todos

JavaScript
11
star
41

grunt-asset-fingerprint

CoffeeScript
9
star
42

covet

Instruct a remote Express app to stub APIs via HTTP requests
CoffeeScript
9
star
43

bored

Gives you ideas of stuff to do when you're bored
Ruby
8
star
44

rails-twitter-oauth-example

An example Rails app that implements log in to Twitter via OAuth
Ruby
8
star
45

javascript-tdd-examples

Yet another little toy repo of javascript tdd examples
JavaScript
8
star
46

baizen

BAI file format parser
Clojure
8
star
47

tiny_type

Fast, easy, and simple runtime type checking for Ruby
Ruby
8
star
48

halfpipe

A Pipedrive client for Ruby that doesn't do half of what you want it to ๐Ÿ›น
Ruby
7
star
49

forewarn

Configure method invocation warnings for deprecated or dangerous methods (e.g. mutable methods in default-frozen String literals in Ruby 3)
Ruby
7
star
50

grunt-jasmine-bundle

A "spec" grunt task for Jasmine that includes a standard pack of helpers (jasmine-given, jasmine-stealth, jasmine-only). Uses minijasminenode.
CoffeeScript
6
star
51

servme

gimme for integration tests
Ruby
6
star
52

intro-to-node

Introduction to Node.js Workshop
JavaScript
6
star
53

standardrb

You're probably in the wrong place. This is an alias for the gem standard, whose binary is standardrb
Ruby
6
star
54

bootboot-example

An example of using boot-boot.
Ruby
5
star
55

testdrivennode

Test Driven Node.js Precompiler for Codemash 2014
JavaScript
5
star
56

docunit

Makes sure the code examples in your docs actually work
CoffeeScript
5
star
57

railsconf-test-drive-javascript

JavaScript
5
star
58

json-to-svg-to-pdf

Converts JSON/CSON input through SVG templates and renders them to PDF using librsvg
JavaScript
5
star
59

imagemagick-macos-font-setup

Sets up user fonts for imagemagick on macOS
Shell
5
star
60

jasmine-before-all

Adds a done-friendly beforeAll global function to Jasmine
JavaScript
5
star
61

good-day

An example ember + active_model_serializers + rails + lineman app
JavaScript
5
star
62

sockem

A wrapper around the ActionCable JS client to ensure eventual delivery for requests
Ruby
5
star
63

satisfaction

Satisfaction tracker for your work!
Ruby
5
star
64

headerify

Browserify plugin to add a comment containing lib name, version, description, and homepage to the top of the bundle
JavaScript
4
star
65

SublimeLinter-contrib-standardrb

SublimeLinter 3 plugin for Ruby, using Standard, a wrapper for Rubocop.
Python
4
star
66

rails-upsert-all-demo

An example app that demos use of Rails 6 `upsert_all` method
Ruby
4
star
67

cobbler

A tool to generate rรฉsumรฉs for Test Double agents.
JavaScript
3
star
68

react-d3-blog-example

Example for Blog Post
JavaScript
3
star
69

supertitle

Converts between subtitles and transcript formats
Ruby
3
star
70

time_traveler_demo

A Rails app that demoes time traveling both Ruby and Postgres in lock-step with one another
Ruby
3
star
71

devops-standards

Standard Auditing Tools for DevSecOps best practices
Python
3
star
72

least

A pager that can dynamically filter log lines
Ruby
3
star
73

defuse

An API to define and use JavaScript in a module-y way. And nothing else.
JavaScript
3
star
74

lockify

Ensure an async function does not run concurrently.
JavaScript
3
star
75

jasmine-matcher-wrapper

A utility to wrap Jasmine 1.x argument matchers for use under Jasmine 2.x
CoffeeScript
3
star
76

testdouble-nock

JavaScript
3
star
77

teenytest-promise

Promise support for asynchronous teenytest tests
JavaScript
3
star
78

npm-tree

Generates a tree of all the node.js modules depended on by a module
CoffeeScript
3
star
79

function-names-at-line

Name the functions found at a particular line number in some JavaScript source
JavaScript
2
star
80

tradecraft

CSS
2
star
81

course-cypress-intro-demo-app

Demo application to supplement Test Double's End-to-end Testing with Cypress intro video course
Ruby
2
star
82

standard-ruby-action

Ruby
2
star
83

rails-training-201

A demo app for Rails 201 students to build on!
Ruby
2
star
84

testdrivennode-frontend

JavaScript
2
star
85

yslow-grader

A little Node.js wrapper for YSlow for PhantomJS
CoffeeScript
2
star
86

ios-learnins

Objective-C
2
star
87

fetcher

Fetches things based on a JSON recipe hosted in a repository
CoffeeScript
2
star
88

backbone-fixins

Boilerplate that strengthens your backbone
JavaScript
2
star
89

ruby_rails_training_github

Ruby
1
star
90

prioritize-api

Elixir
1
star
91

baruco2014-angular

Ruby
1
star
92

oredev2014-angular

JavaScript
1
star
93

double-up

Slack scheduler to set up rotating brunch pairings
Ruby
1
star
94

elm-testdouble

A minimal test double library for TDD with Elm
Elm
1
star
95

doubot

test double's hubot
CoffeeScript
1
star
96

jasmine-example

JavaScript
1
star
97

arg-that

arg-that makes it easier to assert equality on complex objects
Ruby
1
star
98

react-routing-example

Example for screencast on client-side routing in React
CSS
1
star
99

cucumber-peel

Provides a CLI to search a project's step implementations for a given step
Ruby
1
star
100

test_rails_app

A starter Rails application to test your environment setup
Ruby
1
star