使用 Rails 中的 Cocoon gem 通过嵌套属性更新关联模型上的多个复选框

2023-11-29

我找到了这个答案here这应该能够解决我的问题,但事实证明答案是一对多关联。顺便说一句,我正在使用 Rails 5.2

在我的多对多中,我有一个任务模型 has_manytest_methods通过tasks_test_methods where 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 and 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">

I want to have all these test_methods in the new task form like this 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 part

= 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

终于得到了这个任务的答案。我的整个方法是错误的,试图直接插入到连接表中(这是永远行不通的!)。

本文在阅读了多次之后,帮助我找出了我的错误。经过大约 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>

希望这可以帮助。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Rails 中的 Cocoon gem 通过嵌套属性更新关联模型上的多个复选框 的相关文章

随机推荐