我有一个注册表,其中包含对模型和数据库的验证,以防止重复的条目。
我在生产中使用蜜巴格来记录我的错误。当用户尝试使用相同的凭据注册时,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
endrequire '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类型。基本上是希望两者之间保持一致。
此外,任何关于规范的指导和更好的格式它将非常感谢。我在这方面做得很糟糕。
发布于 2019-07-26 23:15:28
您在生产中看到ActiveRecord::RecordNotUnique,但在本地看到ActiveModel::Errors的原因可能是由于生产中的竞态条件,您没有在本地复制。
也就是说,在生产中可能发生的情况是,唯一性验证正在通过,因为试图同时创建两个具有重复信息的记录,并且每个正在运行的记录都是有效的,因为它们都在数据库中找不到具有相同电子邮件地址的现有记录。其中一次创建成功,然后第二次失败,因为第一次在第二次执行唯一性查询之后但在执行插入之前被数据库持久化。
在您的测试环境中,两次尝试的创建是顺序进行的,而不是同时进行的,因此第二次尝试不会通过唯一性检查。
要测试控制器的生产行为,您需要存根PrimeSignup.create并让它引发ActiveRecord::RecordNotUnique错误。
虽然你没有问这个,但我也会给你一个替代方法的建议,因为我恰好是Honeybadger的联合创始人之一……:)您可以在Honeybadger配置中将email参数添加到list of filtered parameters,然后该PII将不会与其余的错误信息一起报告。
发布于 2019-07-26 23:27:38
这样,如果验证失败,Rails验证应该不允许保存,而且您根本不需要处理救援异常。
def resource
@resource ||= PrimeSignup.find_or_initialize_by(resource_params)
if @resource.save
Honeybadger.notify(
@resource.errors.full_messages,
error_message: @resource.errors.full_messages.join(', ')
)
end
end
endhttps://stackoverflow.com/questions/57222383
复制相似问题