validates_uniqueness_of and MySQL unique index

Oct 11
2006 09:52 (Development, Ruby on Rails) · Русский (9,341 views)

Yesterday in mailing list of russian RoR group we have discussed following problem. MySQL database has unique index and model has validates_uniqueness_of constraint. Do we need to handle MySQL server exceptions or RoR’s validation will be enough?

I think we need, but to be sure I decided to make test. First, I created table with unique index:

class CreateCustomers < ActiveRecord::Migration
  def self.up
    create_table :customers do |t|
      t.column :name, :string
    end
    add_index :customers, :name, :unique => true
  end

  def self.down
    drop_table :customers
  end
end

Then I wrote following model:

class Customer < ActiveRecord::Base
  validates_presence_of :name, :if => lambda { |customer|
    unless @@created
      @@created = true
      Customer.create(:name => customer.name)
    end
    true
  }
  validates_uniqueness_of :name
 
  @@created = false
end

You can see two validation rules: one is uniqueness, which is the our primary goal. Second rule’s task is to create second customer between validation and insertion of first. Validations are processed in postorder, therefor validates_presence_of is going first. Now I’ve started script/console and typed:

Customer.create(:name => 'name')

You can find log file below. I think, you don’t need any comments.

SHOW FIELDS FROM customers BEGIN SELECT * FROM customers WHERE (customers.name = 'name') LIMIT 1 SELECT * FROM customers WHERE (customers.name = 'name') LIMIT 1 INSERT INTO customers (`name`) VALUES('name') Mysql::Error: #23000Duplicate entry 'name' for key 2: INSERT INTO customers (`name`) VALUES('name') ROLLBACK

Note: You right, this is broken logic, but I used it only to show what will be if two processes will insert record with the same name. You can replace code inside :if with sleep 10 and run two consoles to reproduce exception.

Post a comment

You can use simple HTML-formatting tags (like <a>, <ul> and others). To format your code sample use <code lang="php">$a = "hello";</code> (allowed languages are ruby, php, yaml, html, csharp, javascript). Also you could use <code>$a = "hello";</code> and its syntax would not be highlighted. If you are not using <code> tag, replace < sign with &lt;.

Submit Comment

 
Copyright © 2005 - 2008, Dmytro Shteflyuk