4

나는 다음과 같은 코드 블록이 : 당신이 아마 추측 할 수로, 그 여러 프로세스가 아무튼 경우 (사용자가 생성하는 동시에,이 메소드를 호출 할 수액티브 예외는 구출하지

unless User.exist?(...) 
    begin 
    user = User.new(...) 
    # Set more attributes of user 
    user.save! 
    rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique => e 
    # Check if that user was created in the meantime 
    user = User.exists?(...) 
    raise e if user.nil? 
    end 
end 

이유는,이다 't'가 이미 존재하기 때문에), 첫번째 블록이 블록에 들어가고 새로운 사용자의 초기화, 속성의 설정 그리고 마지막으로 save!를 호출하기 시작하면, 사용자는 이미 생성되었을 것이다. 그 경우에는 사용자가 존재하는지 다시 확인하고 여전히 예외가 발생하지 않는 경우에만 예외를 발생시킵니다 (= 그 동안에 다른 프로세스가 생성하지 않은 경우).

문제는 정기적으로 ActiveRecord :: RecordInvalid 예외가 저장에서 발생한다는 것입니다. 구조 블록에서 구조되지 않았습니다. 아이디어가 있으십니까?

편집 :

괜찮습니다. 이상합니다. 나는 뭔가를 놓치고 있어야합니다. 나는 같이하는 시몬의 팁에 따라 코드를 리팩토링 : 그것은 'user.save 않는'라는 라인에 던져

ActiveRecord::RecordNotUnique: Mysql::DupEntry: Duplicate entry 'f[email protected]' for key 'index_users_on_email': INSERT INTO `users` ... 

:

unless User.find_by_email(...).present? 
    # Here we know the user does not exist yet 
    user = User.new(...) 
    # Set more attributes of user 
    unless user.save 
    # User could not be saved for some reason, maybe created by another request? 
    raise StandardError, "Could not create user for order #{self.id}." unless User.exists?(:email => ...) 
    end 
end 

지금 나는 다음과 같은 예외를 얻었다. 어떻게 그럴 수 있습니까? Rails는 전자 메일이 고유하지만 MySQL 고유 인덱스가 삽입을 방지하기 때문에 사용자를 만들 수 있다고 생각합니까? 그게 얼마나 가능성이 있니? 어떻게 피할 수 있습니까?

답변

3

이 경우 사용자 테이블 키에 고유 인덱스를 작성하여 데이터베이스에서 오류가 발생할 수 있습니다.

또한 사용자 모델에 validates_uniqueness_of 유효성 검사를 추가하는 것을 잊지 마십시오.

유효성 검사가 항상 중복 데이터를 방지하지는 않습니다 (두 개의 동시 요청이 동일한 밀리 초 단위로 기록 될 가능성은 거의 없습니다). validates_uniqueness_of을 색인과 함께 사용하면 모든 코드가 필요하지 않습니다.

unless User.exist?(...) 
    begin 
    user = User.new(...) 
    # Set more attributes of user 
    user.save! 
    rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique => e 
    # Check if that user was created in the meantime 
    user = User.exists?(...) 
    raise e if user.nil? 
    end 
end 

user = User.new(...) 
# Set more attributes of user 
if user.save 
    # saved 
else 
    # user.errors will return 
    # the list of errors 
end 
+0

감사 :

는 여기에 우리의 간단한 이에 대한 링크의 페이지입니다! 나는 Devise를 인증에 사용하고 있으므로 User 모델에 고유성에 대한 유효성 검사가 포함되어 있으며 전자 메일에 고유 한 인덱스가 있습니다. 나는 내 코드를 리팩토링 할 수있다. begin user.save! 구조 ... 끝 에 다른 user.save 경우 ... 끝 하지만 난 내 원래의 질문에 더 관심이 있어요 : 왜 내 원래 캡처하지 않는 액티브 :: RecordInvalid 예외 암호? –

3

레일 검증 데이터베이스에 경쟁 조건을 감지 할 수 없습니다된다; 우리가 사용하는 솔루션은 데이터베이스 제약 조건을 추가하는 것입니다. 당신의 대답, 시몬에 대한 Rails ActiveRecord Validations: validates_uniqueness_of races

+0

내 마지막 편집에서 알 수 있듯이 내 응용 프로그램에는 데이터베이스 제약 조건이 있습니다 ... –

+0

링크 페이지를 보내 주셔서 감사합니다. 매우 유익한. – bjnord