ruby-on-rails - 唯一性验证未按预期运行
问题描述
我有一个Call
具有以下验证的模型:
class Call < ActiveRecord::Base
validates_uniqueness_of :external_id, scope: :source
end
我通过调用以下服务的 webhook 生成新调用:
class AircallWebhookService
include HubspotExtension
def initialize(params)
@event = params["event"]
@params = params["data"]
@call = nil
@aircall_number = nil
@employee_email = nil
end
def process
@call = Call.find_by(source: :aircall, external_id: @params["id"])
if @call.present?
p "Found existing call!"
else
p "Could not locate existing call."
@call = Call.new(source: :aircall, external_id: @params["id"])
end
@call.source = 1
@call.external_id = @params["id"]
@call.url = @params["direct_link"]
@call.direction = @params["direction"]
@call.status = @params["status"]
@call.missed_call_reason = @params["missed_call_reason"]
@call.started_at = Time.at(@params["started_at"]) if @params["started_at"].present?
@call.answered_at = Time.at(@params["answered_at"]) if @params["answered_at"].present?
@call.ended_at = Time.at(@params["ended_at"]) if @params["ended_at"].present?
@call.duration = @params["duration"]
@call.raw_digits = @params["raw_digits"]
@call.aircall_user_id = @params.dig("user", "id")
@call.contact_id = @params.dig("contact", "id")
@aircall_number = @params.dig("number", "digits").try{|n| n.gsub(/\s|-|\(|\)|\+/, "")}
@call.aircall_user_id = @params.dig("user", "id")
@employee_email = @params.dig("user", "email")
if !@params["tags"].empty?
mapTagToReferrer
end
@call.comments = mapComments
if @call.save
linkTagToCall
linkCallToEmployee
updateHubspotEngagement
end
end
...
end
出于某种原因,尽管进行了uniqueness
验证,但我仍然看到使用相同external_id
和source
. 例如,这些是我的数据库中的 2 条记录:
[
[0] #<Call:0x000055d780f639b8> {
:id => 8149,
:location_id => nil,
:referrer => nil,
:consultation => nil,
:created_at => Tue, 07 Sep 2021 15:42:01 EDT -04:00,
:updated_at => Tue, 07 Sep 2021 15:42:01 EDT -04:00,
:worldwide => nil,
:external_id => 582402916,
:source => "aircall",
:direction => "inbound",
:started_at => Tue, 07 Sep 2021 15:41:03 EDT -04:00,
:answered_at => Tue, 07 Sep 2021 15:41:10 EDT -04:00,
:ended_at => Tue, 07 Sep 2021 15:41:57 EDT -04:00,
:duration => 54,
:status => "done",
:missed_call_reason => nil,
:aircall_user_id => 567754,
:contact_id => nil,
:comments => nil,
:lead_status => nil,
:call_type => "unknown"
},
[1] #<Call:0x000055d780f636e8> {
:id => 8150,
:location_id => nil,
:referrer => nil,
:consultation => nil,
:created_at => Tue, 07 Sep 2021 15:42:01 EDT -04:00,
:updated_at => Tue, 07 Sep 2021 15:42:01 EDT -04:00,
:worldwide => nil,
:external_id => 582402916,
:source => "aircall",
:direction => "inbound",
:started_at => Tue, 07 Sep 2021 15:41:03 EDT -04:00,
:answered_at => Tue, 07 Sep 2021 15:41:10 EDT -04:00,
:ended_at => Tue, 07 Sep 2021 15:41:57 EDT -04:00,
:duration => 54,
:status => "done",
:missed_call_reason => nil,
:aircall_user_id => 567754,
:contact_id => nil,
:comments => nil,
:lead_status => nil,
:call_type => "unknown"
}
]
它们是相同的,甚至created_at
精确到毫秒。这怎么可能?
这是控制器,以备不时之需:
class API::WebhooksController < ApplicationController
def aircall_webhook
ac = AircallWebhookService.new(params)
ac.process
head :ok
end
end
解决方案
validates_uniqueness_of
实际上并不能保证不能插入重复值。它仅捕获用户输入重复数据并提供用户反馈的大多数情况。它非常容易出现竞争条件,并且被像双击阿妈这样简单的东西所挫败。
如果唯一性确实很重要,则需要在具有唯一索引的数据库层上强制执行它。
add_index :calls, [:external_id, :source], unique: true
推荐阅读
- typescript - 将接口限制为联合类型中的特定键
- sql - 每年按年分组,年+9,得到计数的总和
- rxjs - 当您无法控制发布者时,是否可以/建议使用反应式编程
- jquery - 提交动态生成的按钮
- c# - 我可以在同一接口的多个实现上“隐式”调用方法吗?
- java - Optaplanner VRPTW“验证该 sourceVariableName 变量的输入问题的一致性”
- android - Flutter:如何修复多行启用文本字段底部的 SuffixIcon?
- azure-web-app-service - 从 ASP.NET CORE WEB API 向应用程序洞察添加请求
- javascript - 如何立即更新子组件中的父状态
- salesforce - 无法在 SFCC Demandware 中保存用户选择的选项列表值