Привет, Хабр!
Работа с многоуровневыми формами в 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
:похоже на перевод какой-то древней статьи