使用 Cocoon gem in Rails 通过嵌套属性更新关联模型上的多个复选框
Update multiple checkboxes on association model through nested attributes with Cocoon gem in Rails
我找到了这个答案 ,它应该能够解决我的问题,但事实证明这个答案是针对一对多关联的。顺便说一句,我正在使用 Rails 5.2
在我的多对多中,我有一个 has_many test_methods
到 tasks_test_methods
的任务模型,其中 tasks_test_methods
是一个连接 table。
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
这是我加入的table模型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 table 很简单,只接收 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">
我想在新的 task
表格中包含所有这些 test_methods
因此,当用户选中带有标签 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
部分
中使用了 cocoon gem
= 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
放入参数中,当我单击 test_methods
中的 2 个并尝试添加任务时,例如,我将其放入控制台:
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
终于得到了这个任务的答案。我的整个方法都是错误的,试图直接插入连接 table(这永远行不通!)。
This article 多次阅读后帮助我找出了错误。在花了大约 3 天时间寻找解决方案后,最终在 3 分钟内解决了问题。
在您的模型中,接受连接 table 的嵌套属性,如下所示:
accepts_nested_attributes_for :tasks_test_methods, reject_if: :all_blank, allow_destroy: true
在阅读 cocoon gem documentation 时,我发现这句话很有道理。
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>
希望这对您有所帮助。
我找到了这个答案
在我的多对多中,我有一个 has_many test_methods
到 tasks_test_methods
的任务模型,其中 tasks_test_methods
是一个连接 table。
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
这是我加入的table模型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 table 很简单,只接收 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">
我想在新的 task
表格中包含所有这些 test_methods
因此,当用户选中带有标签 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
放入参数中,当我单击 test_methods
中的 2 个并尝试添加任务时,例如,我将其放入控制台:
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
终于得到了这个任务的答案。我的整个方法都是错误的,试图直接插入连接 table(这永远行不通!)。
This article 多次阅读后帮助我找出了错误。在花了大约 3 天时间寻找解决方案后,最终在 3 分钟内解决了问题。
在您的模型中,接受连接 table 的嵌套属性,如下所示:
accepts_nested_attributes_for :tasks_test_methods, reject_if: :all_blank, allow_destroy: true
在阅读 cocoon gem documentation 时,我发现这句话很有道理。
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>
希望这对您有所帮助。