我发现这个答案here应该能够解决我的问题但事实证明答案是针对一对多的关联。顺便说一下,我正在使用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
都是这样的
因此,当用户选中带有标签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
答案 0 :(得分:0)
终于得到了这个任务的答案。我的整个方法都是错误的,试图直接插入连接表(它永远不会起作用!)。
经过多次阅读后,This article帮助我弄明白了我的错误。在花了大约3天的时间来寻找解决方案之后,在3分钟内解决问题。
在模型中,接受连接表的嵌套属性,如下所示:
src <- osmsource_api(url = "https://api.openstreetmap.org/api/0.6/")
在阅读cocoon gem documentation时,我发现这个陈述是有道理的。
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: []
现在你的HTML元素应该是这样的:
.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
希望这会有所帮助。