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 Optioncase_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.
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)
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
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.
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
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
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.
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.
Wir haben Kamipo, ein Mitglied des Rails-Komitees, gebeten, diese Frage auf Twitter sorgfältig zu beantworten (Referenz). Vielen Dank, Kamipo!
Recommended Posts