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
時は、connection
を recorder
に書き換えて
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