Подтвердить что ты не робот

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

У меня была миграция 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 перед запуском миграции.

4b9b3361

Ответ 1

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

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

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

Использование моделей в ваших миграциях в разделе Migrations Guide также может быть интересным.

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

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-значениями, третий работает.

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