Rails:同时创建的重复记录

时间:2017-07-24 21:49:51

标签: ruby-on-rails ruby

我的Rails应用程序发生了一些奇怪的事情。每次用户访问我之前创建的唯一URL时,都会调用控制器操作并将记录保存到表中。

不幸的是,有时会创建两个相同的记录而不是一个。我添加了一个“validates_uniqueness_of”,但它没有用。

我的控制器代码:

class ShorturlController < ApplicationController
  def show
    @shorturl = ShortUrl.find_by_token(params[:id])
    @card = Card.find(@shorturl.card_id)
    @subscriber = BotUser.find_by_sender_id(params['u'])
    @letter_campaign = Letter.find(@card.letter_id).campaign_name.downcase

    if AnalyticClic.where(card_id: @card.id, short_url_id: @shorturl.id, bot_user_id: @subscriber.id).length != 0
      @object = AnalyticClic.where(card_id: @card.id, short_url_id: @shorturl.id, bot_user_id: @subscriber.id)
      @ccount = @object[0].clicks_count
      @object.update(updated_at: Time.now, clicks_count: @ccount += 1)
    else
      AnalyticClic.create(card_id: @card.id, short_url_id: @shorturl.id, bot_user_id: @subscriber.id, clicks_count: "1".to_i)
    end

    @final_url = @card.cta_button_url

    redirect_to @final_url, :status => 301
  end
end

模特:

class AnalyticClic < ApplicationRecord
  validates_uniqueness_of :bot_user_id, scope: :card_id
end

知道有时为什么我有重复的记录? if应该阻止以及validates_uniqueness_of。

enter image description here

2 个答案:

答案 0 :(得分:1)

首先,我相信你的验证可能需要看起来像(虽然,TBH,你的语法可能没问题):

class AnalyticClic < ApplicationRecord
  validates :bot_user_id, uniqueness: { scope: :card_id }
end

然后,我认为你应该稍微清理你的控制器。类似的东西:

class ShorturlController < ApplicationController
  def show
    @shorturl = ShortUrl.find_by_token(params[:id])
    @card = Card.find(@shorturl.card_id)
    @subscriber = BotUser.find_by_sender_id(params['u'])
    @letter_campaign = Letter.find(@card.letter_id).campaign_name.downcase

    analytic_clic.increment!(:click_count, by = 1)

    @final_url = @card.cta_button_url

    redirect_to @final_url, :status => 301
  end

private

  def analytic_clic
    @analytic_clic ||= AnalyticClic.find_or_create_by(
      card_id: @card.id, 
      short_url_id: @shorturl.id, 
      bot_user_id: @subscriber.id
    )
  end

end 

需要注意的几个重要事项:

您需要创建一个在数据库级别强制实现唯一性的索引(正如最大的pleaner所说)。我相信这看起来像是:

class AddIndexToAnalyticClic < ActiveRecord::Migration
  def change
    add_index :analytic_clics [:bot_user_id, :card_id], unique: true, name: :index_bot_user_card_id
  end
end

您需要创建一个迁移,在创建时将:click_count设置为默认值0(否则,您会遇到nil问题,我怀疑)。

而且,您需要考虑increment!的并发性(请参阅docs

答案 1 :(得分:0)

您需要在数据库表中创建唯一索引。可能有两个进程共同创建条件。停止这些重复记录的唯一方法是在数据库级别具有唯一性约束。