

Rails初心者です。  
マイグレーションの仕組みについて教えて下さい。

以下のようなことを先輩に教えてもらいました。  
「Railsは、マイグレーションファイルとschema_migrationsテーブルを比較して  
未実行のマイグレーションを自動的に見つけて実行する」

そこで私はすでに実行されている複数のマイグレーションファイルのひとつにおいて  
以下の作業をしました。

実行前

[code]

    t.string :name
    t.string :email
    t.string :address
    
[/code]

実行後

[code]

    t.string :name
    t.string :address
    
[/code]

emailの行を削除したのです。

その上で、rake db:migrateを実行しました。

私の予想では、schema.rbにおいて、emailのカラムが削除されると思っていましたが  
結果的には変化はありませんでした。

逆に、カラムをひとつ追加しても結果は同じでした。

これはなぜでしょうか？

※カラムを追加/削除する方法として適切ではないことは知っていますが、どういう理屈なのかが知りたいのです。


CC BY-SA 3.0
2017-11-14T01:47:22.167
39554
2017-11-14T05:49:02.020
26111
question
ruby-on-rails database
migrationファイルでカラムを追加/削除してもschema.rbに反映しないのはなぜか


schema_migrationsテーブルにはマイグレーションファイルの「バージョン」部分が入っています。バージョンは、通常は
db/mgirate/タイムスタンプ_マイグレーション名.rb のタイムスタンプ部分の値。

テーブルにバージョンが入っていれば適用済みと判断されます。一方でファイルの内容や修正時刻は見ていませんので、内容を書き換えても未実行とは判断されません。

どのマイグレーションファイルが適用されるかは、 db:migrate:status タスクでも確認できます(downと表示されるもの)

スキーマ定義ファイルを書き換えると適用してくれるツールとして、 ridgepole というものもあります。


CC BY-SA 3.0
2017-11-14T02:29:50.547
39555
2017-11-14T02:29:50.547
17037
39554
answer


migration fileが、db/migrate 以下にあるのはご存知だと思います。  
migration fileには、ファイル名の頭に14桁の数字が付いていると思います。これはmigration file作成時の日時で、versionです。

railsではmigrationの管理にこのversionを使っていて、どのversionまでmigration fileが適応されたか保持してます。

現在のversionは、

[code]

    $ rails db:version
    
[/code]

で確認できます。

で、このcurrent versionよりも新しいversionのmigration fileがある状態で、

[code]

    $ rails db:migrate
    
[/code]

とすると、新しいversionのmigration fileの内容が適応されます。

* * *

しょうねんさんがいじられたmigration fileが以下のものだったとして、

[code]

    db/migrate/20171114000000_create_users.rb
    
[/code]

この時の、current versionが 20171114000000 だと、`rails
db:migrate`を何度実行しても`20171114000000_create_users.rb`に加えた変更は適応されません。

つまり、`20171114000000_create_users.rb`の変更を適応させるには、current versionが20171114000000
より古い状態で`rails db:migrate`してあげなければいけないのです。

versionを古くするには、

[code]

    rails db:rollback
    
[/code]

を実行します。  
そうすると、versionが 20171114000000 より1つ古いversionになるハズです。

この状態で、`20171114000000_create_users.rb`を編集し、再度`rails
db:migrate`すれば、`20171114000000_create_users.rb`に加えた変更はDBに適応されます。

* * *

されるハズなんですが。。。  
恐らくしょうねんさんの環境で`rails db:rollback`しようとするとerrorが出るんでは無いかと思います。  
これは、railsが`rails db:rollback`するときにもtableとmigration fileの情報をcheckしているためです。

例えば、今回のように`email:string`というcolumnを消してrollbackしようとします。  
railsは、tableをmigration fileに従って削除しようとするんですが、migration fileに情報の無いemail
columnが残ってしまいます。辻褄が合わずrailsがerrorを吐くと思います。

なので、  
・作ったときの状態にmigration fileを戻してやる  
・db:rollbackする。  
・migration fileをいじってやる。  
・db:migrateする。  
が正しい手順です。

* * *

そうは言っても、色々いじってしまっていると、元の状態がどんなんか分からなくなってしまって、正しい状態に戻すの大変ですよね。  
その場合は、以下を実行してみてください。

[code]

    rails db:migrate:reset
    
[/code]

コレを実行すると、DBをまっさらな状態にして、migration
fileを古いものから順番に全部適応してくれます。当然DBの中身は全部消えるので注意してください。

また、`rails db:migrate:reset`を実行しようとしても出来ない場合があります。  
その場合は、error内容に`bin/rails db:environment:set
RAILS_ENV=development`を実行しろとか出てると思うので、適宜実行してやってください。


CC BY-SA 3.0
2017-11-14T05:49:02.020
39562
2017-11-14T05:49:02.020
2383
39554
answer