[RUBY] Que faire si vous recevez l'avertissement «Le validateur d'unicité n'appliquera plus la comparaison sensible à la casse dans Rails 6.1.» Dans Rails 6.0

introduction

Si vous mettez à jour une application Rails existante qui utilise MySQL vers Rails 6.0, vous pouvez recevoir l'avertissement suivant:

DEPRECATION WARNING: Uniqueness validator will no longer enforce case sensitive comparison in Rails 6.1. To continue case sensitive comparison on the :name attribute in User model, pass `case_sensitive: true` option explicitly to the uniqueness validator.

(Traduction) Avertissement obsolète: Unicité Varidata ne "force plus les comparaisons sensibles à la casse" dans Rails 6.1. Si vous souhaitez continuer à utiliser la "comparaison sensible à la casse" pour l'attribut : name du modèle User, spécifiez explicitement l'option case_sensitive: true pour le validateur d'unicité.

L'avertissement apparaît dans la partie qui utilise le validateur d'unicité comme suit.

class User < ApplicationRecord
  validates :name, uniqueness: true
end

Pour le moment, si vous ajoutez l'option case_sensitive comme celle-ci, l'avertissement disparaîtra.

class User < ApplicationRecord
  #De cette façon, vous ne recevrez aucun avertissement! !! !!
  validates :name, uniqueness: { case_sensitive: true }
end

Cependant, il n'est pas très bon d'ajouter des options sans réfléchir profondément. Donc, dans cet article, je vais entrer plus en détail sur la façon de traiter cet avertissement.

Rails 5.2 et spécifications antérieures (et problèmes)

En principe, ce problème se produit lors de l'utilisation de MySQL. Ce n'est généralement pas un problème si vous utilisez PostgreSQL.

Je n'entrerai pas dans les détails, mais MySQL a le concept de collaboration. La valeur par défaut est une collaboration telle que ʻutf8mb4_unicode_ci`, auquel cas les chaînes stockées dans la base de données ne sont pas sensibles à la casse.

En d'autres termes, pour rechercher le nom "jnchito", soit en émettant le SQL WHERE name = 'jnchito' ou en émettant le SQL WHERE name =' JNCHITO' frappera.

Cependant, Rails 5.2 et les validateurs d'unicité antérieurs font par défaut des comparaisons sensibles à la casse.

Donc, si "jnchito" est déjà enregistré dans la base de données, il se comporte comme suit.

#Lower jnchito est déjà enregistré, donc NG
user.name = 'jnchito'
user.valid? #=> false

#Le jnchito supérieur n'est déjà pas enregistré, donc c'est OK
user.name = 'JNCHITO'
user.valid? #=> true

#Le SQL suivant est émis dans les coulisses (avec BINARY)
# SELECT 1 AS one FROM `users` WHERE `users`.`name` = BINARY 'JNCHITO' LIMIT 1

À première vue, cela ressemble à une belle spécification, mais elle présente les inconvénients inattendus suivants.

En fait, le code que je viens de mentionner se comporte de manière incohérente comme suit: (Lorsqu'une contrainte unique est attachée au côté DB)

#Capitale"JNCHITO"Ensuite, il semble qu'il puisse être enregistré car il n'y a pas d'erreur de vérification
user.name = 'JNCHITO'
user.valid? #=> true

#Sauver l'exécution ... Oh, je me suis fait prendre dans une violation de contrainte unique DB et une exception s'est produite! !!
user.save
#=> ActiveRecord::RecordNotUnique:
#     Mysql2::Error: Duplicate entry 'JNCHITO' for key 'users.index_users_on_name'

Il semble que ce genre de problème se soit souvent produit lors de l'utilisation de MySQL avec Rails. (Je ne l'ai pas remarqué car j'utilise habituellement PostgreSQL)

Spécifications introduites dans Rails 6.1 (pas Rails 6.0)

Pour contourner ce problème, les validateurs d'unicité de Rails 6.1 sont insensibles à la casse par défaut. Au contraire, à proprement parler, la spécification est que «Rails émet SQL docilement et laisse la distinction de cas aux paramètres côté DB».

En conséquence, les fonctions du côté DB peuvent être pleinement utilisées, de sorte que ce qui précède,

De tels problèmes ne se produiront pas.

Par exemple, si vous avez déjà "jnchito" stocké dans votre base de données, Rails 6.1 se comportera probablement comme ceci:

#NG (insensible à la casse) car jnchito est déjà enregistré
user.name = 'jnchito'
user.valid? #=> false

#JNCHITO est déjà enregistré, donc NG (insensible à la casse)
user.name = 'JNCHITO'
user.valid? #=> false

#Le SQL suivant doit être émis dans les coulisses (sans BINARY)
# SELECT 1 AS one FROM `users` WHERE `users`.`name` = 'JNCHITO' LIMIT 1

Rails 6.0 encourage les développeurs à revoir leur code et leurs paramètres de base de données pour un changement de spécification 6.1

Cependant, en échange d'éviter des «inconvénients inattendus», le changement de spécification de Rails 6.1 entraîne un changement dans le comportement «d'être insensible à la casse».

Ainsi, Rails 6.0 conserve le comportement de Rails 5.2 et versions antérieures, mais encourage les développeurs à changer, en disant: "Rails 6.1 changera son comportement! Décidez de ce que vous voulez faire maintenant!". C'est l'avertissement introduit au début.

Lors de la distinction entre les cas

Si vous voulez être sensible à la casse comme à l'époque de Rails 5.2, vous pouvez ajouter explicitement l'option case_sensitive: true et l'avertissement disparaîtra.

Cependant, s'il n'y a pas de changement dans la collaboration côté DB,

J'aurai toujours le problème.

class User < ApplicationRecord
  #Aucun avertissement ne sera émis, mais si vous ne modifiez pas la collaboration côté DB, des «inconvénients inattendus» subsisteront.
  validates :name, uniqueness: { case_sensitive: true }
end

Si vous voulez résoudre ces problèmes, vous devez changer la collaboration côté base de données en "collaboration sensible à la casse" comme ʻutf8mb4_bin` au lieu de modifier le code côté Rails. (La procédure de modification de la collaboration est omise ici)

Si la collaboration côté DB est sensible à la casse, l'avertissement ne sera pas émis car il n'y aura pas d'incohérence avec le comportement du validateur d'unicité de Rails. (Vous n'avez pas besoin de spécifier l'option case_sensitive)

class User < ApplicationRecord
  #Si vous modifiez la collaboration côté DB, cas_Aucune option sensible requise. Aucun avertissement ou "inconvénients inattendus"
  validates :name, uniqueness: true
end

Insensible à la casse

Spécifiez explicitement case_sensitive: false si vous n'avez pas besoin d'être sensible à la casse. De cette façon, ni la collaboration côté base de données ni le validateur d'unicité de Rails ne seront insensibles à la casse, donc l'incohérence sera résolue et aucun avertissement ne sera affiché.

Cependant, dans ce cas, le comportement de l'application changera, il est donc nécessaire d'examiner attentivement si cela va créer de la confusion pour l'utilisateur.

class User < ApplicationRecord
  #Aucun avertissement ne sera émis. Il n'y a pas de "désavantages inattendus". Mais Rails 5.Changements de comportement avec 2
  validates :name, uniqueness: { case_sensitive: false }
end

Vous pouvez également supprimer l'option case_sensitive: false après la mise à niveau de votre application vers Rails 6.1. (Parce qu'il est insensible à la casse par défaut)

class User < ApplicationRecord
  # Rails 6.1 cas_OK même si vous perdez la sensibilité
  validates :name, uniqueness: true
end

Référence: Résumé du comportement des rails 5.2-6.1

Cette histoire change en fonction de la combinaison de «classement côté MySQL», «option de validation d'unicité« case_sensitive »» et «version Rails».

Le tableau ci-dessous résume ce qui se passe avec chaque combinaison.

Screen Shot 2020-05-28 at 11.14.41.png

En fin de compte, il sera dans un état idéal si une combinaison dans laquelle la colonne "côté DB et Rails ne correspondent pas?" Dans le tableau ci-dessus devient "NON" peut être réalisée.

Les références

Merci

Nous avons demandé à kamipo, membre du comité Rails, de répondre attentivement à cette question sur Twitter (Référence). Merci beaucoup, kamipo!

Recommended Posts

Que faire si vous recevez l'avertissement «Le validateur d'unicité n'appliquera plus la comparaison sensible à la casse dans Rails 6.1.» Dans Rails 6.0
Remède pour "Le validateur d'unicité n'appliquera plus la comparaison sensible à la casse dans Rails 6.1."
Que faire si vous ne pouvez pas obtenir le texte d'un élément dans Selenium
Que faire lorsqu'une exception java.io.IOException se produit dans GlassFish
Que faire si la commande rails devient inutilisable
[Rails] Que faire si vous effectuez accidentellement une installation groupée dans un environnement de production de votre environnement local
[Rails] Que faire si vous ne pouvez pas obtenir de message d'erreur avec la méthode des erreurs
Que faire si vous obtenez une erreur «302» dans le code de test du contrôleur dans Rails
Que faire si vous obtenez une erreur avec l'authentification de base pendant le code de test Rails
Que faire si vous obtenez une erreur gcc dans Docker
Que faire si la page Rails n'est pas affichée dans le didacticiel Rails 1.3.2
Que faire si vous oubliez votre mot de passe root sur CentOS7
[Rails] Que faire si vous ne pouvez pas obtenir de paramètres avec form_with
Que faire si vous obtenez l'erreur Trop long sans sortie (dépassé 10m0s) dans CircleCI
Que faire si le message "Un serveur est déjà en cours d'exécution" s'affiche. Erreur lors de la tentative de démarrage du serveur rails
Que faire si vous obtenez une exception javax.net.ssl.SSLHandshakeException: connexion de l'hôte distant fermée pendant l'établissement de liaison dans IBM JDK
Que faire si vous obtenez une erreur de nombre d'arguments erroné dans binding.pry
[Tutoriel Rails Chapitre 2] Que faire lorsque vous faites une erreur dans le nom de la colonne
Que faire si vous sélectionnez un JRE dans Eclipse et obtenez "Le JRE sélectionné ne prend pas en charge le niveau de conformité actuel 11"
Que faire si vous obtenez d'autres occurrences d'erreurs d'analyse de l'en-tête http seront consignées au niveau de débogage. Dans Tomcat 8.5.37
[Rails] Que faire lorsque l'erreur Aucune base de données sélectionnée et Base de données inconnue apparaît dans db: migrate
[Rails] Que faire si les données ne sont pas enregistrées dans la base de données
Que faire si vous vous fâchez contre OpenSSL avec Pyenv Install
Que faire si vous entrez gem'bcrypt 'dans votre Gemfile et obtenez une erreur avec l'installation du bundle
Que faire si l'image publiée par refile disparaît après avoir défini la page d'erreur 404 dans Rails
Que faire si l'opération non autorisée s'affiche lors de l'exécution d'une commande dans le terminal
Que faire lorsque le préfixe c n'est pas lié dans JSP
Que faire si vous ne pouvez pas installer le plug-in à partir d'Eclipse Marketplace
Que faire si vous n'aimez pas le code généré par swagger-codegen-cli
Que faire si vous recevez une alerte de vulnérabilité MiniMagick sur GitHub
[Rails] Que faire si vous obtenez une erreur indiquant "Impossible de trouver un moteur d'exécution JavaScript." Lors de l'exécution de la commande rails dans Catalina
Que faire si vous avez activé Utiliser le moteur basé sur WSL2 dans Docker Desktop avec une installation WSL2 insuffisante
Que faire si vous obtenez Impossible d'enregistrer la table principale dans un fichier après l'importation d'un projet dans Eclipse
Comment traduire le message d'erreur en japonais (que faire si vous ne pouvez pas vous connecter pour une raison quelconque)
Que faire si vous obtenez Impossible de localiser le répertoire Gemfile ou .bundle /
Que faire si vous ne pouvez pas activer la boîte de sélection créée par bootstrap-select
Que faire lorsque la valeur devient nulle dans le second getSubmittedValue () dans JSF Validator
Que faire si l'installation de ffi échoue lors du lancement d'une application dans Rails
Que faire si le serveur Tomcat meurt
Que faire si vous transmettez des informations incorrectes
[Java] Que faire si vous obtenez une erreur dans Eclipse disant "Non autorisé au niveau source inférieur à 1.X"
Que faire si vous obtenez une erreur d'argument: nombre incorrect d'arguments (donné 2, attendu 0) dans votre test RSpec
Que faire si vous obtenez une erreur indiquant "Veuillez saisir une valeur valide" lors de l'obtention avec Rails datetime_field