LewlSauce
LewlSauce

Reputation: 5862

Rails validates_uniqueness_of doesn't seem to be working for me

I'm having a hard time trying to avoid duplicates in my database and really curious to know if I'm actually doing this correctly. In the example below, my technical reports actually work perfectly fine. So there's no duplicate nodes in the technical report, even if I try to create a duplicate manually.

However, I can't say the same for the nodes' vulns. When I import the exact same file (containing data) twice, I get duplicate Vulns for the same IP when I believe it's not supposed to happen.

So here are two models that I have:

#app/models/node.rb
class Node < ActiveRecord::Base
    validates_uniqueness_of :technical_report_id, :scope => :ip    
    has_many :vulns, dependent: :destroy
end

.

#app/models/vuln.rb
class Vuln < ActiveRecord::Base
  validates_uniqueness_of :node_id, :scope => [:master_finding_id, :vuln_finding_id, :additional_output, :port]

  belongs_to :node
  belongs_to :master_finding
  belongs_to :vuln_finding
end

However, when I go to importing data, I still find myself with duplicates in the Vuln table. I've used rails c to validate this as well.

irb(main):012:0> Vuln.where(node_id: 12).pluck(:master_finding_id, :additional_output, :vuln_finding_id).length
   (0.4ms)  SELECT `vulns`.`master_finding_id`, `vulns`.`additional_output`, `vulns`.`vuln_finding_id` FROM `vulns` WHERE `vulns`.`node_id` = 12
=> 2

When I go to call .uniq it shows that there's only one entry.

irb(main):013:0> Vuln.where(node_id: 12).pluck(:master_finding_id, :additional_output, :vuln_finding_id).uniq.length
   (0.5ms)  SELECT `vulns`.`master_finding_id`, `vulns`.`additional_output`, `vulns`.`vuln_finding_id` FROM `vulns` WHERE `vulns`.`node_id` = 12
=> 1

Does anyone know what I'm doing wrong here? I'm not sure why this works for one model and not the other one. If I try to create two of the exact same Vuln records from rails c CLI, it rolls back like it should have, but not when it's created otherwise.

EDIT

Looks like my issue is with activerecord-import instead. I'm not sure why but it imports nodes just fine, but it calls the "Class Create Many Without Validations Or Callbacks" when it goes to importing vulns. Guess because there's a lot more data or something. I think I have this sort of figured out for now. Perhaps I just need to write a quick method to validate the uniqueness manually since I don't want to get rid of the mass importing gem.

Upvotes: 1

Views: 657

Answers (1)

slowjack2k
slowjack2k

Reputation: 2586

validates_uniqueness_of can not ensure uniqueness in every case. Within the docs you can see an example for the race condition within this kind of validation. If it is realy needed you should also use an uniq constraint on database level.

Upvotes: 2

Related Questions