【发布时间】:2019-12-04 22:29:21
【问题描述】:
我有一个注册表单,其中包含对模型和数据库的验证,以防止重复条目。
我在生产环境中使用 honeybadger 来记录错误。当用户尝试使用相同的凭据进行注册时,honeybadger 会报告ActiveRecord::RecordNotUnique: Mysql2::Error: Duplicate entry for ....。错误的其余部分包含 PII,我试图阻止它(我在一家金融公司工作,所以这是一个合规问题)。
我的解决方案是将Model.create 包装在一个救援块中,并在报告之前自定义蜜獾错误。我为它写了一些 rspecs,但一直失败。当我在块中包含 binding.pry 时,我可以看到副本创建错误,但错误是 ActiveModel::Errors 的实例。现在,我可以尝试挽救ActiveModel::Errors 错误,但我担心ActiveRecord::RecordNotUnique 错误仍会记录在生产环境中,这是我正在努力改变的。
我想不通:
1) 为什么生产和本地会显示不同类型的错误?
2) 为了从我们的生产日志记录中提供自定义错误消息(并隐藏 PII),我必须从哪类错误中解救出来。
我们将不胜感激任何和所有的帮助。谢谢!
作为整体解决方案我尝试过的一些事情是:
1) 使用准备好的语句。但是这不起作用,因为我使用的 ActiveRecord (4.2.11) 版本没有准备好的语句。
2) 使用 Honeybadger 的能力忽略以下错误: https://docs.honeybadger.io/lib/ruby/getting-started/ignoring-errors.html,但是,团队决定我们不想完全关闭错误。
# /app/models/prime_signup.rb
class PrimeSignup < ActiveRecord::Base
validates_presence_of :first_name, :last_name, :email
validates :email, uniqueness: true
def person
@person ||= Person.find_by(email: email)
end
def full_name
"#{first_name} #{last_name}"
end
end
# /db/schema.rb
create_table "prime_signups", force: :cascade do |t|
t.string "first_name", limit: 255
t.string "last_name", limit: 255
t.string "email", limit: 255
t.string "phone_number", limit: 20
end
add_index "prime_signups", ["email"], name: "index_prime_signups_on_email", unique: true, using: :btree
# /app/controllers/api/v1/prime_signups_controller.rb
class API::V1::PrimeSignupsController < API::V1Controller
// omitting skip_before_actions for brevity
def create
return render_forward_compatible_json_error(json_error, resource) unless resource.valid?
service.perform
render json: resource, serializer: API::V1::PrimeSignupSerializer, status: 201
end
private
def resource_params
params.require(:prime_signup).permit(:first_name, :last_name, :email, :phone_number,
:utm_source, :utm_medium, :utm_campaign, :utm_term,
:utm_content)
end
def resource # This is the method I'm trying to rescue the error from
binding.pry
begin
@resource ||= PrimeSignup.create(resource_params)
rescue ActiveRecord::RecordNotUnique => e # This is how I'm trying to customize the error
Honeybadger.notify(
error,
error_message: 'Duplicate Entry',
)
end
end
def json_error
JSONExceptions::InvalidFieldValues.new(detail: resource_errors)
end
def resource_errors
resource.errors.messages.map {|field, message| "#{field} #{message.join}."}.join(" ")
end
def service
::Services::PrimeSignupCreation.new(resource)
end
def render_forward_compatible_json_error(error, resource)
json_error_format = { errors: [error.to_json] }
resource_key = resource.class.name.snakecase
old_error_format = {resource_key => resource.errors.details}
render json: json_error_format.merge(old_error_format), status: error.status
end
end
require 'rails_helper'
describe 'API::V1::PrimeSignups', type: :request do
describe 'POST /api/v1/prime_signups' do
context 'duplicate entry' do
it 'raises a custom honeybadger error' do
prime_signup_params = {
prime_signup: {
first_name: "Walter",
last_name: "White",
email: "walter@white.com",
phone_number: '123456789'
},
authenticity_token: 'authenticated',
format: :json
}
expect(Honeybadger).to receive(:notify)
VCR.use_cassette('/api/v1/prime_signups') do
post '/api/v1/prime_signups', prime_signup_params.to_json, { "CONTENT_TYPE"=>"application/json" }
post '/api/v1/prime_signups', prime_signup_params.to_json, { "CONTENT_TYPE"=>"application/json" }
end
expect(response.status).to eq(422)
# VCR.use_cassette('/api/v1/prime_signups') do
# post '/api/v1/prime_signups', prime_signup_params.to_json, { "CONTENT_TYPE"=>"application/json" }
# end
end
end
end
end
我希望从中救出的错误是 ActiveRecord::RecordNotUnique 类型或记录的生产错误是 ActiveModel::Errors 类型。基本上期望两者之间的一致性。
此外,我们将不胜感激任何有关规格和更好格式的指导。我不擅长。
【问题讨论】:
标签: ruby-on-rails ruby activerecord rspec activemodel