# Why does ActiveRecord still support class level migrations?

**URL:** <https://discuss.rubyonrails.org/t/why-does-activerecord-still-support-class-level-migrations/75294>\
**Category:** A May Of WTFs\
**Tags:** migrations\
**Created:** [May 21, 2020, 7:31pm UTC](https://discuss.rubyonrails.org/t/why-does-activerecord-still-support-class-level-migrations/75294 "2020-05-21T19:31:49Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![wpliao1989](https://avatars.discourse-cdn.com/v4/letter/w/65b543/32.png) [@wpliao1989](https://discuss.rubyonrails.org/u/wpliao1989)\
**Post date:** [May 21, 2020, 7:31pm UTC](https://discuss.rubyonrails.org/t/why-does-activerecord-still-support-class-level-migrations/75294/1 "2020-05-21T19:31:49Z")

</div>

So migrations look like this nowadays:

```ruby
class MyMigration < ActiveRecord::Migration
  def change
    create_table :my_table ...
  end
end

```

To my surprise, the following actually works too!

```ruby
class MyMigration < ActiveRecord::Migration
  create_table :my_table ...
end

```

This was a production bug at my company because people make mistakes and there were no automated tools to catch this error. It leads to inconsistent behavior because

1. It only gets run at the class load time
2. It can’t be rolled back

After some researching, I found that this was the way to do migrations \< Rails 3.1. And on Rails 3.1 we got instance method support: [https://github.com/rails/rails/commit/8b2f801ed8690dcbc61d62e6b3518efaac70a4a4](https://github.com/rails/rails/commit/8b2f801ed8690dcbc61d62e6b3518efaac70a4a4) but class methods were not deprecated.

My question is: what’s the best way to prevent this error from happening?

- Deprecate class method support in future Rails?
- Some custom rubocop rule?
- Some kind of automated test?

---

<div class="post-metadata">

**Author:** ![Adam\_Lassek](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/adam_lassek/32/726_2.png) [@Adam\_Lassek](https://discuss.rubyonrails.org/u/Adam_Lassek)\
**Post date:** [May 21, 2020, 10:15pm UTC](https://discuss.rubyonrails.org/t/why-does-activerecord-still-support-class-level-migrations/75294/2 "2020-05-21T22:15:22Z")

</div>

This truly is a WTF! I’ve spent a _lot_ of time digging around in exactly this area of the framework, and this still surprised me.

The old style of migrations still used `up` and `down`, but they were class methods instead. The commit you referenced is the point at which it changed to instance methods.

The fact that `create_table` works at the class level was never intentional, I don’t think. It’s a side-effect of the `method_missing` delegation to an instance of the `Migration`, which forwards `method_missing` to the database connection.

That’s necessary to allow all the migration helpers to work, but I wonder if we can’t deprecate and remove this singleton `method_missing`, or at least tighten up the message forwarding somehow.

---

<div class="post-metadata">

**Author:** ![Adam\_Lassek](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/adam_lassek/32/726_2.png) [@Adam\_Lassek](https://discuss.rubyonrails.org/u/Adam_Lassek)\
**Post date:** [May 21, 2020, 10:27pm UTC](https://discuss.rubyonrails.org/t/why-does-activerecord-still-support-class-level-migrations/75294/3 "2020-05-21T22:27:51Z")

</div>

Based on some preliminary poking around in the test suite, I think the framework would actually have to remove support for singleton `up` and `down` entirely before this could be fixed.

You have to be able to reference any schema helpers at the class level because you can still define `up` and `down` at the class level.

---

<div class="post-metadata">

**Author:** ![Betsy\_Haibel](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/betsy_haibel/32/1092_2.png) [@Betsy\_Haibel](https://discuss.rubyonrails.org/u/Betsy_Haibel)\
**Post date:** [May 22, 2020, 12:26am UTC](https://discuss.rubyonrails.org/t/why-does-activerecord-still-support-class-level-migrations/75294/4 "2020-05-22T00:26:28Z")

</div>

This one is extra wrinkly due to the backwards-compatibility needs around migrations. We could change `ActiveRecord::Migration[6.2]` to avoid this but there’s no way to remove this behavior from `ActiveRecord::Migration[5.0]`.
