跟踪一个简单的reversible

class TestReversible < ActiveRecord::Migration[5.1]
  def change
    binding.trace_tree(htmp: 'mig/reversible') do
      reversible do |dir|
        dir.up{ puts 'up' }
        dir.down{ puts 'down' }
      end
    end                                                                                                                                                                                                                                 
  end
end


用栈如下

20171114_225547_780_reversible.html

源码如下

# activerecord-5.1.4/lib/active_record/migration.rb
ReversibleBlockHelper = Struct.new(:reverting) do
  def up
    yield unless reverting
  end

  def down
    yield if reverting
  end
end

def reversible
  helper = ReversibleBlockHelper.new(reverting?)
  execute_block { yield helper }
end


非常简单,就是rails/rake命令使用的migrate/up/rollback/down,会保存到reverting?实例变量中(之前分析过),然后遇到reversible块时,再生成一个类似Migration的ReversibleBlockHelper,于是,就如同调用Migration的up/down一样,ReversibleBlockHelper会根据reverting?而决定调up还是down

适合于想在Migration里写change,但又有少部分操作是rails不提供inverse_of,或者改数据,或者特定于数据库语法的场景