简体   繁体   中英

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

I am using a Twitter Gem to pull and save Tweets from user's timeline. Before saving each message , I want to check if this record already exists by comparing the new message's tweet_id to the array of tweet_id 's already saved in the db. No matter what I try, I am still seeing duplicated records being saved in the messages table. Here is what I got:

Controller call:

@messages = Message.pull_tweets(@user)

"pull_tweets" method:

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" method:

  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

The most direct cause of your problem is that tweets.each will return the tweets array, which since it is not nil or false has a truthy value: you're not using the result of your validate_uniqueness_of method.

You instead would want to either do something like

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

which returns true only if all the tweets meet your test, or more likey to be what you want

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

This would however be rather non idiomatic code. You would usually create a validation on your tweet class and add a unique index on the tweet_id column - a uniqueness validation should always be backed up by a unique index or you run the risk of rice conditions.

The validation side of things would look like

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

You can either keep using create! and rescue the validation exception that will be thrown or switch to create which returns true/false depending on what happened. In both cases ActiveRecord::RecordNotUnique will be raised if a duplicate slips past the validation

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

validates_uniqueness_of :tweet_id, scope: :user_id

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM