[RUBY] Was tun, wenn in Rails 6.0 die Warnung "Der Eindeutigkeitsprüfer erzwingt in Rails 6.1 keinen Vergleich zwischen Groß- und Kleinschreibung mehr erzwingt" angezeigt wird

Einführung

Wenn Sie eine vorhandene Rails-Anwendung, die MySQL verwendet, auf Rails 6.0 aktualisieren, wird möglicherweise die folgende Warnung angezeigt:

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.

(Übersetzung) Veraltete Warnung: Eindeutigkeit Varidata erzwingen in Rails 6.1 keine Vergleiche mehr zwischen Groß- und Kleinschreibung. Wenn Sie weiterhin den Vergleich zwischen Groß- und Kleinschreibung für das Attribut : name des Benutzermodells verwenden möchten, geben Sie explizit die Option case_sensitive: true für den Eindeutigkeitsprüfer an.

Die Warnung stammt von dem Teil, der den Eindeutigkeitsprüfer wie folgt verwendet.

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

Wenn Sie die Option "case_sensitive" wie folgt hinzufügen, wird die Warnung vorerst ausgeblendet.

class User < ApplicationRecord
  #Auf diese Weise erhalten Sie jedoch keine Warnungen! !! !!
  validates :name, uniqueness: { case_sensitive: true }
end

Es ist jedoch nicht sehr gut, Optionen hinzuzufügen, ohne tief nachzudenken. In diesem Artikel werde ich näher auf den Umgang mit dieser Warnung eingehen.

Schienen 5.2 und frühere Spezifikationen (und Probleme)

Grundsätzlich tritt dieses Problem bei der Verwendung von MySQL auf. Dies ist normalerweise kein Problem, wenn Sie PostgreSQL verwenden.

Ich werde nicht auf Details eingehen, aber MySQL hat das Konzept der Zusammenarbeit. Die Standardeinstellung ist eine Zusammenarbeit wie "utf8mb4_unicode_ci". In diesem Fall wird bei den in der Datenbank gespeicherten Zeichenfolgen die Groß- und Kleinschreibung nicht berücksichtigt.

Mit anderen Worten, um nach dem Namen "jnchito" zu suchen, wird entweder die Ausgabe von SQL "WHERE name =" jnchito "oder die Ausgabe von SQL" WHERE name = "JNCHITO" ausgeführt.

Rails 5.2 und frühere Eindeutigkeitsprüfer führen jedoch standardmäßig Groß- und Kleinschreibung durch.

Wenn "jnchito" bereits in der Datenbank gespeichert ist, verhält es sich wie folgt.

#Lower jnchito ist bereits registriert, also NG
user.name = 'jnchito'
user.valid? #=> false

#Der obere Jnchito ist bereits nicht registriert, also ist es OK
user.name = 'JNCHITO'
user.valid? #=> true

#Das folgende SQL wird hinter den Kulissen ausgegeben (mit BINARY)
# SELECT 1 AS one FROM `users` WHERE `users`.`name` = BINARY 'JNCHITO' LIMIT 1

Auf den ersten Blick sieht dies nach einer schönen Spezifikation aus, hat aber die folgenden unerwarteten Nachteile.

Tatsächlich verhält sich der gerade erwähnte Code inkonsistent wie folgt: (Wenn eine eindeutige Einschränkung an die DB-Seite angehängt ist)

#Hauptstadt"JNCHITO"Dann scheint es, dass es gespeichert werden kann, weil es keinen Überprüfungsfehler gibt
user.name = 'JNCHITO'
user.valid? #=> true

#Ausführung speichern ... Oh, ich bin in eine Verletzung der DB-eindeutigen Einschränkung geraten und eine Ausnahme ist aufgetreten! !!
user.save
#=> ActiveRecord::RecordNotUnique:
#     Mysql2::Error: Duplicate entry 'JNCHITO' for key 'users.index_users_on_name'

Es scheint, dass diese Art von Problem häufig bei der Verwendung von MySQL mit Rails auftrat. (Ich habe es nicht bemerkt, weil ich normalerweise PostgreSQL benutze)

In Rails 6.1 eingeführte Spezifikationen (nicht Rails 6.0)

Um dieses Problem zu umgehen, wird bei Rails 6.1-Eindeutigkeitsprüfern standardmäßig die Groß- und Kleinschreibung nicht berücksichtigt. Streng genommen lautet die Spezifikation vielmehr: "Rails gibt SQL gehorsam aus und überlässt die Unterscheidung zwischen Groß- und Kleinschreibung den Einstellungen auf der DB-Seite."

Infolgedessen können die Funktionen auf der DB-Seite vollständig genutzt werden, so dass die oben genannten,

Solche Probleme treten nicht auf.

Wenn Sie beispielsweise bereits "jnchito" in Ihrer Datenbank gespeichert haben, verhält sich Rails 6.1 wahrscheinlich folgendermaßen:

#NG (Groß- und Kleinschreibung wird nicht berücksichtigt), da jnchito bereits registriert ist
user.name = 'jnchito'
user.valid? #=> false

#JNCHITO ist bereits registriert, also NG (ohne Berücksichtigung der Groß- / Kleinschreibung)
user.name = 'JNCHITO'
user.valid? #=> false

#Die folgende SQL sollte hinter den Kulissen ausgegeben werden (ohne BINARY)
# SELECT 1 AS one FROM `users` WHERE `users`.`name` = 'JNCHITO' LIMIT 1

Rails 6.0 fordert Entwickler dazu auf, ihre Code- und DB-Einstellungen auf eine Änderung der 6.1-Spezifikation zu überprüfen

Im Austausch zur Vermeidung "unerwarteter Nachteile" führt die Änderung der Spezifikation von Rails 6.1 jedoch zu einer Änderung des Verhaltens "nicht vom Fall zu unterscheiden".

Rails 6.0 behält also das Verhalten von Rails 5.2 und früheren Versionen bei, ermutigt Entwickler jedoch, Änderungen vorzunehmen, und sagt: "Rails 6.1 ändert sein Verhalten! Entscheiden Sie, was Sie jetzt tun möchten!". Das ist die Warnung, die zu Beginn eingeführt wurde.

Bei der Unterscheidung zwischen Fällen

Wenn Sie wie in der Rails 5.2-Ära zwischen Groß- und Kleinschreibung unterscheiden möchten, können Sie die Option "case_sensitive: true" explizit hinzufügen. Die Warnung wird dann ausgeblendet.

Wenn sich jedoch die Zusammenarbeit auf der DB-Seite nicht ändert,

Ich werde immer noch das Problem haben.

class User < ApplicationRecord
  #Es wird keine Warnung ausgegeben, aber wenn Sie die Zusammenarbeit auf der DB-Seite nicht ändern, bleiben "unerwartete Nachteile" bestehen.
  validates :name, uniqueness: { case_sensitive: true }
end

Wenn Sie diese Probleme lösen möchten, müssen Sie die Zusammenarbeit auf der DB-Seite in "Groß- und Kleinschreibung beachten" wie "utf8mb4_bin" ändern, anstatt den Code auf der Rails-Seite zu ändern. (Das Verfahren zum Ändern der Zusammenarbeit wird hier weggelassen.)

Wenn bei der Zusammenarbeit auf der DB-Seite zwischen Groß- und Kleinschreibung unterschieden wird, wird die Warnung nicht ausgegeben, da das Verhalten des Eindeutigkeitsprüfers von Rails nicht übereinstimmt. (Sie müssen die Option "case_sensitive" nicht angeben.)

class User < ApplicationRecord
  #Wenn Sie die Zusammenarbeit auf der DB-Seite ändern, ist case_Keine sensible Option erforderlich. Keine Warnungen oder "unerwarteten Nachteile"
  validates :name, uniqueness: true
end

Groß- und Kleinschreibung wird nicht berücksichtigt

Geben Sie explizit "case_sensitive: false" an, wenn Sie nicht zwischen Groß- und Kleinschreibung unterscheiden müssen. Auf diese Weise wird weder die Zusammenarbeit auf der DB-Seite noch der Eindeutigkeitsprüfer von Rails von Groß- und Kleinschreibung unterschieden, sodass die Nichtübereinstimmung behoben wird und keine Warnung angezeigt wird.

In diesem Fall ändert sich jedoch das Verhalten der Anwendung. Daher muss sorgfältig geprüft werden, ob dies zu Verwirrung beim Benutzer führt.

class User < ApplicationRecord
  #Es wird keine Warnung ausgegeben. Es gibt keine "unerwarteten Nachteile". Aber Schienen 5.Verhaltensänderungen mit 2
  validates :name, uniqueness: { case_sensitive: false }
end

Sie können die Option "case_sensitive: false" auch entfernen, nachdem Sie Ihre Anwendung auf Rails 6.1 aktualisiert haben. (Da standardmäßig die Groß- und Kleinschreibung nicht berücksichtigt wird)

class User < ApplicationRecord
  # Rails 6.1 Fall_OK, auch wenn Sie die Empfindlichkeit verlieren
  validates :name, uniqueness: true
end

Referenz: Verhaltensübersicht von Rails 5.2-6.1

Diese Geschichte ändert sich abhängig von der Kombination aus "Kollatierung auf der MySQL-Seite", "Eindeutigkeitsvalidator'case_sensitive`-Option" und "Rails-Version".

Die folgende Tabelle fasst zusammen, was mit jeder Kombination passiert.

Screen Shot 2020-05-28 at 11.14.41.png

Letztendlich ist es in einem idealen Zustand, wenn eine Kombination realisiert werden kann, bei der die Spalte "DB-Seite und Schienen nicht übereinstimmen?" In der obigen Tabelle zu "NEIN" wird.

Verweise

Vielen Dank

Wir haben Kamipo, ein Mitglied des Rails-Komitees, gebeten, diese Frage auf Twitter sorgfältig zu beantworten (Referenz). Vielen Dank, Kamipo!

Recommended Posts

Was tun, wenn in Rails 6.0 die Warnung "Der Eindeutigkeitsprüfer erzwingt in Rails 6.1 keinen Vergleich zwischen Groß- und Kleinschreibung mehr erzwingt" angezeigt wird
Abhilfe für "Der Eindeutigkeitsprüfer erzwingt in Rails 6.1 keinen Vergleich mehr zwischen Groß- und Kleinschreibung."
Was tun, wenn Sie den Text eines Elements in Selen nicht abrufen können?
Was tun, wenn in GlassFish eine java.io.IOException auftritt?
Was tun, wenn der Befehl Rails unbrauchbar wird?
[Rails] Was tun, wenn Sie versehentlich eine Bundle-Installation in einer Produktionsumgebung in Ihrer lokalen Umgebung durchführen?
[Schienen] Was tun, wenn mit der Fehlermethode keine Fehlermeldung angezeigt wird?
Was tun, wenn im Testcode der Steuereinheit in Rails der Fehler "302" angezeigt wird?
Was tun, wenn während des Rails-Testcodes ein Fehler bei der Standardauthentifizierung auftritt?
Was tun, wenn in Docker ein gcc-Fehler auftritt?
Was tun, wenn die Rails-Seite im Rails-Lernprogramm 1.3.2 nicht angezeigt wird?
Was tun, wenn Sie Ihr Root-Passwort unter CentOS7 vergessen haben?
[Rails] Was tun, wenn Sie mit form_with keine Parameter abrufen können?
Was tun, wenn in CircleCI der Fehler zu lang ohne Ausgabe (über 10 m0s) angezeigt wird?
Was tun, wenn die Meldung "Ein Server läuft bereits" angezeigt wird. Fehler beim Versuch, den Rails-Server zu starten
Was tun, wenn eine javax.net.ssl.SSLHandshakeException angezeigt wird: Remote-Host hat während des Handshakes im IBM JDK die Verbindung geschlossen
Was tun, wenn in bind.pry eine falsche Anzahl von Argumenten angezeigt wird?
[Rails Tutorial Kapitel 2] Was tun, wenn Sie einen Fehlern im Spaltennamen machen?
Was tun, wenn Sie in Eclipse eine JRE auswählen und "Die ausgewählte JRE unterstützt die aktuelle Konformitätsstufe 11 nicht" erhalten?
Was zu tun ist, wenn weitere Fehler beim Parsen von http-Headern auftreten, wird auf Debug-Ebene protokolliert. In Tomcat 8.5.37
[Rails] Was tun, wenn der Fehler Keine Datenbank ausgewählt und Unbekannte Datenbank in db: migrate angezeigt wird?
[Rails] Was tun, wenn keine Daten in der Datenbank registriert sind?
Was tun, wenn Sie sich über OpenSSL mit pyenv install ärgern?
Was tun, wenn Sie gem'bcrypt 'in Ihre Gemfile eingeben und bei der Bundle-Installation eine Fehlermeldung erhalten?
Was tun, wenn das von refile gepostete Bild nach dem Einstellen der 404-Fehlerseite in Rails verschwindet?
Was tun, wenn der Vorgang nicht zulässig ist, wenn ein Befehl im Terminal ausgeführt wird?
Was tun, wenn das Präfix c in JSP nicht gebunden ist?
Was tun, wenn Sie das Plug-In nicht vom Eclipse Marketplace installieren können?
Was tun, wenn Ihnen der von swagger-codegen-cli generierte Code nicht gefällt?
Was tun, wenn auf GitHub eine MiniMagick-Sicherheitsanfälligkeitswarnung angezeigt wird?
[Rails] Was tun, wenn die Fehlermeldung "JavaScript-Laufzeit konnte nicht gefunden werden?" Angezeigt wird, wenn der Befehl "Rails" in Catalina ausgeführt wird
Was tun, wenn Sie aktiviert haben? Verwenden Sie die WSL2-basierte Engine in Docker Desktop mit unzureichender WSL2-Installation
Was tun, wenn Sie die Mastertabelle nach dem Importieren eines Projekts in Eclipse nicht in einer Datei speichern konnten?
So übersetzen Sie die Fehlermeldung ins Japanische (Was tun, wenn Sie sich aus irgendeinem Grund nicht anmelden können)
Was tun, wenn Sie Gemfile oder .bundle / directory nicht finden konnten?
Was tun, wenn Sie das mit bootstrap-select erstellte Auswahlfeld nicht aktivieren können?
Was tun, wenn der Wert im zweiten getSubmittedValue () in JSF Validator null wird?
Was tun, wenn die ffi-Installation beim Starten einer Anwendung in Rails fehlschlägt?
Was tun, wenn der Server-Tomcat stirbt?
Was tun, wenn Sie falsche Informationen eingeben?
[Java] Was tun, wenn in Eclipse die Fehlermeldung "Nicht zulässig auf Quellenebene unter 1.X" angezeigt wird?
Was tun, wenn ein Argumentfehler auftritt? Falsche Anzahl von Argumenten (gegeben 2, erwartete 0) in Ihrem RSpec-Test
Was tun, wenn beim Abrufen von Rails datetime_field die Fehlermeldung "Bitte geben Sie einen gültigen Wert ein" angezeigt wird?