在保存到数据库之前检查记录是否存在 - Rails、Twitter、ActiveRecord

check if record exists before saving to db - Rails, Twitter, ActiveRecord

我正在使用 Twitter Gem 从用户的时间线中提取和保存推文。在保存每个 message 之前,我想通过将新消息的 tweet_id 与数据库中已保存的 tweet_id 的数组进行比较来检查此记录是否已存在。无论我尝试什么,我仍然看到重复的记录保存在 messages table 中。这是我得到的:

控制器调用:

@messages = Message.pull_tweets(@user)

"pull_tweets"方法:

def self.pull_tweets(user)

    tweets = $twitter.home_timeline  # API call to pull all tweets from the timeline

    if tweets && tweets.each { |tweet| validate_uniqueness_of(user,tweet) }
      tweets.each { |tweet| user.messages.create!(tweet_id: tweet.id ... }
      ...
    else
      ... 
    end
  end

"validate_uniqueness_of"方法:

  def self.validate_uniqueness_of(user,tweet)
    if user.messages.pluck(:tweet_id).exclude?(tweet.id.to_s)
      return true
    else
      return false
    end
  end

你的问题最直接的原因是 tweets.each 将 return tweets 数组,因为它不是 nil 或 false 有一个真值:你不是使用您的 validate_uniqueness_of 方法的结果。

你反而会想做类似

的事情
tweets.all? { |tweet| validate_uniqueness_of(user,tweet) }

只有当所有推文都符合您的测试,或者更可能是您想要的时,return才是正确的

if tweets
  tweets = tweets.select { |tweet| validate_uniqueness_of(user,tweet) }
  tweets.each { |tweet| user.messages.create!(tweet_id: tweet.id ... } 
end 

然而,这将是相当不惯用的代码。您通常会在推文 class 上创建验证并在 tweet_id 列上添加唯一性索引 - 唯一性验证应始终由唯一性索引支持,否则您 运行 的风险大米情况。

事情的验证方面看起来像

class Message < ActiveRecord::Base
  validate_uniqueness_of :tweet_id, scope: :user_id #assuming that message belongs_to :user
end

您可以继续使用 create!并拯救将抛出的验证异常或切换到 create which returns true/false 取决于发生的事情。在这两种情况下,如果重复项通过验证

,则会引发 ActiveRecord::RecordNotUnique

您还可以根据 :scope 参数验证 tweet_id 是否唯一:

validates_uniqueness_of :tweet_id, scope: :user_id