Search code examples
ruby-on-railsruby-on-rails-4

Create if record does not exist


I have 3 models in my rails app

class Contact < ActiveRecord::Base
  belongs_to :survey, counter_cache: :contact_count
  belongs_to :voter
  has_many :contact_attempts
end

class Survey < ActiveRecord::Base
  has_many :questions
  has_many :contacts
end

class Voter < ActiveRecord::Base
  has_many :contacts
end

the Contact consists of the voter_id and a survey_id. The Logic of my app is that a there can only be one contact for a voter in any given survey.

right now I am using the following code to enforce this logic. I query the contacts table for records matching the given voter_id and survey_id. if does not exist then it is created. otherwise it does nothing.

if !Contact.exists?(:survey_id => survey, :voter_id => voter)
   c = Contact.new
   c.survey_id = survey
   c.voter_id = voter
   c.save
end

Obviously this requires a select and a insert query to create 1 potential contact. When I am adding potentially thousands of contacts at once.

Right now I'm using Resque to allow this run in the background and away from the ui thread. What can I do to speed this up, and make it more efficient?


Solution

  • You should add first a database index to force this condition at the lowest level as possible:

    add_index :contacts, [:voter_id, :survey_id], unique: true
    

    Then you should add an uniqueness validation at an ActiveRecord level:

    validates_uniqueness_of :voter_id, scope: [:survey_id]
    

    Then contact.save will return false if a contact exists for a specified voter and survey.

    UPDATE: If you create the index, then the uniqueness validation will run pretty fast.