PlankTon
PlankTon

Reputation: 12605

Rails ActiveRecord:: Proper way for validating presence on associations?

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

Upvotes: 1

Views: 136

Answers (1)

cristian
cristian

Reputation: 8744

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

Upvotes: 2

Related Questions