1

레일 5 has_many 기록을 중복 :방지는 다음과 같은 모델을 감안할 때

class Client < ApplicationRecord 
    has_many :preferences 
    validates_associated :preferences 
    accepts_nested_attributes_for :preferences 
end 

class Preference < ApplicationRecord 
    belongs_to :client 
    validates_uniqueness_of :block, scope: [:day, :client_id] 
end 

나는 아직도 클라이언트를 만드는 동안 환경의 배치를 만드는 * 중복 일에 환경을 만들 수 있어요. validates_uniqueness_of 유효성 검사를 실행할 때 client_id 외래 키를 사용할 수 없으므로 (겉으로보기)입니다. (* 중복 된 데이터가 저장되는 것을 방지하는 인덱스가 있지만 데이터베이스에 도달하기 전에 오류를 catch하고 사용자에게 친숙한 오류 메시지를 반환하고 싶습니다.)

ActiveRecord 유효성 검사를 통해 이러한 일이 발생하지 않도록 하시겠습니까?

편집 : This appears to be a known issue.

+0

(즉'validate' 같은 자기 오프 방법 내 수업, 그래서 뭔가를했습니다)? – Kris

+0

@Kris No. 관련하여, 'client_id' 존재 확인을 추가하면 (물론)'client_id'가 아직 존재하지 않기 때문에'client.save'가 실패합니다. – pdoherty926

답변

1

배치를 삽입 할 때 AR 유효성 검사를 사용하여이를 수행 할 수있는 훌륭한 방법은 없지만 다음 단계를 통해 수동으로 수행 할 수 있습니다.

  1. 잠재적으로 중복되는 레코드를로드하려면 PostgreSQL VALUES 목록을 사용하여 데이터베이스에 단일 쿼리를 만드십시오.
  2. 생성하고 중복을 꺼내 당신이 배치하려고 기록을 비교
  3. 수동 단계 1이

    # Build array of uniq attribute pairs we want to check for 
    uniq_attrs = new_collection.map do |record| 
        [ 
        record.day, 
        record.client_id, 
        ] 
    end 
    
    # santize the values and create a tuple like ('Monday', 5) 
    values = uniq_attrs.map do |attrs| 
        safe = attrs.map {|v| ActiveRecord::Base.connection.quote(v)} 
        "(#{safe.join(",")})" 
    end 
    
    existing = Preference.where(%{ 
        (day, client_id) in 
        (#{values.join(",")}) 
    }) 
    
    # SQL Looks like 
    # select * from preferences where (day, client_id) in (('Monday',5), ('Tuesday', 3) ....) 
    

    그럼 당신이 할 수처럼 조금 보이는

하여 오류 메시지 생성 및 반환 existing 컬렉션을 가져 와서 2 단계와 3 단계에서 중복 된 부분을 제거하고 오류 메시지를 생성하십시오.

나는이 기능을 필요로 한

, 나는 일반적으로 사용자 지정 유효성 검사를 만드는 경우 '설정 client_id`되어

class Preference < ApplicationRecord 

    def self.filter_duplicates(collection) 
    # blah blah blah from above 

    non_duplicates = collection.reject do |record| 
     existing.find do |exist| 
     exist.duplicate?(record) 
     end 
    end 

    [non_duplicates, existing] 

    end 

    def duplicate?(record) 
    record.day == self.day && 
    record.client_id = self.client_id 
    end 
end 
관련 문제