Ця стаття пояснює, як правильно відображати повідомлення про валідацію для асоційованих моделей у Rails, коли використовується зв'язок has_many.
Наприклад, якщо модель User має кілька записів Book, ми розглянемо, як належним чином відображати помилки валідації з моделі Book на стороні моделі User.
Приклад:
- Модель
User:has_many :books - Модель
Book: полеtitleє обов'язковим
# user.rb
class User < ApplicationRecord
has_many :books, dependent: :destroy
end
# book.rb
class Book < ApplicationRecord
belongs_to :user
validates :title, presence: true
end
Якщо ми виконаємо @user.save!, залишивши поле title у моделі Book порожнім, виникне помилка валідації в моделі Book, що спричинить виключення ActiveRecord::RecordInvalid.
Однак перевірка user.errors.full_messages поверне лише загальне повідомлення, таке як "Books is invalid".
Щоб вирішити це, ми розглянемо методи відображення більш детальних повідомлень про валідацію для асоційованих моделей.
Висновок
Отримання детальних повідомлень про валідацію замість "Books is invalid"
Метод 1: Використання accepts_nested_attributes_for
За допомогою accepts_nested_attributes_for валідація дочірніх моделей може бути оброблена безпосередньо у формі батьківської моделі.
class User < ApplicationRecord
has_many :books, dependent: :destroy
accepts_nested_attributes_for :books
end
Створення форми (users/new.html.erb)
<%= form_with(model: @user, local: true) do |form| %>
<%= form.label :name %>
<%= form.text_field :name %>
Books
<%= form.fields_for :books do |book_form| %> <%= book_form.label :title, "Book Title" %> <%= book_form.text_field :title %> <% end %> <%= form.submit "Save" %> <% end %>
Переваги:
- Дозволяє одночасно створювати та оновлювати батьківську і дочірні моделі в межах однієї форми.
- Зберігає код компактним.
Недоліки:
- Деякі розробники надають перевагу уникати використання accepts_nested_attributes_for.
Метод 2: Реалізація власної валідації в батьківській моделі
Додавання власної валідації в модель User дозволяє відображати помилки валідації моделі Book у моделі User.
class User < ApplicationRecord
has_many :books, dependent: :destroy
validate :validate_books
private
def validate_books
errors.delete(:books) if errors[:books].present?
books.each do |book|
next if book.valid?
book.errors.full_messages.each do |msg|
errors.add(:books, "Book #{book.id}: #{msg}")
end
end
end
Переваги:
- Дозволяє більш детально контролювати повідомлення про помилки валідації.
- Об'єднує обробку помилок у батьківській моделі.
Недоліки:
- Потрібно явне викликання valid?.
- Вплив на продуктивність при обробці великої кількості асоційованих записів.
Метод 3: Використання autosave: true
Встановлення autosave: true гарантує, що під час збереження батьківської моделі асоційовані моделі також автоматично зберігаються та валідуються.
class User < ApplicationRecord
has_many :books, dependent: :destroy, autosave: true
end
Це означає, що виклик User.save також збереже і перевірить асоційовані записи Book, додавши помилки до User, якщо це необхідно.
Переваги:
- Дозволяє автоматичне збереження без використання accepts_nested_attributes_for.
- Усуває потребу в явних викликах valid?.
Недоліки:
- Кастомізація повідомлень про помилки валідації стає складнішою.
- Проблеми з продуктивністю можуть виникнути при обробці великої кількості асоційованих записів.
Резюме
Знову ж таки, таблиця нижче є підсумком цієї статті.
Який метод слід вибрати?
- Для простого впровадження: Використовуйте
accepts_nested_attributes_for. - Для детальнішого контролю над повідомленнями про помилки валідації: Реалізуйте власну валідацію в моделі
User(Parent). - Для мінімальних змін у визначеннях моделі/контролера: Використовуйте
autosave: true.
Rails пропонує кілька способів обробки повідомлень про валідацію для асоційованих моделей. Вибирайте найкращий підхід залежно від вимог вашого проекту!
Перекладено з: Introduction