使用 join table 更新记录会创建重复条目
Updating record with join table creates duplicate entries
我有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
在连接 table 值时更新它们'一样吗?
因此,当我尝试更新相关文档时,例如:
- 我最初有文档 5
- 现在我添加文档6并调用更新函数
它试图将文档 5 和 6 重新添加到数据库中,所以我得到了错误:
Completed 422 Unprocessable Entity in 9176ms
ActiveRecord::RecordInvalid (Validation failed: Document has already been taken)
这是因为我添加了以下验证:
validates_uniqueness_of :document_id, scope: :task_id
在我的 DocumentsTask 模型中,如上所示。问题是如何防止它尝试重新添加现有记录
假设 task_params[:documents]
是一个文档 ID 数组(基于您现在如何将它与 find
一起使用),您应该可以像这样快速修复:
@task.documents << Document.where(id: task_params[:documents]).where.not(task_id: @task.id)
基本上这只是在将它们分配给任务之前过滤掉已经与给定任务关联的文档。
也就是说,我建议采用更强大的方法作为长期解决方案。几个选项(在许多选项中)将任务创建的责任提取到它自己的 class 中(因此您可以更轻松地测试它并使该功能更具可移植性),或者您可以考虑覆盖 setter 任务模型中文档的方法类似于此答案描述的内容:
我有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
在连接 table 值时更新它们'一样吗?
因此,当我尝试更新相关文档时,例如:
- 我最初有文档 5
- 现在我添加文档6并调用更新函数
它试图将文档 5 和 6 重新添加到数据库中,所以我得到了错误:
Completed 422 Unprocessable Entity in 9176ms
ActiveRecord::RecordInvalid (Validation failed: Document has already been taken)
这是因为我添加了以下验证:
validates_uniqueness_of :document_id, scope: :task_id
在我的 DocumentsTask 模型中,如上所示。问题是如何防止它尝试重新添加现有记录
假设 task_params[:documents]
是一个文档 ID 数组(基于您现在如何将它与 find
一起使用),您应该可以像这样快速修复:
@task.documents << Document.where(id: task_params[:documents]).where.not(task_id: @task.id)
基本上这只是在将它们分配给任务之前过滤掉已经与给定任务关联的文档。
也就是说,我建议采用更强大的方法作为长期解决方案。几个选项(在许多选项中)将任务创建的责任提取到它自己的 class 中(因此您可以更轻松地测试它并使该功能更具可移植性),或者您可以考虑覆盖 setter 任务模型中文档的方法类似于此答案描述的内容: