【问题标题】:Uniqueness validation not functioning as expected唯一性验证未按预期运行
【发布时间】:2021-09-15 11:52:16
【问题描述】:

我有一个具有以下验证的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_idsource 的调用。例如,这些是我的数据库中的 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

【问题讨论】:

标签: ruby-on-rails validation


【解决方案1】:

validates_uniqueness_of 实际上并不能保证不能插入重复值。它仅捕获用户输入重复数据并提供用户反馈的大多数情况。它非常容易出现竞争条件,并且会被像双击阿妈这样简单的东西所挫败。

如果唯一性真的很重要,您需要在数据库层上使用唯一索引强制它。

add_index :calls, [:external_id, :source], unique: true

【讨论】:

  • 运行迁移时出现此错误:PG::UniqueViolation: ERROR: could not create unique index "idx_calls_external_id_source" DETAIL: Key (external_id, source)=(529270041, 1) is duplicated .
  • 从数据库中删除重复条目并再次尝试迁移。
猜你喜欢
  • 2021-07-29
  • 2021-09-21
  • 1970-01-01
  • 1970-01-01
  • 2017-07-19
  • 1970-01-01
  • 2013-01-21
  • 1970-01-01
相关资源
最近更新 更多