2017-07-24 93 views
0

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

不幸的是,有时会创建两个相同的记录而不是一个。我添加了“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

+0

你应该把验证检查在数据库级别上,不只是在车型。请参阅[do-rails-need-database-level-constraints](https://stackoverflow.com/questions/2589509/does-rails-need-database-level-constraints) –

回答

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_count0上创建一个默认值(否则,你就会有一个nil问题,我怀疑)。

而且,你要想想有increment!并发(见docs

+0

谢谢,它可行! – AlphaNico

+0

太棒了!很高兴帮助。 – jvillian

0

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