Вступ

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

Щоб вирішити це, ми розглянемо методи відображення більш детальних повідомлень про валідацію для асоційованих моделей.

Висновок

pic

Отримання детальних повідомлень про валідацію замість "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?.

Недоліки:
- Кастомізація повідомлень про помилки валідації стає складнішою.
- Проблеми з продуктивністю можуть виникнути при обробці великої кількості асоційованих записів.

Резюме

Знову ж таки, таблиця нижче є підсумком цієї статті.

pic

Який метод слід вибрати?

  • Для простого впровадження: Використовуйте accepts_nested_attributes_for.
  • Для детальнішого контролю над повідомленнями про помилки валідації: Реалізуйте власну валідацію в моделі User(Parent).
  • Для мінімальних змін у визначеннях моделі/контролера: Використовуйте autosave: true.

Rails пропонує кілька способів обробки повідомлень про валідацію для асоційованих моделей. Вибирайте найкращий підхід залежно від вимог вашого проекту!

Перекладено з: Introduction

Leave a Reply

Your email address will not be published. Required fields are marked *