Как написать условные миграции в рельсах? - PullRequest
20 голосов
/ 13 февраля 2011

Я ищу способы записи миграций в рельсы, которые можно выполнить для базы данных много раз без сбоев.

Например, допустим, у меня есть такая миграция:

class AddUrlToProfile < ActiveRecord::Migration
  def self.up
    add_column :profile, :url, :string
  end

  def self.down
    remove_column :profile, :url
  end
end

Если столбец url уже существует в таблице Profile (если, например, schema.rb был неожиданно изменен)), моя миграция не удастся сказать, что это дубликат!

Так как выполнить эту миграцию, только если она должна?

Спасибо

Ответы [ 4 ]

50 голосов
/ 13 февраля 2011

Вы можете сделать что-то вроде этого:

class AddUrlToProfile < ActiveRecord::Migration
  def self.up
    Profile.reset_column_information
    add_column(:profile, :url, :string) unless Profile.column_names.include?('url')

  end

  def self.down
    Profile.reset_column_information
    remove_column(:profile, :url) if Profile.column_names.include?('url')
  end
end

Это сбросит информацию о столбце до его начала - убедившись, что модель профиля имеет актуальную информацию о столбце из фактической таблицы. Затем он будет только добавить столбец, если он не существует. То же самое происходит с функцией down, но она удаляет столбец, только если он существует.

Если у вас есть несколько вариантов использования для этого, вы можете выделить код в функцию и повторно использовать его в своих миграциях.

15 голосов
/ 28 марта 2012

Для Rails 3.X , есть метод column_exists?(:table_name, :column_name).

Для Rails 2.X , вы можете проверить существование столбцов с помощью следующего:

columns("<table name>").index {|col| col.name == "<column name>"}

... или, если вы не в файле миграции:

ActiveRecord::Base.connection.columns("<table name>").index {|col| col.name == "<column name>"}

Если он возвращает nil, такой столбец не существует.Если он возвращает Fixnum, то столбец существует.Естественно, вы можете поместить более селективные параметры между {...}, если хотите идентифицировать столбец не только по его имени, например:

{ |col| col.name == "foo" and col.sql_type == "tinyint(1)" and col.primary == nil }
8 голосов
/ 13 февраля 2011

Это должно работать

def self.table_exists?(name)
  ActiveRecord::Base.connection.tables.include?(name)
end

if table_exists?(:profile) && !Profile.column_names.include?("url")
  add_column :profile, :url, :string
end
2 голосов
/ 01 февраля 2017

Обернуть мою миграцию в условно работал для меня. Рельсы 4.X

class AddUrlToProfile < ActiveRecord::Migration
  unless Profile.column_names.include?("url")
    def self.up
      add_column :profile, :url, :string
    end

    def self.down
      remove_column :profile, :url
    end
  end
end 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...