diff options
| author | Teddy Wing | 2017-11-29 16:47:55 +0100 |
|---|---|---|
| committer | Teddy Wing | 2017-11-29 17:11:43 +0100 |
| commit | 8e9eb5d09ec8aa482afe33c7009c9ab78fdc6ede (patch) | |
| tree | 65824d2fffc97374d80718b4bb4ad88fd25ba2d3 /app | |
| parent | dba5ded7b591126c3ee690669afb23eec7e04522 (diff) | |
| download | chouette-core-8e9eb5d09ec8aa482afe33c7009c9ab78fdc6ede.tar.bz2 | |
Referential: Lock `referentials` table before validation
It was possible for two identical referentials (with the same metadata)
to be created and persisted if they were created at the same time. This
is validated by the test: `spec/models/referential_spec.rb:164`.
As a heavy-handed solution to that problem, prevent two referentials
from being created at the same time by setting a lock on the
`referentials` database table before Rails validation begins. This
prevents any other referentials from being saved at the same time as the
current one. Thanks to Alban for coming up with the lock Postgres query.
The lock should be the last `before_validation` hook that gets executed,
so we put it after the other `before_validation` definitions. We want it
to be the last one because we're trying to hold the lock for as little
time as possible.
Note that we don't need to explicitly unlock the table as this will
happen automatically at the end of the transaction.
Refs #5024
Diffstat (limited to 'app')
| -rw-r--r-- | app/models/referential.rb | 8 |
1 files changed, 8 insertions, 0 deletions
diff --git a/app/models/referential.rb b/app/models/referential.rb index ee74bd9f5..a8f387122 100644 --- a/app/models/referential.rb +++ b/app/models/referential.rb @@ -192,6 +192,7 @@ class Referential < ActiveRecord::Base before_validation :assign_line_and_stop_area_referential, :on => :create, if: :workbench before_validation :assign_slug, :on => :create before_validation :assign_prefix, :on => :create + before_validation :lock_table, :on => :create before_create :create_schema after_create :clone_schema, if: :created_from @@ -369,4 +370,11 @@ class Referential < ActiveRecord::Base not metadatas_overlap? end + private + + def lock_table + ActiveRecord::Base.connection.execute( + 'LOCK referentials IN ACCESS EXCLUSIVE MODE' + ) + end end |
