[英]Why does my production logs show an ActiveRecord::RecordNotUnique error but my local binding.pry shows me an ActiveModel::Errors?
我有一個注冊表單,其中包含對模型和數據庫的驗證,以防止重復輸入。
我在生產中使用honeybadger記錄錯誤。 當用戶嘗試使用相同的憑據進行注冊時,honeybadger報告ActiveRecord::RecordNotUnique: Mysql2::Error: Duplicate entry for ....
。 錯誤的其余部分包含我要防止的PII(我在一家金融公司工作,所以這是合規性問題)。
我的解決方案是將Model.create
包裝在救援塊中,並在報告之前自定義honeybadger錯誤。 我為此寫了一些rspec,但一直失敗。 當我在塊中包含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
類型。 基本上期望兩者之間的一致性。
同樣,任何有關規格和更好格式的指南將不勝感激。 我很糟糕。
您在生產中看到ActiveRecord::RecordNotUnique
但在本地看到ActiveModel::Errors
原因可能是由於您未在本地復制而在生產中出現競爭條件。
也就是說,在生產中可能發生的情況是,唯一性驗證正在通過,因為試圖同時創建兩個具有重復信息的記錄,並且每個運行中的記錄都是有效的,因為它們都未在數據庫中找到現有記錄使用相同的電子郵件地址。 其中一個創建成功,然后第二個失敗,因為第一個創建在第二個查詢執行其唯一性查詢之后但無法進行插入之前被數據庫保留。
在您的測試環境中,兩次嘗試的創建是順序發生的,而不是同時發生的,因此第二次嘗試不會超過唯一性檢查。
要測試控制器的生產行為,您需要對PrimeSignup.create
進行存根並將其引發ActiveRecord::RecordNotUnique
錯誤。
盡管您沒有要求,但我也將為您提供替代方法的建議,因為我恰好是Honeybadger的聯合創始人之一... :)您可以將email
參數添加到過濾參數列表中在您的Honeybadger配置中,那么該PII不會與其他錯誤信息一起報告。
這樣,如果Rails驗證通過驗證失敗,並且您根本不必處理救援異常,則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
end
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.