【问题标题】:Rails: Duplicate records created at the same timeRails:同时创建的重复记录
【发布时间】:2017-07-24 21:49:51
【问题描述】:

我的 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。

【问题讨论】:

标签: ruby-on-rails ruby


【解决方案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 

需要注意的一些重要事项:

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

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

【讨论】:

  • 太棒了!很高兴它有帮助。
【解决方案2】:

您需要在数据库表中创建唯一索引。可能有两个过程一起创造条件。阻止这些重复记录的唯一方法是在数据库级别设置唯一性约束。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-01
    • 1970-01-01
    • 2014-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多