Raf Andersson Wed Aug 14 17:07:36 -0400 2013

Subject: creation with validates_uniqueness_of on primary key error

(please somebody make a search inside this forum)

There is a problem when using validates_uniqueness_of on the primary key

Database table members:
number int primary key
name varchar 255

php version 5.4.10
mysql version 5.5.29

I use this in my model:
static $validates_uniqueness_of = array(
array('number', 'message' => 'custom message', 'on' => 'create')
);

and then just do a simple create like this, where attributes is a name and a number, and the primary key:
$member = Member::create($attributes);

The error I get is not my custom message but:
Internal Server Error: 23000, 1062, Duplicate entry '3' for key 'PRIMARY'
(code 500 I believe)

then what is the point of validates_uniqueness_of if it doesn't work?

Raf


Csongor Fagyal Mon Sep 30 22:53:00 -0400 2013

validates_uniqueness_of does not work if you are validating for the primary key. Take a look at the source here:
https://github.com/kla/php-activerecord/blob/master/lib/Validations.php
At around 588-598

It basically checks whether your primary key is not the same as the value you check for, because that would result in a validation error when all you try to do is save the given record (without modification). (It should probably check whether the given field is dirty or not... but that's a different story.)

Here as a patch that might help you, even though it's probably not the best approach: it skips the magic above for new records where it doesn't make sense anyway.

Change this:

$sql = "";
$conditions = array("");
$pk_quoted = $connection->quote_name($pk[0]);
if ($pk_value === null)
$sql = "{$pk_quoted} IS NOT NULL";
else {
$sql = "{$pk_quoted} != ?";
array_push($conditions,$pk_value);
}
foreach ($fields as $field)
{
$field = $this->model->get_real_attribute_name($field);
$quoted_field = $connection->quote_name($field);
$sql .= " AND {$quoted_field}=?";
array_push($conditions,$this->model->$field);
}

To this:

$sql = "";
$conditions = array("");
$pk_quoted = $connection->quote_name($pk[0]);
if ($pk_value === null)
$sql = "{$pk_quoted} IS NOT NULL";
elseif (!$this->model->is_new_record()) {
$sql = "{$pk_quoted} != ?";
array_push($conditions,$pk_value);
}
foreach ($fields as $field)
{
$field = $this->model->get_real_attribute_name($field);
$quoted_field = $connection->quote_name($field);
$sql.= ($sql ? ' AND ': '') . " {$quoted_field}=?";
array_push($conditions,$this->model->$field);
}

(1-1/1)