Обновите несколько флажков в модели ассоциации с помощью вложенных атрибутов с помощью Cocoon gem в Rails

Я нашел этот ответ здесь, который должен решить мою проблему, но оказывается, что ответ предназначен для ассоциации "один ко многим". Кстати, я использую Rails 5.2

В моем «многие ко многим» у меня есть модель задачи, которая имеет_many от test_methods до tasks_test_methods, где tasks_test_methods - это таблица соединений.

class Task < ApplicationRecord
  has_many :tasks_test_methods, inverse_of: :task, :dependent => :destroy 
  has_many :test_methods, :through => :tasks_test_methods

  accepts_nested_attributes_for :tasks_test_methods, reject_if: :all_blank, allow_destroy: true
end

Вот моя модель соединительного стола tasks_test_methods

class TasksTestMethod < ApplicationRecord 
  belongs_to :task
  belongs_to :test_method

  accepts_nested_attributes_for :test_method, :reject_if => :all_blank
end

И моя модель TestMethod

class TestMethod < ApplicationRecord
  has_many :tasks_test_methods, inverse_of: :test_method, :dependent => :destroy 
  has_many :tasks, :through => :tasks_test_methods
end

Таблица My TasksTestMethods проста и принимает только task_id и test_method_id

create_table "tasks_test_methods", id: false, force: :cascade do |t|
    t.bigint "task_id", null: false
    t.bigint "test_method_id", null: false
end

У меня есть список предопределенных test_methods, которые отображаются и должны быть добавлены в task при создании. Например.

<TestMethod id: 1, name: "Visual Testing (VT)", code: nil, description: nil, category_id: 1, created_at: "2018-05-15 12:11:38", updated_at: "2018-05-15 12:11:38">

Я хочу иметь все эти test_methods в новой форме task вот так Обновите несколько флажков в модели ассоциации с помощью вложенных атрибутов с помощью Cocoon gem в Rails

Поэтому, когда пользователи устанавливают флажок с меткой Visual Testing, новая запись создается следующим образом (пример из консоли rails):

2.5.1 :176 > params = { task: { name: "Test", client_id: 1, tasks_test_methods_attributes: [test_method_id: 1]}}
 => {:task=>{:name=>"Test", :client_id=>1, :tasks_test_methods_attributes=>[{:test_method_id=>1}]}}
2.5.1 :177 > task = Task.create!(params[:task])
<ActiveRecord::Associations::CollectionProxy [#<TasksTestMethod task_id: 16, test_method_id: 2>]>

Это моя новая форма task, здесь я использую драгоценный камень кокона уже в части fields_for

= form_with(model: @task) do |f|
  .form-group
     %label Client Name:
        = f.select(:client_id, @clients.collect { |client| [ client.name, client.id ] }, { include_blank: "Select Client" }, { :class => 'form-control select2', style: 'width: 100%;' })
   .col-md-12
      = f.fields_for :tasks_test_method do |task_test_method|
        = render 'test_method_fields', f: task_test_method

А в частичке test_method_fields у меня вот что:

= collection_check_boxes :tasks_test_method, :test_method_ids, @test_methods, :id, :name do |box| 
  .form-group.row 
    .form-check.col-md-3
      = box.check_box
      %span.ml-2 
        = box.label

Приведенный выше код показывает флажки, как и ожидалось, но работает не так, как ожидалось. Может кто-нибудь посоветовать мне, как заставить эту работу работать?

Я также внес их в белый список в TasksController

tasks_test_methods_attributes: [:id, test_method_ids: []])

Это кодовая форма, создаваемая для каждого флажка в консоли браузера.

<div class = "form-check col-md-3">
  <input type = "checkbox" value = "1" name = "tasks_test_method[test_method_ids][]" id = "tasks_test_method_test_method_ids_1">
  <span class = "ml-2">
   <label for = "tasks_test_method_test_method_ids_1">Visual Testing (VT)</label>
  </span>
</div>

Проблема в том, что я не могу включить tasks_test_methods_attributes в параметры, также когда я нажимаю на 2 из test_methods и пытаюсь добавить задачу, например, я получаю это в консоли:

Parameters: {"utf8"=>"✓", "authenticity_token"=>"cuEnQNeh4iT+38AwsNduQGce5kxFcS7sFw0SAgpdvxJjVziFTnrSgzdq6LODNDxzhan2ne31YMeCcJdYL8VoSQ= = ", "task"=>{"client_id"=>"", "name"=>"", "department_id"=>"", "start_date"=>"", "offshore_flag"=>"0", "order_number"=>"", "description"=>"", "task_manager_id"=>"", "language_id"=>"", "client_ref"=>"", "testsite"=>"", "contact_person_phone"=>"", "contact_person"=>"", "contact_person_email"=>"", "information_to_operator"=>""}, "tasks_test_method"=>{"test_method_ids"=>["", "1", "2"]}, "commit"=>"Create Task"} 

Когда я пытаюсь создать Task, он создается, но без части tasks_test_methods_attributes в параметрах.

Это мой TasksController new action

def new
  @task = Task.new 
  TestMethod.all.each do |test_method|
    @task.tasks_test_methods.build(test_method_id: test_method.id)
  end
 end
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
645
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Наконец-то получил ответ на поставленную задачу. Весь мой подход был неправильным, я пытался вставить прямо в таблицу соединений (это никогда не сработает!).

эта статья помог мне понять мою ошибку, прочитав ее несколько раз. В итоге проблема была устранена за 3 минуты, после того как поиск решения занял около 3 дней.

В вашей модели примите вложенные атрибуты для объединенной таблицы следующим образом:

accepts_nested_attributes_for :tasks_test_methods, reject_if: :all_blank, allow_destroy: true

Читая документация по драгоценному камню кокона, я обнаружил, что это утверждение имеет смысл. When saving nested items, theoretically the parent is not yet saved on validation, so rails needs help to know the link between relations. There are two ways: either declare the belongs_to as optional: false, but the cleanest way is to specify the inverse_of: on the has_many. That is why we write : has_many :tasks, inverse_of: :test_method

Теперь в моей модели Task у меня

has_many :tasks_test_methods, inverse_of: :task, :dependent => :destroy 
has_many :test_methods, :through => :tasks_test_methods

Также в моей модели TestMethod у меня есть

has_many :tasks_test_methods, inverse_of: :test_method, :dependent => :destroy 
has_many :tasks, :through => :tasks_test_methods

И затем в TasksController я добавил это в параметры, test_method_ids: []

И, наконец, в форме у меня есть это:

.form-group
   = f.collection_check_boxes :test_method_ids, @test_methods, :id, :name do |test_method|
      .form-check.mb-4
         = test_method.check_box(class: "form-check-input")
         %label.form-check-label 
            %span.ml-2  
              = test_method.label

И когда теперь ваш HTML-элемент должен выглядеть так:

<div class = "form-check mb-4">
  <input class = "form-check-input" type = "checkbox" value = "1" name = "task[test_method_ids][]" id = "task_test_method_ids_1">
  <label class = "form-check-label">
   <span class = "ml-2">
     <label for = "task_test_method_ids_1">Visual Testing (VT)</label>
   </span>
  </label>
</div>

Надеюсь это поможет.

Другие вопросы по теме