Rails 마이그레이션에서 nullable 열을 nullable로 변경하는 방법은 무엇입니까?


188

이전 마이그레이션에서 날짜 열을 만들어 null을 허용하도록 설정했습니다. 이제 null을 허용하지 않도록 변경하고 싶습니다. 해당 데이터베이스에 null 행이 있다고 가정하면 어떻게해야합니까? 해당 열이 현재 null 인 경우 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}). 원래 형식의 쿼리로 모든 모델의 필드 값이 0이되었습니다.
dimitarvp

업데이트 해 주셔서 감사합니다. 나는이 답변을 쓸 때 이것이 사실이 아니라는 것을 알고 있지만 당시에 사용하고있는 Ruby 또는 RoR 버전을 기억할 수 없습니다.
DanneManne

1
이 마이그레이션에서 'up'/ 'down'방법을 사용하거나 마이그레이션에서 간단한 변경 방법을 사용할 수 있습니까?
EE33

2
change방법은이 경우에 적합하지 않습니다. (1)이 update_all방법은 마이그레이션 및 잠재적 복귀 모두에서 실행 되기 때문 입니다. 최악의 상황은 아니지만 (2) 마이그레이션으로 인해 잠재적 인 되돌리기에서 열이 변경된 항목을 알 수있는 방법이 없기 때문입니다. 따라서이 경우에는 up및을 사용 down합니다.
DanneManne

2
관심있는 사람이라면 내 대답 은 한 번에 이것을 수행하는 방법을 보여줍니다.
Rick Smith

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
테이블에 이미 널값이있는 경우 문제가 발생합니다. 내 답변보기
Rick Smith

5
3.2에서도 사용 가능합니다. 값이 널인 기본값을 설정하기위한 네 번째 매개 변수도 있습니다.
toxaq

1
에 1을 더 change_column_null합니다. 그러나 위의 Rick Smith의 의견은 매우 유효한 사례를 지적합니다.
0112

null 값을 업데이트하기위한 쿼리를 추가하도록 업데이트되었습니다. 네 번째 매개 변수 (기본값)는 실제로 미래의 레코드에 대한 기본값도 갖고 자 할 때만 유용합니다.
mrbrdo

3
실제로 Rails 4.2 문서에 따르면, 4 번째 매개 변수는 미래의 레코드에 대한 기본값을 설정하지 않습니다. 열의 기본값입니다. "
Mike Fischer

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의 경우, 주석 처리 된 기본 설정을 포함하여 가장 정확하고 완전한 답변 인 것으로 보입니다.
Mike Fischer

4
테이블에 새 열을 추가하고 null에 대한 새 값을 삽입하려고하지만 열의 기본값을 추가하지 않으려는 경우 마이그레이션에서이를 수행 할 수 있습니다. add_column :users, :admin, :stringthenchange_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)에서 앱을 푸시하고 실행하면 null을 쓸 때 null이 아닌 열에 박혔습니다. MySql에서는 "change_column_null"만 작동하여 "change_column ... : null => false"를 사용할 수 없습니다. 감사.
rtfminc

1
그래서 change_column_null 이후 마이그레이션은 무엇입니까
js111

1
Postges는 MySQL보다 더 엄격합니다. 필자는 필요할 것으로 예상합니다 change_column_null.
jessecurry

3
@rtfminc 엣지 케이스와 관련하여 많은 문제를 피하기 때문에 개발 및 프로덕션에서 동일한 데이터베이스 엔진을 사용하는 것이 좋습니다.
yagooar

12

레일 4 :

def change
  change_column_null(:users, :admin, false )
end

1
답변에 대한 설명을 입력하십시오.
Wahyu Kristianto

3

에서는 레일 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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.