UPDATE: Using a Postgres UUID field is a great way if you don’t care about the format of the unique field. See http://blog.arkency.com/2014/10/how-to-start-using-uuid-in-activerecord-with-postgresql/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Add a unique index in your migrations like this: | |
# add_index :table, :code, unique: true | |
before_create :set_code | |
around_save :save_with_unique_code | |
def self.generate_code | |
SecureRandom.hex(2).upcase | |
end | |
def set_code(force = false) | |
self.code = self.class.generate_code if code.nil? || force | |
end | |
def save_with_unique_code | |
begin | |
self.class.connection.execute("SAVEPOINT before_record_create;") | |
yield | |
# NOTE: be careful if you have other unique fields! | |
rescue ActiveRecord::RecordNotUnique | |
set_code(true) | |
self.class.connection.execute("ROLLBACK TO SAVEPOINT before_record_create;") | |
retry | |
end | |
end |
Also see example 40-2 in the Postgres doc for a similar concept in pure PL/pgSQL: http://www.postgresql.org/docs/current/static/plpgsql-control-structures.html#PLPGSQL-ERROR-TRAPPING
Though I like your approach a lot more, since it doesn’t require stored procedures.
Thanks. I was hoping there is some built-in unique hash generation in postgres, that would be really nice. The PL/pgSQL approach is nice in case you expect collisions to happen often.
Thanks
Check out the update, in my opinion that’s a pretty neat way to do it and much more robust too.