настройка миграции рельсов логическое поле не работает - PullRequest
0 голосов
/ 28 октября 2018

У меня есть миграция, которая добавляет логический столбец и устанавливает значение для некоторых строк.Новое значение не сохраняется в базе данных при сохранении модели.Вот упрощенная версия кода:

class AddSmartToStudent
  def change
    add_column :students, :smart, :boolean

    Student.where(grade: 'A').each do |student|
      student.smart = true
      student.save!
    end
   end
end

Заранее спасибо!

Ответы [ 3 ]

0 голосов
/ 28 октября 2018

В своей миграции вы добавляете логический столбец и сразу после этого используете его в модели.Не уверен, что это возможно - когда миграция еще не завершена, транзакция не зафиксирована.Модель Student может еще не иметь поля smart.

Как Луис Сильва предлагает, вы можете использовать метод reset_column_information для обновления информации о столбцах для Student.Но проблема в том, что миграции не для манипулирования данными.Если вы хотите изменить некоторые данные, это лучше сделать в задаче rake.

Если по какой-то причине вы ДОЛЖНЫ сделать это в процессе миграции, вы можете сделать это простым SQL-запросом.Для PostgreSQL это будет:

execute "UPDATE students SET smart='t' WHERE grade='A'"
0 голосов
/ 29 октября 2018

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

  1. Как утверждают другие, вы пытаетесь использовать атрибут, который вы добавляете в той же миграции.Безопасная вещь - сбросить информацию о столбце, как объяснено в ответе Луиса Сильвы .

  2. Вторая проблема связана с тем, что вы используетеdef change, где часть содержимого необратима.Все в методе изменения должно быть обратимым.В противном случае следует использовать def up и def down.

Вот два варианта, которые могут решить вашу проблему:

  1. Использование def upи def down.

    class AddSmartToStudent
      def up
        add_column :students, :smart, :boolean
    
        Student.reset_column_information
        Student
          .where(grade: 'A')
          .find_each { |student| student.update!(smart: true) }
      end
    
      def down
        remove_column :students, :smart
      end
    end
    
  2. Использование reversible.

    class AddSmartToStudent
      def change
        add_column :students, :smart, :boolean
    
        reversible do |change|
          change.up do
            Student.reset_column_information
            Student
              .where(grade: 'A')
              .find_each { |student| student.update!(smart: true) }
          end
        end
      end
    end
    

Если вы нене заботясь о обратных вызовах Rails, валидации и т. д. вы также можете использовать

Student.where(grade: 'A').update_all(smart: true)

в качестве замены

Student.where(grade: 'A').find_each { |student| student.update!(smart: true) }

Это обновляет все записи одним запросом, но не создает экземплярзаписи, то есть обратные вызовы Rails, проверки и т. д. не будут выполняться.Для получения дополнительной информации см update_all.

0 голосов
/ 28 октября 2018

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

Выполните эту строку перед предложением, где

Student.reset_column_information

reset_column_information

...