即使验证失败,update_attributes也会更改属性



例如,如果我在prop1时运行test.update_attributes prop1: 'test', prop2: 'test2',并且prop2具有阻止这些值的验证,则test.prop1仍将'test'test.prop2仍将'test2'。为什么会发生这种情况,我该如何解决?

根据 Rails 文档 for update_attributes ,它是 update 的别名。其来源如下:

# File activerecord/lib/active_record/persistence.rb, line 247
def update(attributes)
  # The following transaction covers any possible database side-effects of the
  # attributes assignment. For example, setting the IDs of a child collection.
  with_transaction_returning_status do
    assign_attributes(attributes)
    save
  end
end

因此,它被包装在数据库事务中,这就是回滚发生的原因。但是,让我们看看 assign_attributes .根据其来源:

# File activerecord/lib/active_record/attribute_assignment.rb, line 23
def assign_attributes(new_attributes)
  ...
  _assign_attribute(k, v)
  ...
end

这被定义为:

# File activerecord/lib/active_record/attribute_assignment.rb, line 53
def _assign_attribute(k, v)
  public_send("#{k}=", v)
rescue NoMethodError
  if respond_to?("#{k}=")
    raise
  else
    raise UnknownAttributeError.new(self, k)
  end
end

所以,当你打电话给test.update_attributes prop1: 'test', prop2: 'test'时,它基本上归结为:

test.prop1 = 'test'
test.prop2 = 'test'
test.save

如果 save 未通过验证,我们的内存中副本test仍具有修改后的prop1prop2值。因此,我们需要使用 test.reload 并且问题得到解决(即我们的数据库和内存版本都保持不变)。

tl;dr 在失败的update_attributes调用后使用test.reload

尝试将其包装在 if 语句中:

if test.update(test_params)
  # your code here
else
  # your code here  
end

这是按设计工作的。例如,update控制器方法通常如下所示:

def update
  @test = Test.find(params[:id])
  if @test.update(test_attributes)
    # redirect to index with success messsage
  else
    render :edit
  end
  private
  def test_attributes
    # params.require here
  end
end

然后,render :edit将重新显示表单,其中包含错误消息和填写的错误值供用户更正。因此,您实际上确实希望模型实例中提供不正确的值。

相关内容

  • 没有找到相关文章

最新更新