Как распознать направление миграции (вверх или вниз) с миграциями стиля Rails 3 (определение изменения)? - PullRequest
25 голосов
/ 06 октября 2011

Мне очень нравится миграция в стиле Rails 3, то есть один метод change достаточно умен, чтобы распознавать, выполняется ли миграция или выполняется откат, поэтому мне не нужно писать методы зеркалирования up и downдруг с другом.Но у меня есть ситуация, когда мне нужно пропустить некоторый код при откате миграции (обновление counter_cache столбцов, которые я добавляю).

Я посмотрел на http://guides.rubyonrails.org/migrations.html, но примеры в конце раздела 5 страдают от той же проблемы:

class AddFuzzToProduct < ActiveRecord::Migration
  class Product < ActiveRecord::Base
  end
  def change
    add_column :products, :fuzz, :string
    Product.reset_column_information
    Product.all.each { |f| f.update_attributes! :fuzz => 'fuzzy' }
  end
end

Когда откат переносится, обновление fuzz поле не обязательно.Есть ли способ предотвратить это?

Я попытался изучить Product.column_names, но так как Rails достаточно умен, чтобы выполнить миграцию в обратном направлении, обновление выполняется до удаления столбца.Кроме того, когда метод change определен, любые методы up или down, похоже, игнорируются.Есть другие идеи?

Ответы [ 4 ]

62 голосов
/ 29 июля 2013

Просто для дальнейшего использования, для Rails 4 лучший способ сделать это - использовать reversible:

def change
  # ...change code...

  reversible do |dir|
    dir.up do
      # ...up-only code...
    end
  end
end

См. http://guides.rubyonrails.org/migrations.html#using-reversible

20 голосов
/ 06 октября 2011

В этом случае, я думаю, вам придется использовать up и down методы как обычно. Не волнуйтесь, несмотря на добавление change в Rails 3, эти методы, насколько я знаю, не привязаны к блоку прерывания. Продолжайте использовать их там, где это необходимо.

Редактировать: Вот вариант: Переопределить migrate.

class AddFuzzToProduct < ActiveRecord::Migration
  class Product < ActiveRecord::Base
  end

  def change
    add_column :products, :fuzz, :string
  end

  def migrate(direction)
    super # Let Rails do its thing as usual...

    if direction == :up # ...but then do something extra if we're going 'up.'
      Product.reset_column_information
      Product.all.each { |f| f.update_attributes! :fuzz => 'fuzzy' }
    end
  end
end

Мысли

19 голосов
/ 09 июля 2014

В рельсах 3.x вы также можете сделать это

class AddFuzzToProduct < ActiveRecord::Migration
  class Product < ActiveRecord::Base
  end
  def change
    add_column :products, :fuzz, :string
    unless reverting?
      # Do this only when direction is up
      Product.reset_column_information
      Product.all.each { |f| f.update_attributes! :fuzz => 'fuzzy' }
    end
  end
end
0 голосов
/ 04 февраля 2013

Вот неприятная мысль: @connection - это CommandRecorder при падении.

def change
    add_column :products, :fuzz, :string
    unless @connection.kind_of?(ActiveRecord::Migration::CommandRecorder)
        Product.reset_column_information
        Product.all.each { |f| f.update_attributes! :fuzz => 'fuzzy' }
    end
end

Не пробовал. Очевидно, что вы находитесь за пределами Rails API, поэтому он может сломаться в любое время.

Если бы только метод изменения имел законный способ определения направления миграции ...

...