I found this answer here which should be able to solve my problem but turns out that answer is for a one to many association. Btw, i'm using Rails 5.2
In my many to many, I have a Task model which has_many test_methods
through tasks_test_methods
where tasks_test_methods
is a join 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
Here is my join table model tasks_test_methods
class TasksTestMethod < ApplicationRecord
belongs_to :task
belongs_to :test_method
accepts_nested_attributes_for :test_method, :reject_if => :all_blank
end
And my TestMethod model
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 is simple and only receives the 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
I have a list of predefined test_methods
that are displayed and needs to be added to a task
upon creation. For example.
<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
So when users checks a checkbox with label Visual Testing
a new record is created like this (an example from the rails console):
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>]>
This is my new task
form, here I'm using cocoon gem already in the 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
And in the test_method_fields
partial I have this:
= 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
The above code shows the checkboxes as expected, but doesn't work as expected. Can someone guide me on how to make this work?
I have also whitelisted these in the TasksController
tasks_test_methods_attributes: [:id, test_method_ids: []])
This is the code form produces for each checkbox in the browser console
<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>
The problem is I can't get the tasks_test_methods_attributes
into the params, also when I click on 2 of the test_methods
and try to add a task, for example, I get this in the console:
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"}
When I try to create a Task
, it's been created but without the tasks_test_methods_attributes
part in the params.
This is my 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