Посмотрите видео к этому посту https://www.youtube.com/watch?v=gAXs3xhfHVg. Спасибо за подписку!
При создании платформы электронной коммерции Thoughts & Fitness я столкнулся с очень интересной проблемой. Мой клиент хотел иметь возможность создавать ежедневные тренировки на своем сайте. Каждая тренировка будет иметь определенное количество подъемов, и количество подъемов для каждой тренировки будет варьироваться.
Обычно при работе со связанными моделями мы склонны использовать вложенные ресурсы, но в этом сценарии вложенные ресурсы сделают добавление упражнений к каждой тренировке очень громоздким. Мне нужна была динамическая форма, которая позволила бы мне легко добавлять новые формы для каждого упражнения в ежедневных тренировках.
Если вам легче учиться с помощью видео, посмотрите версию этого поста на YouTube https://www.youtube.com/watch?v=gAXs3xhfHVg.
Конфигурация файла Gem
В этом уроке мы будем использовать гемы Simple Form и tailwindcss-rails. Simple Form делает написание форм Rails очень простым. Я считаю, что TailwindCSS намного лучше, чем Bootstrap, потому что он дает мне больше контроля, позволяя применять отдельные точки останова к каждому из моих классов, а также содержит больше компонентов, чем Bootstrap. Кроме того, мы собираемся использовать гем simple_form_tailwinded, который стилизует все наши формы.
Давайте приступим к настройке нашего файла gem.
gem "tailwindcss-rails", "~> 0.3.3" gem 'simple_form' gem 'simple_form-tailwind'
Для краткости я не буду описывать команды для установки всех этих драгоценных камней, но все их git-страницы указаны выше.
Создание наших моделей
У нас будет две модели DailyWorkouts и Lift. Каждый DailyWorkout будет иметь фокус, т.е. над какой частью тела мы работаем сегодня и будет много подъемов. Каждое упражнение будет иметь название, количество подходов, количество повторений и будет принадлежать ежедневной тренировке.
rails g model DailyWorkout focus rails g model Lift name sets:integer reps:integer daily_workout:references rails db:migrate
Ссылки — это способ добавления внешнего ключа к нашей модели лифта. Этот ключ будет равен идентификатору DailyWorkout, которому принадлежит наш лифт.
Наш файл модели лифта должен выглядеть так:
class Lift < ApplicationRecord belongs_to :daily_workout end
И наша Ежедневная тренировка должна выглядеть так:
class DailyWorkout < ApplicationRecord has_many :lifts accepts_nested_attributes_for :lifts end
Согласно документации Rails, помощник accepts_nested_attributes_for позволяет нам сохранять связанные записи через его родителя. В основном это означает, что мы собираемся создавать все наши упражнения с помощью нашей модели DailyWorkout.
Контроллер
Давайте создадим наш ежедневный контроллер тренировок, не забудьте настроить маршруты!.
rails g controller DailyWorkouts new create
Теперь наш контроллер должен выглядеть так:
class DailyWorkoutsController < ApplicationController def new @daily_workout = DailyWorkout.new @daily_workout.lifts.build end def create @daily_workout = DailyWorkout.create(daily_workout_params) if @daily_workout.save flash[:success] = "A daily Workout Was Created !" redirect_to root_path else render :new end end private def daily_workout_params params.require(:daily_workout).permit(:focus, lifts_attributes: %i[name sets reps]) end end
Внутри нашего нового действия мы создаем DailyWorkout и используем помощник сборки active_record, чтобы добавить набор упражнений в нашу ежедневную тренировку. Действие создания ничем не отличается от действия стандартной модели.
Наш метод daily_workout_params допускает значения: фокус нашей тренировки и атрибуты для каждого упражнения. Давайте начнем стилизовать наши представления.
Вид
Прежде чем мы сделаем нашу форму динамической, мы собираемся запрограммировать ее так, чтобы мы строили только одно упражнение для нашей ежедневной тренировки. Поскольку эта форма уже очень сложна, важно, чтобы мы максимально упростили ее, прежде чем переходить к более сложным задачам.
# new.html.erb <%= simple_form_for @daily_workout do |f| %> <%= f.input :focus %> <%= f.simple_fields_for :lifts do |w| %> <div id='fieldsetContainer'> <fieldset id="0" class="text-indigo-500"> <%= w.input :name %> <%= w.input :sets %> <%= w.input :reps %> <% end %> </fieldset> </div> <%= f.button :submit %> <% end %> <br/> <button id=”addLift” onclick="addLift()"> Add another lift </button>
Метод simple_fields_for используется для создания обёртки для наших лифтов, он почти такой же, как и хелпер fields_for по умолчанию в Rails. После нашей формы мы создаем кнопку, которая будет вызывать функцию JavaScript при нажатии. Эта функция будет отвечать за добавление новой формы Лифта, что даст нам возможность добавлять больше Лифтов в нашу коллекцию.
Я поместил тег script непосредственно под HTML и включил ведение журнала консоли для отладки, посмотрите код ниже:
<script> const addWorkout = ()=> { const lastId = document.querySelector('#fieldsetContainer').lastElementChild.id; console.log(lastId) const newId = parseInt(lastId,10) + 1 console.log(newId) const newFieldset = document.querySelector('[id="0"]').outerHTML.replace(/0/g, newId) console.log(newFieldset) document.querySelector("#fieldsetContainer").insertAdjacentHTML("beforeend", newFieldset) } </script>
По сути, все, что мы делаем, это находим идентификатор последней созданной формы лифта, создаем новую форму с идентификатором N + 1 и добавляем эту форму в наш HTML.
Вот и все для этого урока, надеюсь, вы чему-то научились!
Обязательно подпишитесь!
Ютуб: https://www.youtube.com/channel/UCfd8A1xfzqk7veapUhe8hLQ
Подкаст Кори Корнер: https://anchor.fm/coreys-corner