如何挽救控制器中的ActiveRecord :: RecordNotUnique错误并重新呈现表单?

时间:2018-07-13 18:33:13

标签: ruby-on-rails activerecord exception-handling

我的控制器的#create动作由于唯一性约束而失败,因为我已将其添加到Boo模型的name和title属性中。

def create
 @boo = current_user.my_boos.create(boo_params)
 respond_to do |format|
  if @boo.save
    format.html { redirect_to root_path, notice: "Thanks!" }
    format.json { render :index, status: :created, location: @boo }
  else
    format.html { render :new }
    format.json { render json: @boo.errors, status: :unprocessable_entity }
  end
 end
end

提交此操作会产生Railsy的PG::UniqueViolation: ERROR: duplicate key value violates unique constraint "index_boos_on_name_and_title"错误,我认为最好将其显示为错误消息和重新渲染的页面。

我正在阅读的所有内容都表明,从Exception救援是不好的,而从StandardError救援是好的。但是我还没有找到任何可以解释如何更好地向最终用户显示该错误而又不从Exception抢救的东西。就像,StandardError似乎不适用于数据库。

2 个答案:

答案 0 :(得分:2)

直接的答案是抢救您要从中恢复的特定异常,然后在您认为合适的情况下对其进行处理...

def create
  @boo = current_user.my_boos.new(boo_params)
  respond_to do |format|
    begin
      if @boo.save
        format.html { redirect_to root_path, notice: "Thanks!" }
        format.json { render :index, status: :created, location: @boo }
      else
        format.html { render :new }
        format.json { render json: @boo.errors, status: :unprocessable_entity }
      end
    rescue PG::UniqueViolation
      format.html { render :new }
      format.json { render json: ["We've already got one"], status: :unprocessable_entity }
    end
  end
end

(营救StandardError应该也可以,但虽然安全,但比我们需要的范围要广得多。)

但是,我建议一个更“ Railsy”的解决方案是在数据库约束之外,在模型中定义唯一性验证,因此将由现有的{ {1}}有条件。

答案 1 :(得分:2)

您可以将验证添加到Boo模型中,这将防止尝试保存无效记录,并且无需从PG :: UniqueViolation错误中恢复:

class Boo < ApplicationRecord
  # ...
  validates :name, uniqueness: { scope: :title }
  # ...
end

(c)http://guides.rubyonrails.org/active_record_validations.html#uniqueness