使用连接表更新记录会创建重复的条目

时间:2018-03-21 18:48:22

标签: ruby-on-rails ruby-on-rails-4 join activerecord

我有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并调用更新函数

它尝试将文档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模型中,如上所示。问题是如何防止它尝试重新添加现有记录

1 个答案:

答案 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