Пятница, 11 февраля 2022 11:37

Validate JSON schema in Active Admin

Оцените материал
(1 Голосовать)

Валидация Active Record для поля JSON в ActiveAdmin / Ruby on Rails.

Validate JSON schema in Active Admin.
Validate JSON schema in Active Admin.

 

Сходу оговорюсь: само собой разумеется, нам нужна всего только валидация на уровне модели, ActiveAdmin "из коробки" подхватит логику, блокируя при провале валидации запись данных в db и выведя в панели управления соответствующее уведомление. Мы только подредактируем последнее, сделав чуть более информативным (остановлюсь на этом далее). Работать будем на примере блога на рельсах, приняв, что модель Slideshow и интеграция с ActiveAdmin (см. цикл статей "Rails Blog") уже имеют место быть.

 

 

Что же, с места в карьер. Добавляем в Gemfile и инсталлируем:

 

# ActiveRecord::JSONValidator makes it easy to validate JSON attributes against a JSON schema.
gem 'activerecord_json_validator', '~> 2.0.0'

 

Мы собираемся проверять данные (вводимые администратором блога во вкладке ActiveAdmin) на соответствие актуальным стандартам JSON, добавив, кроме того, еще и собственные критерии валидации. Для чего создаем этот профайл:

config/schemas/slideshow.rb

{
  "type": "object",
  "$schema": "http://json-schema.org/draft-04/schema#",
  "properties": {
    "resize_to_limit": { "type": "array" },
    "monochrome": { "type": "boolean" },
    "kuwahara": {"type": "string"},
    "sepia-tone": {"type": "string"},
    "quality": { "type": "integer" },
    "polaroid": { "type": "integer" }
  },
  "required": ["resize_to_limit"]
}

 

 Короткой строкой и в скобках. В "properties" находятся опции ImageMagick, которые мы намереваемся использовать в ActiveStorage::Variant для нарезки превью изображений. Забегая вперед: демо того, что в итоге получилось, можно взглянуть здесь.

 

Теперь добавляем в модель...

 

  PROFILE_JSON_SCHEMA = Pathname.new(Rails.root.join('config', 'schemas', 'slideshow.json'))
  validates :options, presence: true, json: {
    schema: PROFILE_JSON_SCHEMA,
    message: ->(errors) { errors }
  }

 

...и все уже должно работать. Пробуйте: в случае несоответствия параметров указанным критериям вкладка ActiveAdmin отобразит message с описанием допущенных ошибок. Помните, обещано было сделать сообщение информативным? - done.

Впрочем, "пробовать" будем по-взрослому, написав тесты RSpec. Предлагаю как-то так:

 

В качестве live demo вы в любой момент можете клонировать репозиторий CRUD-Blog и поэкспериментировать с описанными тестами.

 

require 'rails_helper'

RSpec.describe Slideshow, type: :model do
    describe 'validates data column' do
      subject { described_class.new(options: options) }
      let(:valid_data) do
      {
        "resize_to_limit": [1, 2],
        "kuwahara": 'string',
        "polaroid": 1
      }
    end

    describe 'valid data' do
      let(:options) { valid_data }
      it { is_expected.to be_valid }
    end

    describe 'value type is invalid (case 1)' do
      let(:options) { valid_data.merge quality: 'string' }
      it { is_expected.not_to be_valid }
    end

    describe 'value type is invalid (case 2)' do
      let(:options) { valid_data.merge monochrome: 'array' }
      it { is_expected.not_to be_valid }
    end

    describe 'value type is valid' do
      let(:options) { valid_data.merge monochrome: true }
      it { is_expected.to be_valid }
    end

    describe 'missing a optional element' do
      let(:options) { valid_data.except :kuwahara }
      it { is_expected.to be_valid }
    end

    describe 'missing a necessary element' do
      let(:options) { valid_data.except :resize_to_limit }
      it { is_expected.not_to be_valid }
    end
  end
end

 

Всего шесть тестов: для начала убеждаемся, что данные :valid_data адекватны, затем добавляем к ним один за другим пару элементов, где value принадлежат типу данных, противоречащих указанным в профайле, и еще один, где значение соответствует нужному; напоследок удаляем необязательный элемент и, наконец, обязательный. Все тесты должны пройти:

 

$ bundle exec rspec spec/models/slideshow_spec.rb 
......

Finished in 0.33026 seconds (files took 10.42 seconds to load)
6 examples, 0 failures

Оставить комментарий

Добавьте ваш комментарий

Заказать сайт

Веб-разработка. Заказать сайт

Вы можете заказать сайт-визитку, блог, корпоративный сайт, интернет-магазин или коммерческий web-портал.