Philippe Lang
2006-Nov-27 17:59 UTC
Active Record, Foreign Key Object = nil and endless Optimistic Locking exception
Hi,
I have two tables:
----------------------------------------
create table project_types (
lock_version int default 0,
id serial,
name varchar(32) not null,
lookup varchar(5) not null,
primary key (id)
);
create table projects (
lock_version int default 0,
id serial,
creation_date date,
reference varchar(50),
terminated int,
customer_id int not null,
project_type_id int not null,
primary key (id),
foreign key (customer_id) references customers (id),
foreign key (project_type_id) references project_types (id)
);
----------------------------------------
class ProjectType < ActiveRecord::Base
has_many :projects
end
class Project < ActiveRecord::Base
belongs_to :project_type
end
----------------------------------------
The following code works just fine:
----------------------------------------
p1 = Project.find(1)
p1.project_type = ProjectType.find(1)
p1.save
p1.project_type = ProjectType.find(2)
p1.save
----------------------------------------
When I try saving a project which has a project_type = nil, I get an exception,
which is 100% normal, since this foreign key is "not null" in the
schema. However, I cannot figure out how to correct the object then, and give it
a better foreign key. I keep on receiving an ActiveRecord::StaleObjectError
exception, as this small example shows:
----------------------------------------
begin
p1 = Project.find(1)
p1.project_type = nil
p1.save
rescue Exception => e
puts e
puts "-------------------------------------"
begin
p1.project_type = ProjectType.find(1)
p1.save
rescue Exception => e
puts e
puts "-------------------------------------"
end
end
----------------------------------------
-------------------------------------
RuntimeError: ERROR C23502 Mnull value in column
"project_type_id" violates
not-null constraint FexecMain.c L1818 RExecConstraints: UPDATE
projects
SET "creation_date" = ''2006-12-12'',
"customer_id" = 1, "reference" = ''re
f 1'', "terminated" = 1, "project_type_id" = NULL,
"lock_version" = 201
WHERE id = 1
AND lock_version = 200
-------------------------------------
Attempted to update a stale object
-------------------------------------
If I replace "nil" with ProjectType.new, things work as expected:
----------------------------------------
begin
p1 = Project.find(1)
p1.project_type = ProjectType.new
p1.save
rescue Exception => e
puts e
puts "-------------------------------------"
begin
p1.project_type = ProjectType.find(1)
p1.save
rescue Exception => e
puts e
puts "-------------------------------------"
end
end
----------------------------------------
-------------------------------------
RuntimeError: ERROR C23502 Mnull value in column "name" violates
not-null c
onstraint FexecMain.c L1818 RExecConstraints: INSERT INTO project_ty
pes ("name", "lock_version", "lookup")
VALUES(NULL, 0, NULL)
-------------------------------------
The object gets corrected in the rescue.
I have the feeling that assigning nil to a foreign key is perfectly acceptable,
no?
---------------
Philippe Lang
Attik System