sendagaya.rb #330 rake db:rollback時のソースコードリーディング

sendagaya.rb #330 では、 rails db:rollback のときのコードを読んだ。 もとは、 @sanfrecce_osaka がきになって調べてくれていた内容

こちらで用意するmigrationファイルのchange のなかのメソッド呼び出しを行うときに rake db:migrate では、ActiveRecord::ConnectionAdapters の各adapter(下記コードでいうと connection ) をレシーバーとして実行するのにたいして、rake db:rollback 時は、connectionrecorder に書き換えて changeメソッドのなかで実行されるメソッド呼び出しをrecorderに一旦記録させて すべて記録した後に、逆の動作に変更して replay で実行しているのが面白かった。

rake db:migrate 時のchange の実行

[823, 832] in /Users/jun-fukaya/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/activerecord-6.0.3.3/lib/active_record/migration.rb
   823:       @connection = conn
   824:       if respond_to?(:change)
   825:         if direction == :down
   826:           revert { change }
   827:         else
=> 828:           change
   829:         end
   830:       else
   831:         send(direction)
   832:       end
(byebug) puts @connection
#<ActiveRecord::ConnectionAdapters::SQLite3Adapter:0x00007f9df54c8098>
nil

rake db:rollback 時の change の内容を反転させるための connection の差し替え部分 recorder.replay(self) でrecorderで記録したchangeの処理内容逆にして実行している

[689, 708] in /Users/jun-fukaya/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/activerecord-6.0.3.3/lib/active_record/migration.rb
  689:     # This command can be nested.
   690:     def revert(*migration_classes)
   691:       run(*migration_classes.reverse, revert: true) unless migration_classes.empty?
   692:       if block_given?
   693:         if connection.respond_to? :revert
   694:           connection.revert { yield }
   695:         else
   696:           recorder = command_recorder
   697:           @connection = recorder
   698:           suppress_messages do
=> 699:             connection.revert { yield }
   700:           end
   701:           @connection = recorder.delegate
   702:           recorder.replay(self)
   703:         end
   704:       end
   705:     end
(byebug) puts connection
#<ActiveRecord::Migration::CommandRecorder:0x00007f82315ccfa0>
nil
(byebug) puts recorder
#<ActiveRecord::Migration::CommandRecorder:0x00007f82315ccfa0>
nil
(byebug) puts recorder.delegate
#<ActiveRecord::ConnectionAdapters::SQLite3Adapter:0x00007f8231d1ce90>
nil
(byebug) puts @connection
#<ActiveRecord::Migration::CommandRecorder:0x00007f82315ccfa0>
nil