[RUBY] Y a-t-il un ingénieur qui n'a pas validé la colonne Json dans Rails?

Il s'agit d'un article sur la validation des colonnes Json à l'aide de json-schema dans Rails.

Préface

Cela fait longtemps que la colonne Json a été ajoutée à MySQL.

** Rails ne semble pas être la valeur par défaut, mais je veux valider Json correctement! ** ** Mais quand j'essaye de l'écrire honnêtement avec une méthode personnalisée ...

Exemple de méthode personnalisée stupide

some_model.rb


class SomeModel < ApplicationRecord
  validate :verify_timetable

  private

  def verify_timetable
    errors.add(:timetable, 'Pas un tableau') && return unless timetable.is_a?(Array)

    timetable.each do |el|
      errors.add(:timetable, 'L'élément n'est pas un hachage') && next unless el.is_a?(Hash)
      errors.add(:timetable, 'La clé de hachage n'est pas valide') && next unless el.keys.sort == %w[end_at start_at]

      %w[start_at end_at].each do |key|
        DateTime.parse(el[key])
      rescue ArgumentError
        errors.add(:timetable, "#{key}La valeur de n'est pas valide")
      end
    end
  end
end

――Ce sera un montant considérable ... ――Il est difficile de gérer des réglages fins tels que "Autorisez-vous un excès ou un manque de clés?"

Je pense que ces clients sont nombreux. Si vous n'y pensez pas, faites-vous la validation côté application?

Cette fois, j'utiliserai json-schema pour présenter la méthode de validation Json la plus cool à laquelle j'aie jamais pensé.

À quoi ça va ressembler

some_model.rb


class SomeModel < ApplicationRecord
  TIMETABLE_SCHEMA = {
    type: 'array',
    items: {
      type: 'object',
      properties: {
        start_at: { type: 'string', format: :datetime },
        end_at: { type: 'string', format: :datetime },
      },
    },
  }.freeze
  validates :timetable, json: { schema: TIMETABLE_SCHEMA }
end

C'est assez intuitif, n'est-ce pas? Vous pouvez placer le schéma où vous le souhaitez. Je veux mettre en place la validation en validation, donc je la définis juste avant la validation.

Comment utiliser

installation de gemmes

Gemfile


gem 'json-schema'

Définition du validateur personnalisé

C'est un paramètre pour pouvoir appeler avec validates: hoge, json: {schema: fuga}. Je l'ai mis dans ʻapp / validators`.

app/validators/json_validator.rb


class JsonValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    JSON::Validator.validate!(options[:schema], value, strict: true)
  rescue JSON::Schema::ValidationError => e
    record.errors[attribute] << (options[:message] || e.message)
  end
end

À ce stade, la validation selon le schéma Json normal (correspondance de modèle par expression régulière, définition de minLength, maxLength, etc.) est possible. Tout en recherchant sur Google les spécifications de Json Schema, lisez Gem Readme et essayez diverses choses. (Par exemple, strict: true est un paramètre qui ignore le contenu requis et n'autorise pas l'excès ou le manque de clés) C'est facile car vous pouvez écrire avec le hachage Ruby.

Ajout de Varidata pour DateTime

Il n'y a pas de type de date dans la définition de type de Json. Mais pour le moment, il existe des cas où vous souhaitez mettre des informations de date et d'heure dans Json. Ici, en référence à ce problème, le validateur de DateTime est ajouté à JSON :: Validator.

config/initializers/json_validator.rb


datetime = -> value {
  begin
    DateTime.parse(value)
  rescue ArgumentError
    raise JSON::Schema::CustomFormatError.new('not datetime format')
  end
}
JSON::Validator.register_format_validator(:datetime, datetime)

Si vous avez quelque chose comme "Je veux ce format personnalisé!", Vous pouvez l'ajouter ici.

Contraction

Comment était-ce? Cela semble vous libérer des descriptions de validation personnelles. Les ingénieurs qui ont négligé la validation de Json en profiteront pour améliorer la validation côté application et mener une vie Rails saine!

Recommended Posts

Y a-t-il un ingénieur qui n'a pas validé la colonne Json dans Rails?
Comment afficher la valeur lorsqu'il y a un tableau dans le tableau
Y a-t-il une instance même si le constructeur échoue?
[Rails] Comment afficher les images dans la vue
Lancer une exception et attraper lorsqu'il n'y a pas de gestionnaire correspondant au chemin au printemps
Que faire lorsque Cloud 9 est plein dans le didacticiel Rails
Je ne vois pas d'erreur dans l'installation du bundle Rails ... la solution
Puma --Nignx est une voie de sortie lorsque les rails s -e production -d ne fonctionnent pas dans l'environnement