我有3个型号如下:
class Document < ActiveRecord::Base
has_many :documents_tasks, inverse_of: :document
has_many :tasks, through: :documents_tasks, dependent: :destroy
end
class Task < ActiveRecord::Base
has_many :documents_tasks, inverse_of: :task
has_many :documents, through: :documents_tasks, dependent: :destroy
end
class DocumentsTask < ActiveRecord::Base
belongs_to :task, inverse_of: :documents_tasks
belongs_to :document, inverse_of: :documents_tasks
validates_uniqueness_of :document_id, scope: :task_id
end
在上面我尝试更新Task
的记录时,如果我保留验证,则会在DocumentsTask
模型上为重复条目引发验证错误,如果删除验证,则直接插入重复项。
我更新任务记录的代码是:
def update
@task = @coach.tasks.find(params[:id])
@task.update(:name => task_params[:name], :description => task_params[:description] )
@task.documents << Document.find(task_params[:documents])
if @task.save
render 'show'
else
render status: 500, json: {
error: true,
reason: @task.errors.full_messages.to_sentence
}
end
end
我知道我可以将unique index
添加到数据库中以自动防止重复条目,但是有哪些方法可以阻止controller
更新连接表值时它们是否相同?
因此,当我尝试更新相关文档时,例如:
它尝试将文档5和6重新添加到db中,因此我收到错误:
Completed 422 Unprocessable Entity in 9176ms
ActiveRecord::RecordInvalid (Validation failed: Document has already been taken)
这是因为我添加了以下验证:
validates_uniqueness_of :document_id, scope: :task_id
在我的DocumentsTask模型中,如上所示。问题是如何防止它尝试重新添加现有记录
答案 0 :(得分:1)
假设task_params[:documents]
是一个文档ID数组(基于您现在如何与find
一起使用),您应该可以做一些像这样的快速修复:
@task.documents << Document.where(id: task_params[:documents]).where.not(task_id: @task.id)
基本上,这只会过滤掉已经与给定任务关联的文档,然后再将它们分配给任务。
那就是说,作为一个长期的解决方案,我建议一些更强大的东西。一些选项(在众多选项中)将把任务创建的责任提取到它自己的类中(这样你可以更容易地测试它并使该功能更加便携),或者你可以考虑覆盖setter方法(s)您的任务模型中的文档与此答案描述的内容类似:https://stackoverflow.com/a/2891245/456673