Привет, Хабр!
Работа с многоуровневыми формами в Ruby on Rails — это то, что точно поднимет ваш скилл в Ruby. В этой рассмотрим, как упростить этот процесс с помощью двух гемов: Wicked и Cocoon.
Многоуровневые формы позволяют собирать информацию от пользователя поэтапно, что делает интерфейс более дружелюбным.
Настройка и конфигурация гемов Wicked и Cocoon для Rails
Wicked
Для начала добавляем Wicked в Gemfile:
gem 'wicked'
Затем выполняем команду bundle install для установки гема.
Wicked превращает контроллер в магический многоэтапный процесс. Начинаем с создания нового контроллера или модификации существующего, добавив в него миксин Wicked::Wizard. Например:
rails g controller after_signup
В контроллер добавляем:
include Wicked::Wizard
steps :first_step, :second_step
В config/routes.rb указываем, что контроллер должен использовать магические маршруты:
resources :after_signup, only: [:show, :update], controller: 'after_signup'
Юзаем render_wizard для управления переходами между шагами. Например:
def show
@user = current_user
render_wizard
end
В update методе можно обработать ввод данных и переход к след. шагу.
Cocoon
Аналогично как и с Wicked, добавляем следующую строку в Gemfile:
gem 'cocoon'
Выполняемbundle install.
С Cocoon можно легко работать с вложенными атрибутами, например в форме можно использовать link_to_add_association и link_to_remove_association для динамического добавления или удаления полей.
Пример использования в форме с помощью simple_form:
<%= simple_form_for @user do |f| %>
<%= f.simple_fields_for :addresses do |address| %>
<%= render 'address_fields', f: address %>
<% end %>
<%= link_to_add_association 'add address', f, :addresses %>
<% end %>
В частичном представлении _address_fields.html.erb можно использовать link_to_remove_association для добавления возможности удаления.
Cocoon автоматически работает с jQuery через application.js:
//= require jquery
//= require cocoon
На стороне клиента можно использовать события Cocoon, такие как cocoon:before-insert и cocoon:after-insert, для добавления пользовательских анимаций или логики обработки:
$(document).on('cocoon:before-insert', function(e, insertedItem) {
// анимация или другие действия перед вставкой элемента
insertedItem.fadeIn('slow');
});
$(document).on('cocoon:after-insert', function(e, insertedItem) {
// действия после вставки элемента
});
Обработка и валидация данных формы
Rails предоставляет множество хелперов для валидации, таких как presence, length, numericality, и format, которые помогают убедиться, что данные соответствуют определённым требованиям. Например, чтобы убедиться, что поле не пустое и соответствует определённой длине, можно использовать следующие валидации в модели:
class Comment < ApplicationRecord
validates :content, presence: true, length: { maximum: 500 }
end
Если данные не проходят валидацию, объект не будет сохранён в БД, а ошибки можно будет проверить через метод errors объекта.
Еще можно определить собственные методы валидации для более спец. требований, используя хелпер validate. Например, если нужно проверить, что текст не содержит ненормативной лексики, можно определить такой метод:
class Comment < ApplicationRecord
validate :check_for_offensive_language
private
def check_for_offensive_language
if content.include?('offensive_word')
errors.add(:content, 'contains offensive language')
end
end
end
При работе с формами и API, важно правильно обрабатывать ошибки валидации и передавать их юзеру. В контроллере можно организовать проверку валидности объекта и соответствующим образом формировать ответ:
class UsersController < ApplicationController
def create
user = User.new(user_params)
if user.save
render json: user, status: :created
else
render json: { errors: user.errors.full_messages }, status: :unprocessable_entity
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password)
end
end
Так можно отображать пользователю конкретные ошибки, связанные с каждым полем формы.
Тестирование
Для тестирования многоуровневых форм рекомендуется использовать сочетание RSpec и Capybara:
describe "Multi-step form", type: :feature do
it "processes the form correctly" do
visit new_registration_path
fill_in 'Name', with: 'Kolya'
click_button 'Next'
fill_in 'Address', with: '123 Lenina St'
click_button 'Submit'
expect(page).to have_content('Registration successful')
end
end
Для детальной отладки можете использовать гем Pry. С ним можно остановить выполнение кода в любой точке и изучить текущее состояние переменных и логику выполнения:
class RegistrationsController < ApplicationController
def create
binding.pry # остановка и отладка в этой точке
@user = User.new(user_params)
if @user.save
redirect_to @user
else
render :new
end
end
end
Также не забываем логировать основные парамтеры:
Rails.logger.debug "Processing step 1 with data: #{params[:user]}"
Для более сложных многоуровневых форм можно юзать интеграционные тесты. Создавайте тестовые объекты с помощью FactoryBot и проверяйте ассоциации и валидации с помощью Shoulda Matchers:
describe User, type: :model do
it { should validate_presence_of(:email) }
it "has a valid factory" do
user = build(:user)
expect(user).to be_valid
end
end
Все лучшие практики веб-разработки на Ruby on Rails можно освоить на практическом онлайн-курсе.
Комментарии (2)

klondaiker
15.05.2024 17:18Сейчас за место Cocoon лучше использовать уже готовый stimulus компонент
https://www.stimulus-components.com/docs/stimulus-rails-nested-form
leotada
>Cocoon автоматически работает с jQuery через
application.js:похоже на перевод какой-то древней статьи