Ця стаття пояснює, як правильно відображати повідомлення про валідацію для асоційованих моделей у 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