2

다른 테이블에 깨진 레코드가있는 레거시 데이터베이스에 Rails 3.2 앱을 구축하고 있습니다. 가장 골치 아픈 문제 중 하나는 잘못된 날짜가 포함되어 있다는 것입니다.정상적으로 "Mysql2 :: Error : 잘못된 날짜"를 ActiveRecord에서 처리하는 방법은 무엇입니까?

나는 코드를 작동시키기 위해 수동으로 한 번 수정 한 샌드 박스를 설정했습니다. 이제 배포시기입니다. 이러한 이유 때문에 매일 밤 샌드 박스가 다시 설정되고 실제 데이터베이스에서 복사되고 흰 족제비 색인이 다시 작성되며 마이그레이션이 다시 적용됩니다. 실시간 설치에 배포하기 전에 마지막 수정 사항을 얻기 위해 샌드 박스에 자주 배포하려고합니다.

레거시 PHP 응용 프로그램과이 새로운 Rails 응용 프로그램을 몇 주에서 몇 달 동안 병렬로 실행해야하므로 날짜를 한 번만 수정하면됩니다 (업데이트 :). 동시에 같은 데이터베이스). 이 작업을 자동화하는 방법이 필요합니다. 아마도 마이그레이션이나 레이크 작업을해야 할 것입니다.

하지만 문제는 ActiveRecord가 이러한 레코드를로드 할 때 질식하므로 레코드를 조사하고 날짜를 수정하는 방법이 없습니다.

두 번째 문제는 PHP 코드가 트랜잭션을 사용하지 않고 일부 코드 경로가 손상되어 고아와 깨진 테이블 제약 조건이 남아 있기 때문에 레거시 데이터베이스에 불일치가 있다는 것입니다. 나는 그것들을 처리 할 것이고, 그들 대부분은 이미 모델에서 돌보고있다. 첫 번째 문제는 날짜와 관련이 있습니다.

대체 어떻게 해결할 예정입니까? 어쩌면 예외를 가로 채고 일부 try-to-fix 코드를 실행하여 깨진 레코드가있는 레거시 데이터베이스를 마이그레이션 할 수있는 마법의 보석 일 수도 있습니다 ...

마이그레이션 경로는 MySQL과 3 개의 프로덕션 환경 (라이브 데이터베이스 , 동일한 데이터베이스로 스테이징, 매일 밤 데이터베이스 복제본을 재설정하는 샌드 박스). 우리는 하나의 단계에서 전체 레거시 애플리케이션을 대체 할 수 없기 때문에 일회성 데이터 매핑/마이그레이션을하지 않기로 결정했습니다 (약 50000 개의 기사가 담긴 CMS, 수 백 개의 주제, 이미지 및 다운로드가 포함 된 거대한 파일 데이터베이스, 약 10 개의 웹 사이트 지원 , 약 12 ​​년간의 데이터 및 작업, 다양한 프로그래밍 기술의 까다로운 PHP 코드, 다른 마이그레이션 단계의 코드 중복, 파트너 사이트의 RSS 콘텐츠 가져 오기 등이 포함 된 기사/게시물을 해당 애플리케이션의 주제 기사 타임 라인으로 가져오고 훨씬 더 재미있는 것들 ...

첫 번째 단계는 일관된 관리자 및 게시 인터페이스를 얻기 위해 백엔드 응용 프로그램을 마이그레이션하는 것입니다. 레거시 프론트 엔드 응용 프로그램은 여전히 ​​데이터베이스에 작성해야합니다 (방문자가 작성한 주석 및 기타 컨텐츠). 데이터베이스를 수정하는 프로세스는 정기적으로 무인으로 실행할 수 있어야합니다. .

우리는 이미 belongs_to 및 has_many에서 손상된 모델 종속성을 정상적으로 처리하는 수정 프로그램을 가지고 있습니다. Paperclip 통합은 모든 환상적인 파일 이름 매핑이 작동하도록 설계되었습니다. 그리고 airbrake gem은 redmine 설치시 모든 응용 프로그램 충돌을보고하므로 모든 왼쪽 변덕을 간략하게 살펴볼 수 있습니다.

레거시 응용 프로그램은 최신 MySQL 버전에서 작동하도록 이미 수정되었으며 현재 MySQL 데이터베이스 서버로 마이그레이션되었습니다.

답변

-1

나는 그것이 예를 들어, 문제 Date.parse()

를 해결할 생각 Date.parse (foo.created_at)

+0

아니, 실제로는되지 않습니다. Article.find (article_with_broken_date) 예외가 발생하므로 날짜를 수정하고 레코드를 다시 저장할 기회가 없습니다. – hurikhan77

0

데이터 변환 및 수정과 같은 필요한 모든 변환 및 수정을 수행하는 데이터 가져 오기 레이크 작업을 만들고 레거시 응용 프로그램에서 최신 업데이트를 얻을 때마다이를 실행하십시오. 이 작업은 원시 SQL (look-up "execute"및 "exec_query"메소드)을 사용할 수 있지만 모델에서 작동 할 필요는 없습니다. 이것은 당신이 찾고 있던 마법의 "보석"이 될 것입니다. 분명한 데이터의 모든 경우가 고유하기 때문에 당연히, 당신은 그것을위한 모든 도구를 가질 수 없습니다. 하지만 새로운 코드베이스에 klugege를 만들지 마십시오.

+0

워크 플로우를 잘 이해하고 있는지 확실하지 않습니다. 내가 원하지 않는 것은 데이터를 임포트하는 것이다. 기존 앱과 Rails 앱은 병렬로 실행되기 때문에 동일한 데이터베이스를 동시에 사용해야하며 기존부터 현대까지 단계별로 유연한 마이그레이션을 수행하고 있습니다. "실행"과 "exec_query"로 작업하는 것이 효과적 일지 모르지만, 제 의견으로는 그것이 바로 kludge입니다. 내 모델을 사용하여 깨진 데이터에 액세스하고 모델에 구현 된 로직으로 스스로 수정하도록해야합니다. – hurikhan77

+0

원본 메시지에서 두 응용 프로그램이 동일한 데이터베이스를 공유해야한다는 것은 분명하지 않았습니다. 또는 나는 오해를했다. 그렇다면 내 솔루션이 분명히 작동하지 않습니다. 그러나 모델을 "논리로 구현 된 깨진 데이터를 수정"하는 데 강하게 반대합니다. 모델에 포함 된 논리는 비즈니스 논리에 관한 것이어야하며 깨진 데이터에 대한 해킹 및 해결 방법이 아닙니다. 그 kludges가 쌓일 것이기 때문에, 당신의 비즈니스 논리를 오염시키고 결국 코드를 ​​이해하기 어렵게 만듭니다. 그런 식으로하지 말 것을 제안합니다 :-) –

+0

실제로, 그것은 원본 메시지에 포함되어 있습니다 : "레거시 PHP 응용 프로그램과이 새로운 Rails 응용 프로그램을 몇 주에서 몇 달 동안 병렬로 실행해야하므로 우리는 날짜를 한 번만 수정하면됩니다. "- 그러나 나는 그것을 수정하여 더 명확 해졌습니다. 내 모델의 로직은 오래된 DB의 오류로 우아하게 디자인되었습니다 (코드에서 가정에서 누락 된 정보를 즉석에서 추측 할 수 있습니다). 날짜는 동일합니다 (사실 offline_at과 같은 날짜입니다). 0000-00-00 16:30은 online_at 상태와 같은 날에 오프라인 상태가된다는 것을 의미합니다. 예전의 PHP 코드는 이러한 경우를 코드에서 처리합니다. – hurikhan77

2

나는 동일한 문제가있었습니다. 이 솔루션은 다음과 같이 캐스팅을 수행하지 mysql2에게했다 :

client.query(sql, cast: false).each do |row| 
    row['some_date'] = Date.parse(row['some_date']) rescue(nil) 
end 

클라이언트 오브젝트를 구축하는 방법에 대한 자세한 내용은 mysql2 documentation를 참조하십시오. 필요한 경우 ActiveRecord::Base.configurations을 통해 rails db config에 액세스하십시오.

+1

성가 시지만 유망한 것처럼 보입니다. – hurikhan77

+0

@ hurikhan77 mysql2에 날짜를 타입 변환하지 말라는 문제를 해결합니다. 그러면 정상적으로 구조하고 유효하지 않은 날짜를 nil로 설정할 수 있습니다. 어떻게 성가신 일 이니? 그것이 나를 위해했던 것처럼 당신의 문제를 해결한다면 이것을 정확하게 표시하십시오. – Zubin

+0

프로젝트를 테스트하자 마자 해결 된 것으로 표시합니다.BTW, "성가신"부정적인 의미가 아니므로, "원시 AR 사용에 비해 복잡한"로 읽어주십시오. 특히 SQL 명령을 쓰지 않으려 고합니다. AR 내의 typecasting을 중지 할 수있는 방법이 있기를 바랍니다. – hurikhan77

0

유사 항목 : Rails: How to handle existing invalid dates in database? 및 정답이 없으므로 아래에서 내 솔루션을 다시 게시하십시오. 거짓, 예를 들면 :

나는 나를 위해 일한 가장 간단한 해결책은 에 database.yml을 파일 쓰기 캐스트를 설정하는 생각 개발 섹션

development 
    <<: *default 
    adapter: mysql2  
    (... some other settings ...) 
    cast: false