Як змінити нульовий стовпчик на нульовий під час міграції Rails?


188

Я створив стовпець дати в попередній міграції і встановив його на нуль. Тепер я хочу змінити його, щоб він не мінявся. Як мені це зробити, якщо в цій базі даних є нульові рядки? Я все добре, встановивши ці стовпці на Time.now, якщо вони наразі недійсні.

Відповіді:


204

Якщо ви робите це під час міграції, ви, ймовірно, можете це зробити так:

# Make sure no null value exist
MyModel.where(date_column: nil).update_all(date_column: Time.now)

# Change the column to not allow null
change_column :my_models, :date_column, :datetime, null: false

1
Лише зауваження, адже це змусило мене розбити базу даних розробників. Швидше за все використовувати явний синтаксис хеш, як це: MyModel.update_all({:date_column => Time.now}, {:date_column => nil}). Запит у вашій оригінальній формі щойно зробив усі мої моделі нульовими значеннями в полі.
— dimitarvp

Дякуємо за оновлення. Я знаю, що це було не так, коли я писав цю відповідь, але не можу пригадати, яку версію Ruby чи RoR я використовував у той час.
— DanneManne

1
Чи є у вас метод "вгору" / "вниз" для цієї міграції чи ви можете просто змінити метод міграції?
— EE33

2
changeМетод не так підходить для цього випадку , тому що (1) update_allметод буде виконуватися на обох мігрують і потенційного Revert. Це може бути не найгірше, але через те, що (2) міграція не може дізнатися, з чого змінився стовпчик при потенційному поверненні. Так що за цей випадок я б дотримувався upі down.
— DanneManne

2
Для всіх, хто цікавиться, моя відповідь показує, як це зробити за один крок.
— Рік Сміт

167

У Rails 4 це краще (DRYer) рішення:

change_column_null :my_models, :date_column, false

Щоб упевнитись, NULLщо в цьому стовпці немає записів зі значеннями, ви можете передати четвертий параметр, який є типовим значенням для записів із NULLзначеннями:

change_column_null :my_models, :date_column, false, Time.now

4
Це спричиняє проблеми, коли в таблиці вже є нульові значення. Дивіться мою відповідь
— Рік Сміт

5
Також доступний в 3.2. Має і 4-й параметр для встановлення за замовчуванням, де значення є нульовим.
— toxaq

1
Плюс 1 за change_column_null. Однак коментар Ріка Сміта вказує на дуже вагомий випадок.
— 0112

Оновлено, щоб додати запит на оновлення нульових значень. Четвертий параметр (значення за замовчуванням) корисний лише тоді, коли ви дійсно хочете мати за замовчуванням також і майбутні записи.
— мрбрдо

3
Насправді, згідно з документами Rails 4.2, 4-й парам НЕ встановлює значення за замовчуванням для майбутніх записів: "Метод приймає необов'язковий четвертий аргумент для заміни існуючих + NULL + s на якесь інше значення. Зауважте, що четвертий аргумент не встановлюється стовпець за замовчуванням. "
— Майк Фішер

70

Rails 4 (інші відповіді на Rails 4 мають проблеми):

def change
  change_column_null(:users, :admin, false, <put a default value here> )
  # change_column(:users, :admin, :string, :default => "")
end

Зміна стовпця зі значеннями NULL, щоб не допустити NULL, спричинить проблеми. Це саме той тип коду, який буде добре працювати в налаштуваннях вашої розробки, а потім виходить з ладу при спробі розгорнути його у виробництво LIVE . Спочатку слід змінити значення NULL на щось дійсне, а потім заборонити NULL. Четверте значення у change_column_nullробить саме це. Детальнішу інформацію див. У документації .

Крім того, я, як правило, віддаю перевагу встановити значення поля за замовчуванням для поля, тому мені не потрібно вказувати значення поля кожного разу, коли я створюю новий об'єкт. Я включив коментований код, щоб зробити це також.


3
Для Rails 4 це, як видається, є найточнішою та найповнішою відповіддю, включаючи налаштування за замовчуванням, коментовані за замовчуванням.
— Майк Фішер

4
Якщо ви додаєте новий стовпець у таблицю і хочете вставити нові значення для null, але не хочете додавати значення стовпця за замовчуванням, це можна зробити під час міграції: add_column :users, :admin, :stringтодіchange_column_null(:admin, :string, false, "new_value_for_existing_records")
— colsen

34

Створіть міграцію, яка має change_columnвислів зі :default =>значенням.

change_column :my_table, :my_column, :integer, :default => 0, :null => false

Див .: change_column

Залежно від двигуна бази даних, можливо, вам доведеться використовувати change_column_null


1
Це працювало для мене. Використання MySql локально. При натисканні та запуску програми в Heroku (Postgres) вона вибилася на стовпчик, який не був нульовим, коли я писав це нуль - справедливо. Тільки "change_column_null" працював би не міг використовувати "change_column ...: null => false" на MySql. Дякую.
— rtfminc

1
тож якою була ваша міграція після change_column_null
— js111

1
Повідомлення більш суворі, ніж MySQL - я б очікував, що це зажадає change_column_null.
— 1212 року

3
@rtfminc Я настійно рекомендую використовувати один і той же механізм баз даних у розробці та на виробництві, оскільки це дозволяє уникнути багатьох проблем, коли справа стосується кращих справ.
— yagooar


3

У Rails 4.02+ за документами немає такого способу, як update_all2 аргументи. Натомість можна використовувати цей код:

# Make sure no null value exist
MyModel.where(date_column: nil).update_all(date_column: Time.now)

# Change the column to not allow null
change_column :my_models, :date_column, :datetime, null: false

2

Ви не можете використовувати add_timestamps та null: false, якщо у вас є існуючі записи, ось ось таке рішення:

def change
  add_timestamps(:buttons, null: true)

  Button.find_each { |b| b.update(created_at: Time.zone.now, updated_at: Time.zone.now) }

  change_column_null(:buttons, :created_at, false)
  change_column_null(:buttons, :updated_at, false)
end
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.