11
votes

Les rails valident l'unicité des gammes de date

J'ai une application qui implique des enregistrements d'absence pour les employés.

Je dois vous assurer que les dates de début et de fin pour chaque enregistrement ne se chevauchent pas. P>

SO, par exemple, si je suis entré dans un Enregistrement d'absence qui a commencé aujourd'hui et s'est terminé demain, il ne devrait pas être possible d'entrer une autre à l'intérieur de cette plage de date de quelque manière que ce soit. Donc, je ne pouvais pas en faire un qui commence la veille aujourd'hui, puis se termine la journée après demain, ou une date ultérieure. P>

Pour le mettre simplement, je dois faire la plage de date unique. P >

Quelle est la meilleure façon d'y parvenir? p>

validateurs personnalisés dans la classe modèle qui implique itération à travers tous les enregistrements prennent beaucoup trop de temps à compléter, et je n'ai pas trouvé de gemmes qui abordent cette adresse problème. Je n'ai pas non plus trouvé aucun moyen de périmé par l'unicité dans le modèle non plus. Je suis excentré: / p>

Merci pour votre temps! P>

EDIT: P>

class Absence < ActiveRecord::Base
attr_accessible :date, :date_ended, :status, :reason, :form, :user_id, :tempuser, :company_id
belongs_to :user
default_scope { where(company_id: Company.current_id) }

validates :date, :date_ended, :status, :reason, :form, :user_id, presence: true 
validates_numericality_of :user_id, :only_integer => true, :message => "can only be whole number."
end


1 commentaires

Éventuellement en créant un modèle pour enregistrer les dates d'occasion? Quelque chose comme employéeaccendedated. Cela serait plus rapide que d'itération de tous les enregistrements.


5 Réponses :


21
votes

J'utilise ceci:

  scope :overlaps, ->(start_date, end_date) do
    where "(DATEDIFF(start_date, ?) * DATEDIFF(?, end_date)) >= 0", end_date, start_date
  end

  def overlaps?
    overlaps.exists?
  end

  # Others are models to be compared with your current model
  # you can get these with a where for example
  def overlaps
    siblings.overlaps start_date, end_date
  end

  validate :not_overlap

  def not_overlap
    errors.add(:key, 'message') if overlaps?
  end

  # -1 is when you have a nil id, so you will get all persisted user absences
  # I think -1 could be omitted, but did not work for me, as far as I remember
  def siblings
    user.absences.where('id != ?', id || -1)
  end


12 commentaires

Pourriez-vous expliquer ce que ces frères et sœurs étaient utilisés dans l'exemple précédent? Et comment va-t-il réellement utiliser votre étendue de chevauchements? Juste en validant le caractère unique des deux dates de la portée des chevauchements?


Voulez-vous pas plus d'une absence d'une période donnée pour un utilisateur donné? va mettre à jour en supposant cela.


Oui, chaque utilisateur ne doit être autorisé qu'à un enregistrement d'absence du 1/1/2013 à, par exemple, 10/1/2013. Toutes les dates entre ces dates sont hors limites pour tout autre record d'absence, pour cet utilisateur.


Je reçois une "méthode non définie" clé? ' Pour Nil: Nilclass "Erreur et" Vous devez fournir au moins une validation "sur" Validatedate: NOT_Overlap ". Qu'est-ce que c'est exactement un frère de fraîcheur au fait? Je pourrais peut-être contribuer davantage si je savais. Je suis loin d'être un expert sur la scope, ha! Edit: Ah, je vois que vous définissez cela dans le nouveau code. À votre santé!


remplacer: la touche avec: base, les frères et sœurs sont des frères et sœurs d'une absence, ce qui signifie des absences du même utilisateur, à l'exception de l'absence actuelle


Il se plaint toujours d'avoir besoin d'au moins une validation sur «Validate: Not_overlap». La méthode non définie était que cela ne savait pas quel était le "utilisateur", mais j'ai réparé celui-là.


La portée par défaut pourrait-elle être en quelque sorte causer ce problème? Cela ne devrait pas, puisque tous mes enregistrements ont des données de scorage correctes


Ignorer mon commentaire précédent, et je pense que cela devrait être validé, ne pas valider le: Not_overlap?


Maintenant, c'est un problème de sqlite ... ça ne sait pas ce qu'est la datrodiff. Serait LISTS.ADEWALL.COM/Archive/trac/2005-may/003124 .html travail à la place?


Voir cette question Stackoverflow.com/questions/5972163/sqlite-query-Questions


Pas d'inquiétude homme, je l'ai obtenue en remplaçant le SQL dans la portée des chevauchements avec ceci: où "((((date julianday (date (date)) - Julianday (((date ((date)) - Julianday ( DATE_LIQUÉ))))> = 0 ", Date_Le Date, Date Merci de toute l'aide, peu de personnes ne passeraient pas trois heures à aider un étranger complet. Si je peux rembourser la faveur, faites le moi savoir! Bonne chance!


UTILISATEUR.ABENDENCES.LOWE.NOT (ID: ID) générera une déclaration correcte, pas besoin de -1. Nécessite des rails 4 cependant.



8
votes

Modification de la réponse acceptée, voici une étendue de chevauchements qui fonctionnera pour DBS qui ne comprennent pas la datrodiff xxx

ceci dessine sur la solution pour Determine si deux chaînes de date se chevauchent


1 commentaires

Honnêtement, en utilisant > = et <= semble plus lisible et portable que datrodiff Même si votre dB prend en charge datrodiff .



1
votes

Il y a un gemme appelé validateate_overlap qui vous permet de valider facilement les chevauchements de la plage de date. Vous pouvez également utiliser des étendues sur la validation.


0 commentaires

1
votes

Bien que la solution Juanpastas est correcte, elle sera valide pour la création d'enregistrements, mais peut conduire à de fausses validations négatives sur les mises à jour.

Si vous devez modifier un enregistrement existant, dites que la plage est 2014-03-13..2014-06-12 et vous souhaitez le réduire à 2014-03-13..2014-04-12, vous " ll Obtenez une erreur de chevauchement car il vérifie elle-même. P>

  def siblings
    Absence_users.where('user_id = ? AND id != ?', user_id, self)
  end


0 commentaires

8
votes

Utilisez le gem validateate_overlap code> .

class Meeting < ActiveRecord::Base
  belongs_to User
  validates :start_date, :end_date, overlap: { scope: 'user_id',
                                             message_content: 'overlaps with Users other meetings.' }
end


0 commentaires