Rails, 기존 테이블에 대한 null 제약 조건이 있는 add_reference

3479 단어 10stipsrails

(10초 꿀팁으로 코딩 문제 풀고 정신건강 예방하는 방법을 배우는 곳) 입니다.

좋은 아침 엔지니어들!
null:false 가 포함된 열을 어떻게 추가하고 기존 레코드에 기본값을 설정하지만 새 레코드가 nil에 대해 유효성이 검사되는지 확인합니다(대신 기본값이 할당됨)?

이것은 까다롭게 들리며 나는 당신의 생명을 구하기 위해 여기에 있습니다.

준비가 된?

제약조건이 null:false인 참조 추가



오늘 저는 데이터가 있는 기존 테이블에 검증된 참조 열(일명 외래 키)을 추가하고 싶었습니다. 쉬워요...

add_reference :application_users, :company, index: true, foreign_key: true, null: false


company_id 열의 설정null: false은 레코드가 항상 기본값을 가져야 하는 제약 조건을 생성합니다.

이것이 바로 내가 원했던 것입니다. 테이블이 비어 있으면 문제가 없습니다.

그러나 기존 레코드의 기본값은 어떻습니까?

위에 표시된 마이그레이션은 마이그레이션을 제공하지 않으면 실패합니다.

-- add_reference(:application_users, :company, {:null=>false, :foreign_key=>true, :index=>true})
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:

PG::NotNullViolation: ERROR:  column "company_id" contains null values

Caused by:
ActiveRecord::NotNullViolation: PG::NotNullViolation: ERROR:  column "company_id" contains null values

Caused by:
PG::NotNullViolation: ERROR:  column "company_id" contains null values


제약 조건에 의해 null이 허용되지 않고 다른 기본값이 제공되지 않으면 데이터베이스에서 결정할 다른 방법이 없습니다.

그리고 여기 흥미로운 부분이 있습니다!

기본값 추가, 적절한 방법



id가 1인 회사가 있다는 것을 확실히 알고 있는 경우 default: 1를 추가하여 기본적으로 해당 회사에 속하도록 모든 기존 레코드를 설정할 수 있습니다.

그러나 개발, 스테이징 및 프로덕션과 같은 여러 환경이 있으면 Company 모델을 사용하고 이 모델에서 값을 검색해야 합니다.

그래서, 나는 이런 식으로 하기로 결정했습니다...

default_company_id = Company.first.try(:id) || Company.create(name: 'Default company').id
add_reference :application_users, :company, index: true, foreign_key: true, null: false, default: default_company_id


하지만 아직 끝나지 않았다는 것을 알았습니다!

새 레코드가 default: default_company_id 에 할당되는 것을 원하지 않습니다. 대신 데이터베이스가 거래를 검증하고 회사가 제공되지 않으면 정상적으로 실패하기를 원합니다.

그래서 한 줄을 추가했습니다.

default_company_id = Company.first.try(:id) || Company.create(name: 'Default company').id
add_reference :application_users, :company, index: true, foreign_key: true, null: false, default: default_company_id

# set default back to nil
change_column_default :application_users, :company_id, nil


이렇게 하면 기본값이 다시 nil로 설정되고 제약 조건이 여전히 존재하므로 company_id 없이 ApplicationUser를 생성하면 예상대로 예외가 발생합니다.

엄청난! 끝났어!

중요한 참고 사항



일반적으로 마이그레이션에서 모델 클래스를 사용하는 것은 안티 패턴으로 간주됩니다.

저는 여기에서 Rails 4를 사용하고 있으며 최신 버전의 Rails에서는 ApplicationRecord에서 상속하는 익명 클래스를 만든 다음 명시적으로 다음과 같이 테이블 이름을 그룹으로 설정할 수 있습니다.

default_company_id = Class.new(ApplicationRecord)
                            .tap { |c| c.table_name = :companies }
                            .find_or_create_by(name: 'Default company')
                            .id


도움이 되었나요?

친구/동료/형제 자매와 공유하십시오.

안녕히 계세요,
중.

좋은 웹페이지 즐겨찾기