Вижте видеоклипа за тази публикация https://www.youtube.com/watch?v=gAXs3xhfHVg . Благодаря, че се абонирахте!

Докато изграждах платформата за електронна търговия Thoughts & Fitness, се натъкнах на много интересен проблем. Моят клиент искаше да може да създава ежедневни тренировки на своя сайт. Всяка тренировка ще има определен брой повдигания и броят на повдиганията за всяка тренировка ще варира.

Обикновено, когато работим със свързани модели, сме склонни да използваме вложени ресурси, но в този сценарий вложените ресурси биха направили много тромаво добавянето на повдигания към всяка тренировка. Имах нужда от динамична форма, която да ми позволи безпроблемно да добавям нови форми за всяко повдигане в ежедневните тренировки.

Ако е по-лесно да научите чрез видео плащане, версията в YouTube на тази публикация https://www.youtube.com/watch?v=gAXs3xhfHVg

Конфигурация на Gem файл

За този урок ще използваме скъпоценни камъни Опростена форма и 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 ще има фокус, т.е. върху коя част от тялото работим днес и ще има много повдигания. Всяко повдигане ще има име, брой серии, брой повторения и ще принадлежи към 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 позволява стойности: фокусът на нашата тренировка и атрибутите за всяко повдигане. Нека започнем да оформяме нашите възгледи.

Гледката

Преди да направим нашата форма динамична, ще я програмираме така, че да изградим само едно повдигане за нашата DailyWorkout. Тъй като този формуляр вече е много сложен, важно е да поддържаме нещата възможно най-прости, преди да преминем към сложни задачи.

# 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 се използва за създаване на обвивка за нашите асансьори, той е почти същият като помощника Rails fields_for по подразбиране. След нашия формуляр създаваме бутон, който ще извика функция на JavaScript при щракване. Тази функция ще отговаря за добавянето на нов формуляр за повдигане, като по този начин ни дава възможност да добавяме още повдигачи към нашата колекция.

Поставих маркера на скрипта директно под 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.

Това е всичко за този урок, надявам се, че сте научили нещо!

Не пропускайте да се абонирате!

Youtube: https://www.youtube.com/channel/UCfd8A1xfzqk7veapUhe8hLQ

Corey’s Corner Podcast: https://anchor.fm/coreys-corner