Обновите несколько флажков на модели ассоциации с помощью вложенных атрибутов с помощью Cocoon Gem в Rails - PullRequest
0 голосов
/ 17 мая 2018

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

В моем «многих ко многим» у меня есть модель «Задача», в которой есть от_мани 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

Моя таблица 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, как это enter image description here

Таким образом, когда пользователь устанавливает флажок с меткой 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

1 Ответ

0 голосов
/ 20 мая 2018

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

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

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

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

Читая документацию по кокону 1011 *, я обнаружил, что это утверждение имеет смысл. 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>

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

...