Reputation: 13262
Maybe it's been too long since I've used Rails but I can't figure out why this works (creating a Task
and then assigning prerequisites
using #prerequisite_ids=
):
[3] pry(main)> task = Task.create(name:"do this last")
=> #<Task:0x00007fb0e2570860
id: 7,
name: "do this last",
...>
[4] pry(main)> task.prerequisite_ids=[5,6]
=> [5, 6]
[5] pry(main)> task.prerequisites
=> [#<Task:0x00007fb0e2a82948
id: 5,
name: "Do this first",
...>
#<Task:0x00007fb0e2a82600
id: 6,
name: "Do this next",
...>]
But this doesn't (passing an array of prerequisite_ids
to Task.create
)
[1] pry(main)> t = Task.create(name:"do this last", prerequisite_ids:[5,6])
Task Load (1.3ms) SELECT "tasks".* FROM "tasks" WHERE "tasks"."id" IN ($1, $2) [["id", 5], ["id", 6]]
(0.3ms) BEGIN
(0.2ms) ROLLBACK
=> #<Task:0x00007fb0e0e93d40 id: nil, name: "do this last", description: nil, created_at: nil, updated_at: nil, completed: false>
[2] pry(main)> t.errors
=> #<ActiveModel::Errors:0x00007fb0e2b18b00
@base=#<Task:0x00007fb0e0e93d40 id: nil, name: "do this last", description: nil, created_at: nil, updated_at: nil, completed: false>,
@details={:prerequisite_tasks=>[{:error=>:invalid}, {:error=>:invalid}]},
@messages={:prerequisite_tasks=>["is invalid"]}>
The <<
operator also works to add prerequisites
. And ta = Task.create(name:"do this last", prerequisites:[Task.find(5), Task.find(6)]
similarly does not work.
My Model and Controller (even though I guess the controller doesn't actually factor in here):
class Task < ApplicationRecord
has_many :prerequisite_tasks, foreign_key: :do_second_id
has_many :prerequisites, through: :prerequisite_tasks, source: :do_first
end
class PrerequisiteTask < ApplicationRecord
belongs_to :do_first, class_name: :Task
belongs_to :do_second, class_name: :Task
end
class TasksController < ApplicationController
def index
render json: Task.all
end
def show
task = Task.find(params[:id])
render json: task
end
def create
task = Task.create task_params
render json: task, status: 201
end
end
def task_params
params.require(:task).permit :name, :description, :completed, prerequisite_ids: []
end
I've gotten my tests to pass with this workaround:
def create
task = Task.create task_params.except(:prerequisite_ids)
task.update prerequisite_ids: task_params[:prerequisite_ids]
render json: task, status: 201
end
Prying into the tests shows that the created object AND the returned json both have the correct prerequisite_ids
. So it appears to work.
However, when I try to POST
from Postman, it's not accepting the prerequisite_ids
update:
Started POST "/tasks?task[name]=Post%20from%20Postman&task[description]=Testing%20value%20types&task[completed]=true&task[prerequisite_ids]=[5,6]" for ::1 at 2019-04-26 23:57:12 +0000
Processing by TasksController#create as */*
Parameters: {"task"=>{"name"=>"Post from Postman", "description"=>"Testing value types", "completed"=>"true", "prerequisite_ids"=>"[5,6]"}}
Unpermitted parameter: :prerequisite_ids
(0.6ms) BEGIN
↳ app/controllers/tasks_controller.rb:12
Task Create (1.2ms) INSERT INTO "tasks" ("name", "description", "created_at", "updated_at", "completed") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["name", "Post from Postman"], ["description", "Testing value types"], ["created_at", "2019-04-26 23:57:12.373180"], ["updated_at", "2019-04-26 23:57:12.373180"], ["completed", true]]
↳ app/controllers/tasks_controller.rb:12
(1.1ms) COMMIT
↳ app/controllers/tasks_controller.rb:12
Unpermitted parameter: :prerequisite_ids
(0.6ms) BEGIN
↳ app/controllers/tasks_controller.rb:13
Task Load (0.5ms) SELECT "tasks".* FROM "tasks" WHERE 1=0
↳ app/controllers/tasks_controller.rb:13
Task Load (1.0ms) SELECT "tasks".* FROM "tasks" INNER JOIN "prerequisite_tasks" ON "tasks"."id" = "prerequisite_tasks"."do_first_id" WHERE "prerequisite_tasks"."do_second_id" = $1 [["do_second_id", 15]]
↳ app/controllers/tasks_controller.rb:13
(0.2ms) COMMIT
↳ app/controllers/tasks_controller.rb:13
[active_model_serializers] Rendered TaskSerializer with ActiveModelSerializers::Adapter::Attributes (1.58ms)
Completed 201 Created in 55ms (Views: 7.9ms | ActiveRecord: 5.1ms)
The returned object:
{
"id": 16,
"name": "Post from Postman",
"description": "Testing value types",
"completed": true,
"prerequisite_ids": []
}
Upvotes: 0
Views: 37
Reputation: 9586
prerequisite_ids
is not an attribute of the model which is why you cannot pass it into the create
method.
Instead, it's a helper method added to the class when you created the relationship with has_many :prerequisites
.
You can read more about this functionality in the Rails Guide, Methods Added by has_many, as well as in the ActiveRecord::Associations::ClassMethods docs.
Upvotes: 1