Dans ActiveRecord, si vous placez une chaîne de caractères dans une colonne de type Date ou de type Integer, elle sera automatiquement convertie en ce type de colonne.
Par exemple, si vous disposez du tableau des utilisateurs suivant: (Created_at et updated_at sont omis pour plus de simplicité.)
create_table "users", force: :cascade do |t|
t.string "name"
t.integer "age"
end
Essayons de saisir différentes valeurs à l'aide de la console Rails.
irb (main): 001: 0> User.new (nom: "Taro", âge: 21) Essayez de mettre un nombre dans #age
=> # <Nom d'utilisateur: "Taro", âge: 21>
irb (main): 002: 0> User.new (nom: "Taro", age: "21") Essayez de mettre une chaîne de caractères dans #age
=> # <Nom d'utilisateur: "Taro", âge: 21>
irb (main): 003: 0> User.new (nom: "Taro", age: "21") Essayez de mettre une chaîne de caractères dans #age (1 est un nombre pleine largeur)
=> # <Nom d'utilisateur: "Taro", âge: 2>
Le premier est une valeur numérique. Puisqu'il s'agit d'une valeur numérique, elle peut être saisie telle quelle.
Le second est une chaîne. La chaîne de caractères "21" a été convertie en nombre 21. Merveilleux.
Que diriez-vous du troisième, la 1 partie de "21" est un nombre pleine largeur. C'est devenu l'âge: 2. C'est complètement différent de 21.
Au fait, même si vous utilisez "2 1" (avec un espace entre eux) ou "2 a" (avec un caractère autre qu'un nombre), ce sera l'âge: 2.
Supposons que vous essayez de lire une entrée non numérique et d'appliquer la validation suivante.
validates :age, format: { with: /\A[0-9]+\z/}
Dans ce cas, si l'utilisateur saisit «2 1», «2 a», etc., la validation sera appliquée à 2 ans et elle sera sauvegardée en tant que données correctes.
En guise de solution, vous pouvez ajouter _before_type_cast à age pour valider la valeur entrée par l'utilisateur au lieu de la valeur après la conversion du type. [* Référence "before_type_cast with rails / validates"](https://dora.bk.tsukuba.ac.jp/~takeuchi/?%E3%82%BD%E3%83%95%E3%83%88%E3 % 82% A6% E3% 82% A7% E3% 82% A2% 2Frails% 2Fvalide% E3% 81% A7before_type_cast)
validates :age_before_type_cast, format: { with: /\A[0-9]+\z/ }, presence: true
En plus de la validation, _before_type_cast est également utile lorsque vous souhaitez convertir des caractères alphanumériques dans une chaîne de caractères de pleine largeur à demi-largeur, ou lorsque vous souhaitez enregistrer après avoir supprimé les espaces.
À titre d'exemple, le code suivant utilise une gemme appelée Moji pour convertir de pleine largeur en demi-largeur.
Cette fois, j'utilise _before_type_cast parce que je veux aligner l'entrée qui est un mélange de pleine largeur et demi-largeur tel que "21" (1 est pleine largeur) de l'utilisateur à demi-largeur avant validation.
Après avoir reçu la chaîne de caractères telle qu'elle est entrée par l'utilisateur avec age_before_type_cast et l'avoir convertie, la chaîne de caractères convertie est mise en age.
validates :age_before_type_cast, format: { with: /\A[0-9]+\z/ }, presence: true
before_validation do
string = self.send(:age_before_type_cast)
string = Moji.normalize_zen_han(string)
send(:write_attribute, :age, string)
end
Le premier est la différence entre les attributs normaux et les attributs avec _before_type_cast. La valeur ne peut pas être obtenue avec [: 〇〇_before_type_cast]. En particulier
irb (main): 001: 0> user = User.new (nom: "Taro", âge: "21")
irb(main):002:0> user.age
=> 21
irb(main):003:0> user.age_before_typecast
=> "21"
irb(main):004:0> user[:age]
=> 21
irb(main):005:0> user[:age_before_typecast]
=> nil
Vous pouvez obtenir la valeur avec user.age_before_type_cast, Quand j'essaye d'obtenir la valeur en utilisant l'utilisateur [: age_before_type_cast], nil est retourné.
irb(main):001:0> user.age = 21
=> 21
irb(main):002:0> user.age_before_type_cast = 21
=> #NoMethodError se produit.
Puisque _before_type_cast sert à vérifier l'entrée avant la conversion de type en age, il n'est bien sûr pas possible de se mettre à jour.
De plus, si vous enregistrez, 〇〇 et 〇〇_before_type_cast seront les mêmes. En particulier,
irb (main): 001: 0> user = User.new (nom: "Taro", âge: "21")
irb(main):002:0> user.save
irb(main):003:0> user.age_before_typecast
=> 21
Le nombre 21 est renvoyé à la place de la chaîne "21".
Soyez prudent lors de la mise en œuvre ou du test en raison des propriétés ci-dessus!
[before_type_cast with rails / validates](https://dora.bk.tsukuba.ac.jp/~takeuchi/?%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6 % E3% 82% A7% E3% 82% A2% 2Frails% 2Fvalide% E3% 81% A7before_type_cast)