问题
I have a Rails association between models Project
and Queue
. A project has_many queues. A queue must have a project, and consequently has a presence validation on project_id
Suppose I want to create a new project WITH queues. For example, something like this:
project = Project.new(valid: param, options: here)
project.queues << Queue.new(other_valid: param, options: here)
project.save!
The save is going to fail because the queues fail the project_id presence validation.
My usual ugly way of getting around this is to create a project, then add queues, and wrap the whole lot in a transaction so that if any part of the process fails, it rolls back. ...Somehow that seems uglier than it should be.
So, is there a more graceful way of creating queues on a new project without hitting the presence validation, but still assert that those queues must have a project?
Cheers
回答1:
Try to use the build method on your queues association, like this:
project = Project.new(valid: param, options: here)
project.queues.build(other_valid: param, options: here) //this will build the queue and set its project_id to your current project.
project.save!
Just to be sure that your project_id has the correct value, before calling project.save!
insert this line:
project.queues.each do |queue|
puts queue.project_id
end
So what's wrong with your code?
project = Project.new(valid: param, options: here) //build a new project - this is not yet persisted, so your id column is nil
project.queues << Queue.new(other_valid: param, options: here) // this line tries to save the queue to the database, does not wait for you to call project.save!
project.save!
When you call:
project.queues << Queue.new(other_valid: param, options: here)`
Rails tries to save your new queue to the database, but since your project is not saved, queue.project_id
is nil so your queue validation fails.
If you try something similar with a project fetched from the database (a persisted project), your code will work without errors.
If you still want to use something similar, save the project before adding a new queue on it, like this:
project = Project.new(valid: param, options: here)
if project.save
project.queues << Queue.new(other_valid: param, options: here) //this guarantees that project_id exists
end
来源:https://stackoverflow.com/questions/24226116/rails-activerecord-proper-way-for-validating-presence-on-associations