2016-06-18 11 views
1

こんにちは私は、新しいオブジェクトと更新されたオブジェクトが重複しているかどうかをチェックする方法があります。 方法:自己オブジェクトの検証を防ぐ方法

def timeline 
    if start_at_changed? || end_at_changed? || person_id_changed? 
     if (person.vacations.where('start_at <= ?', start_at).count > 0 && 
     person.vacations.where('end_at >= ?', end_at).count > 0) || 
     (person.vacations.where('start_at <= ?', start_at).count > 0 && 
      person.vacations.where('end_at <= ?', end_at).count > 0 && 
      person.vacations.where('end_at >= ?', start_at).count > 0) || 
     (person.vacations.where('start_at >= ?', start_at).count > 0 && 
     person.vacations.where('start_at <= ?', end_at).count > 0 && 
     person.vacations.where('end_at >= ?', end_at).count > 0) 
     errors.add(:base, 'You have a vacation during this period.') 
     end 
    end 
    end 

私の問題は、いくつかの休暇を編集しようとしています。たとえば変更した場合start_at妥当性検査は、このオブジェクトと戻りエラーもチェックします。例:start_at 2016-06-27、end_at:2016-06-30 2016年6月26日にstart_atを変更してみます。検証では、期間「2016-06-27-2016-06-30」がチェックされるため、「あなたはこの期間中休暇を取っています。」という結果が返されます。どのように私は更新だけを試して、チェックオブジェクトを除外するには他の?

+0

をあなたは[ ''存在?]使用する必要があります(http://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-exists-3F) 、 'count'ではなく、8つではなく1つのクエリを実行する必要があります。 –

答えて

1

あなたのクエリで現在の休暇IDを除外するだけで済みます。以下のような何か:

def timeline 
    if start_at_changed? || end_at_changed? || person_id_changed? 
    if (person.vacations.where('start_at <= ? and vacations.id != ?', start_at, id).count > 0 && 
     person.vacations.where('end_at >= ? and vacations.id != ?', end_at, id).count > 0) || 
     ... 
    end 
    end 
end 

また、あなたがnot条件を使用することができます。詳細情報hereおよびhere

ここでは、多くのクエリを実行しています。これは生産上非常に高価になる可能性があります。私の提案は、このクエリをすべて1つのクエリでマージすることです。速度の向上だけでなく、コードの可読性が本当に良いでしょう。 あなたのコードは次のようになります。

def timeline 
    if start_at_changed? || end_at_changed? || person_id_changed? 
    overlapping_vacations = person.vacations.where('vacations.id != ?', id) 
    overlapping_vacations = overlapping_vacations.where('((start_at <= :start_at AND end_at >= :end_at) OR 
           (start_at <= :start_at AND end_at <= :end_at AND end_at >= :start_at) OR 
           (start_at >= :start_at AND start_at <= :end_at AND end_at >= :end_at))', 
           start_at: start_at, end_at: end_at) 
    if overlapping_vacations.exists? 
     errors.add(:base, 'You have a vacation during this period.') 
    end 
    end 
end 
+0

ご協力いただきありがとうございます!コードに小さなエラーがあります。 overlapping_vacations.existsをチェックすると、それだけがチェックされます:overlapping_vacations = person.vacations.where。私はこれを修復します。クエリの結果を変数に持ち込み、次に存在するチェックを行います。 –

関連する問題