Skip to content

Allow override of PostgreSQL UUID primary key default #10404

Merged
merged 1 commit into from May 1, 2013

2 participants

@chadmoone

bc8ebef adds the ability to define tables with primary keys which use PostgreSQL's native UUID type, which is pretty sweet 😄.

However, because PostgreSQL does not itself provide a usable default value or UUID generator function, thePostgreSQLAdapter implementation sets the default value to uuid_generate_v4(), which is a function provided by an external extension (uuid-ossp) that is not enabled by default in PostgreSQL (it is also not supported by some distributions of PostgreSQL—notably Heroku's Postgres.app).

This default can currently only be overridden by either passing another UUID generation function (which will also not be enabled by default), or passing an actual static UUID value, which is not appropriate for a primary key.

This patch allows the :default option on a table definition to be set to nil, which will set no default value.

Setting the default value to nil will require you to always generate a UUID before saving a record (likely in a model's or concern's before_save callback), but it will at least allow you to use the UUID primary key feature without extensions or external libraries.

I also tried to add a little documentation that will hopefully help people looking into this in the future. Please let me know if you have any feedback or suggestions.

(Tagging @tenderlove, as this is the patch the he and I discussed in the rails-core mailing list.)

@rafaelfranca rafaelfranca commented on an outdated diff May 1, 2013
...tive_record/connection_adapters/postgresql_adapter.rb
def primary_key(name, type = :primary_key, options = {})
return super unless type == :uuid
- options[:default] ||= 'uuid_generate_v4()'
@rafaelfranca
Ruby on Rails member
rafaelfranca added a note May 1, 2013

Maybe

options[:default] = options.fetch(:default, 'uuid_generate_v4()')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@rafaelfranca rafaelfranca commented on an outdated diff May 1, 2013
...tive_record/connection_adapters/postgresql_adapter.rb
@@ -330,9 +330,40 @@ def json(name, options = {})
class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
include ColumnMethods
+ # Defines the primary key field.
+ # Use of the native PostgreSQL UUID type is supported, and can be used
+ # by defining your tables as such:
+ #
+ # create_table :stuffs, id: :uuid do |t|
+ # t.string :content
+ # t.timestamps
+ # end
+ #
+ # By default, this will use the +uuid_generate_v4()+ function from the
+ # +uuid-ossp+ extension, which MUST be enabled on your databse. To enable
+ # the +uuid-ossp+ extension, you can use the +enable_extension+ method in your
+ # migrations To use a UUID primary key without +uuid-ossp+ enabled, you can
+ # set the +:default+ option to nil:
+ #
@rafaelfranca
Ruby on Rails member
rafaelfranca added a note May 1, 2013

Please remove the trailing spaces after the #

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@rafaelfranca rafaelfranca commented on an outdated diff May 1, 2013
...tive_record/connection_adapters/postgresql_adapter.rb
+ # t.string :content
+ # t.timestamps
+ # end
+ #
+ # By default, this will use the +uuid_generate_v4()+ function from the
+ # +uuid-ossp+ extension, which MUST be enabled on your databse. To enable
+ # the +uuid-ossp+ extension, you can use the +enable_extension+ method in your
+ # migrations To use a UUID primary key without +uuid-ossp+ enabled, you can
+ # set the +:default+ option to nil:
+ #
+ # create_table :stuffs, id: false do |t|
+ # t.primary_key :id, :uuid, default: nil
+ # t.uuid :foo_id
+ # t.timestamps
+ # end
+ #
@rafaelfranca
Ruby on Rails member
rafaelfranca added a note May 1, 2013

Please remove the trailing spaces after the #

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@rafaelfranca rafaelfranca commented on an outdated diff May 1, 2013
...tive_record/connection_adapters/postgresql_adapter.rb
+ # migrations To use a UUID primary key without +uuid-ossp+ enabled, you can
+ # set the +:default+ option to nil:
+ #
+ # create_table :stuffs, id: false do |t|
+ # t.primary_key :id, :uuid, default: nil
+ # t.uuid :foo_id
+ # t.timestamps
+ # end
+ #
+ # You may also pass a different UUID generation function from +uuid-ossp+
+ # or another library.
+ #
+ # Note that setting the UUID primary key default value to +nil+
+ # will require you to assure that you always provide a UUID value
+ # before saving a record (as primary keys cannot be nil). This might be
+ # done via the SecureRandom.uuid method and a +before_save+ callback,
@rafaelfranca
Ruby on Rails member
rafaelfranca added a note May 1, 2013

Please remove the trailing spaces after the ,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@rafaelfranca rafaelfranca commented on an outdated diff May 1, 2013
activerecord/test/cases/adapters/postgresql/uuid_test.rb
+
+ @connection.transaction do
+ @connection.create_table('pg_uuids', id: false) do |t|
+ t.primary_key :id, :uuid, default: nil
+ t.string 'name'
+ end
+ end
+ end
+
+ def teardown
+ @connection.execute 'drop table if exists pg_uuids'
+ end
+
+ def test_id_allows_default_override_via_nil
+ col_desc = @connection.execute("SELECT pg_get_expr(d.adbin, d.adrelid) as default
+ FROM pg_attribute a
@rafaelfranca
Ruby on Rails member
rafaelfranca added a note May 1, 2013

Please remove the trailing spaces after the a

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@rafaelfranca
Ruby on Rails member

Thank you so much. Your patch is very good.

Congratulations for the nice documentation.

I did some stylistic comments.

@chadmoone

Thanks for the feedback!

My bad on the trailing spaces, I need to get my linter to check for that...

I'll get the tweaks in and squashed shortly.

@chadmoone chadmoone allow override of uuid_generate_v4() default by passing default: nil
without this, it's not possible to use UUID primary keys without uuid-ossp installed and activated
55c40c0
@chadmoone

Ok, that should include everything mentioned above. Let me know if you see anything else.

@rafaelfranca rafaelfranca merged commit 09ac177 into rails:master May 1, 2013
@rafaelfranca
Ruby on Rails member

Thank you

@chadmoone chadmoone deleted the chadmoone:fix-pg-uuid-default branch May 1, 2013
@chadmoone chadmoone referenced this pull request in carbonfive/raygun May 2, 2013
Closed

Use postgres UUIDs for primary keys #85

@kamipo kamipo added a commit to kamipo/rails that referenced this pull request Oct 27, 2015
@kamipo kamipo Allow bigint with default nil for avoiding auto increment primary key
Such as #10404, #18206.
68cfeb0
@kamipo kamipo added a commit to kamipo/rails that referenced this pull request Oct 27, 2015
@kamipo kamipo Allow bigint with default nil for avoiding auto increment primary key
Such as #10404, #18206.
9a5a31a
@kamipo kamipo added a commit to kamipo/rails that referenced this pull request Nov 2, 2015
@kamipo kamipo Allow bigint with default nil for avoiding auto increment primary key
Such as #10404, #18206.
2ee48c2
@kamipo kamipo added a commit to kamipo/rails that referenced this pull request Nov 2, 2015
@kamipo kamipo Allow bigint with default nil for avoiding auto increment primary key
Such as #10404, #18206.
06b8e0e
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.