Rails 3.1: невозможно записать в столбец в той же миграции, которая его добавляет - PullRequest
23 голосов
/ 20 января 2012

У меня была миграция add_column, которая работала бы нормально. Однако после запуска и запуска консоли я обнаружил, что столбцы first_name и last_name были полностью пустыми. Я попытался использовать save! вместо этого, и это имело тот же эффект - никаких сообщений об ошибках. Вот оригинал:

class UserAddFirstNameAndLastName < ActiveRecord::Migration
  def change
    # add column first name, last name string
    add_column :users, :first_name, :string
    add_column :users, :last_name, :string

    User.all.each do |u|
      u.first_name = 'first name'
      u.last_name = 'last name'
      u.save
    end
  end
end

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

Когда я разделил это на две миграции, желаемый эффект был достигнут. У кого-нибудь есть объяснение этому? Клянусь, я даже делал это в том же проекте с прошлыми миграциями.

Другие примечания: Разработайте для пользовательского движка, добавили новые столбцы в attr_accessible в классе User перед запуском миграции.

1 Ответ

37 голосов
/ 20 января 2012

Вы загружаете класс Users где-то перед запуском миграции, поэтому User немного запутался в своей собственной структуре.Решение заключается в вызове reset_column_information после добавления столбца:

Сбрасывает всю кэшированную информацию о столбцах, что приведет к их перезагрузке при следующем запросе.

Самым распространенным шаблоном использования этого метода, вероятно, является миграция, когда сразу после создания таблицы вы хотите заполнить ее некоторыми значениями по умолчанию

Использование моделей в вашемМиграции раздел Руководства по миграции также стоит посмотреть.

Попробуйте откатиться и использовать миграцию, как это:

def change
  # add column first name, last name string
  add_column :users, :first_name, :string
  add_column :users, :last_name, :string

  User.reset_column_information

  User.all.each do |u|
    u.first_name = 'first name'
    u.last_name = 'last name'
    u.save
  end
end

Я проверилэто с тремя миграциями, как это:

# 1: Don't touch Model before the new columns.
def change
  add_column :models, :some_column, :string
  Model.all.each { |m| m.some_column = 'pancakes'; m.save }
end

# 2: Pull in Model before adding the new columns.
def change
  puts Model.all.count
  add_column :models, :some_column, :string
  Model.all.each { |m| m.some_column = 'pancakes'; m.save }
end

# 3: Pull in Model before adding the new columns but use reset_column_information
def change
  puts Model.all.count
  add_column :models, :some_column, :string
  Model.reset_column_information
  Model.all.each { |m| m.some_column = 'pancakes'; m.save }
end

Первый работает просто отлично, второй добавляет some_column, но оставляет его со значениями NULL, третий также работает.

IПредположим, что что-то в инициализации вашего приложения (возможно, из Devise) вызывает загрузку пользователя и его схемы, а затем вы добавляете столбец.Но, видимо, пользователь только частично знает о новом столбце, так как вызов u.first_name работает, но что-то кэшируется внутри пользователя, чтобы предотвратить запись атрибута в базу данных.

...