Skip to main content

Rails forms: Reform vs Model Inheritance

Сравнение

ПодходПример
Reform с собственной структурой (composition)class ListingForm < Reform::Form
Форма-наследник модели (напрямую от Listing)class ListingForm < Listing

Reform (Reform::Form + Contract)

class ListingForm < Reform::Form
property :address
property :city
property :state

validation do
required(:address).filled
required(:city).filled
required(:state).filled
end
end

Полностью независимая форма, которая:

  • валидирует без связи с ActiveRecord
  • управляет структурой полей
  • может сохранять в модель через sync + model.save
  • может объединять несколько моделей

Наследование от модели

class ListingForm < Listing
attr_accessor :some_virtual_param

validates :address, presence: true
validates :some_virtual_param, numericality: true
end

Работает как патч модели: добавляются поля и валидации прямо на модель + немного виртуальных полей.


Сравнение Reform vs наследование от модели

КритерийReform (< Reform::Form)Наследование от модели
🧱 Изоляция формы✅ Полная (никак не трогает модель)❌ Сильно зависит от модели
🎯 Валидирует только input✅ Да, это и цель❌ Наследует бизнес-валидации
🧩 Поддержка вложенных моделей✅ Через composition, collection, nested❌ Очень сложно, часто невозможна
🔁 Использует модельЧерез model (явно)Модель — это и есть форма
🧪 Тестируемость✅ Отличная❌ Путается с AR
💥 Усложнение модели❌ Нет⚠️ Модель становится перегруженной
📚 Документация и поддержка👍 Хорошая (Reform, Trailblazer)🟡 Стандартный Rails, но анти-паттерн
🧰 ВалидацииDry-validation или Reform DSLActiveRecord validation
🧬 Методы сохраненияsync, save, validate, prepopulatesave/update напрямую

Минусы Form < Model

  • Всё завязано на БД — даже если тебе нужны просто временные данные
  • Сложно тестировать — приходится поднимать БД
  • Колбэки и ассоциации модели могут мешать логике формы
  • Переиспользование ограничено — нельзя собрать из нескольких моделей

Когда Reform — победитель

  • У тебя форма, не совпадающая 1:1 с моделью
  • Нужно объединить несколько сущностей (напр. Listing + Address + Owner)
  • Хочешь использовать dry-validation или строгую структуру
  • Строишь API и хочешь единый интерфейс валидации
  • Хочешь безболезненно тестировать формы без ActiveRecord

Итог

ВыборИспользуй когда
Form < Reform::Form✅ Универсальное, масштабируемое, чистое решение
Form < Model🔧 Подходит ТОЛЬКО для очень простых UI-форм, но лучше избегать