rails-uuid-pk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7e1ef0fefbc7527b8c728500ad6280dd8f3fd8ab1aaf3c7fe708b952c8bae326
4
+ data.tar.gz: db36f10be02bbac2fe2befb4993489a3b9ad346e4b798a0af1a885c89bd883f4
5
+ SHA512:
6
+ metadata.gz: d16161f270f32d71e76cb02339954bf3abd378f1d6a652ebfde0f5ab85e44147a1216969dc5b9e47f1a25bc89a37487bdc63dd983d67941c4de0f53c325b699e
7
+ data.tar.gz: f4720b5cbd0d71bbdb78fd2157b09bbe6a886264f9b4460274a00cef3141ba18b6fa0c5afaf7b66354bffb2dc49ea92165f6729fe4c1c5c43f8b84985ca61232
data/CHANGELOG.md ADDED
@@ -0,0 +1,18 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v1.0.0.html).
7
+
8
+ ## [0.1.0] - 2026-01-07
9
+
10
+ ### Added
11
+ - Initial release with UUIDv7 primary key support for Rails applications
12
+ - Automatic UUIDv7 generation using `SecureRandom.uuid_v7`
13
+ - Railtie for automatic inclusion in all ActiveRecord models
14
+ - Generator for installation and setup
15
+ - Support for PostgreSQL and SQLite databases
16
+ - Comprehensive test suite
17
+ - AGENTS.md file for LLM coding agent guidance
18
+ - Development section in README.md with setup and testing instructions
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright Joon Lee
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,177 @@
1
+ # rails-uuid-pk
2
+
3
+ **Dead-simple UUIDv7 primary keys for modern Rails apps**
4
+ Works great with **PostgreSQL 18+** and **SQLite 3.51+** — zero extra extensions required.
5
+
6
+ [![Gem Version](https://img.shields.io/gem/v/rails-uuid-pk.svg?style=flat-square)](https://rubygems.org/gems/rails-uuid-pk)
7
+ [![Ruby](https://img.shields.io/badge/ruby-≥3.3-red.svg?style=flat-square)](https://www.ruby-lang.org)
8
+ [![Rails](https://img.shields.io/badge/rails-≥8.1-9650f9.svg?style=flat-square)](https://rubyonrails.org)
9
+
10
+ ## Why this gem?
11
+
12
+ - Uses **native** `SecureRandom.uuid_v7` (Ruby 3.3+)
13
+ - Automatically sets `:uuid` as default primary key type
14
+ - Adds reliable `before_create` callback for UUIDv7 generation
15
+ - Works perfectly on **both PostgreSQL 18+** and **SQLite** (and older PostgreSQL versions too)
16
+ - Zero database extensions needed
17
+ - Minimal and maintainable — no monkey-patching hell
18
+
19
+ ## Installation
20
+
21
+ Add to your `Gemfile`:
22
+
23
+ ```ruby
24
+ gem "rails-uuid-pk", "~> 0.1"
25
+ ```
26
+
27
+ Then run:
28
+
29
+ ```bash
30
+ bundle install
31
+ rails generate rails_uuid_pk:install
32
+ ```
33
+
34
+ The generator will:
35
+
36
+ - Set `primary_key_type: :uuid` in your generators config
37
+ - Create `app/models/concerns/has_uuidv7_primary_key.rb` (optional explicit include)
38
+ - Show important compatibility notes
39
+
40
+ ## Usage
41
+
42
+ After installation, **every new model** you generate will get a `uuid` primary key with automatic UUIDv7 values:
43
+
44
+ ```bash
45
+ rails g model User name:string email:string
46
+ # → creates id: :uuid with automatic uuidv7 generation
47
+ ```
48
+
49
+ That's it! No changes needed in your models.
50
+
51
+ ```ruby
52
+ # This works out of the box:
53
+ User.create!(name: "Alice") # ← id is automatically a proper UUIDv7
54
+ ```
55
+
56
+ ## Important Compatibility Notes
57
+
58
+ ### Action Text & Active Storage
59
+
60
+ **These Rails engines do NOT automatically respect the `primary_key_type: :uuid` setting** when generating their install migrations.
61
+
62
+ When you run:
63
+
64
+ ```bash
65
+ rails action_text:install
66
+ rails active_storage:install
67
+ ```
68
+
69
+ You **MUST** manually edit the generated migration and change:
70
+
71
+ ```ruby
72
+ t.references :record, null: false, polymorphic: true, index: false
73
+ # to
74
+ t.references :record, null: false, polymorphic: true, index: false, type: :uuid
75
+ ```
76
+
77
+ Same applies to `active_storage_attachments.record_id`.
78
+
79
+ **Without this change** you will get:
80
+
81
+ - `PG::DatatypeMismatch` errors
82
+ - Duplicate key violations on uniqueness indexes
83
+ - Association failures
84
+
85
+ This is a **long-standing Rails limitation** (still present in Rails 8+).
86
+ The gem shows a big warning during installation — but double-check every time you install these engines.
87
+
88
+ ### Other polymorphic associations
89
+
90
+ Any **custom polymorphic** association you create manually should also explicitly use `type: :uuid` if the parent models use UUID primary keys.
91
+
92
+ ```ruby
93
+ # Good
94
+ has_many :comments, as: :commentable, foreign_key: { type: :uuid }
95
+
96
+ # Risky (may cause type mismatch)
97
+ has_many :comments, as: :commentable
98
+ ```
99
+
100
+ ## Features / Trade-offs
101
+
102
+ | Feature | Status | Notes |
103
+ |--------------------------------------|-----------------|-----------------------------------------------------------------------|
104
+ | UUIDv7 generation | Automatic | Uses `SecureRandom.uuid_v7` (very good randomness + monotonicity) |
105
+ | PostgreSQL 18+ native `uuidv7()` | Not used | Fallback approach — more universal, no extensions needed |
106
+ | SQLite support | Full | No native function → app-side generation works great |
107
+ | Index locality / performance | Very good | UUIDv7 is monotonic → almost as good as sequential IDs |
108
+ | Zero config after install | Yes (mostly) | Except Action Text / Active Storage migrations |
109
+ | Works with Rails 7.1 – 8+ | Yes | Tested conceptually up to Rails 8.1+ |
110
+
111
+ ## Why not use native PostgreSQL `uuidv7()`?
112
+
113
+ While PostgreSQL 18+ has excellent native `uuidv7()` support, the **fallback approach** was chosen for maximum compatibility:
114
+
115
+ - Works on SQLite without changes
116
+ - Works on older PostgreSQL versions
117
+ - No need to manage database extensions
118
+ - Zero risk when switching databases or in CI/test environments
119
+
120
+ You can still add native PostgreSQL defaults manually if you want maximum performance — the gem's fallback is safe and will simply be ignored.
121
+
122
+ ## Development
123
+
124
+ ### Devcontainer Setup
125
+
126
+ This project includes a devcontainer configuration for VS Code. To get started:
127
+
128
+ 1. Open the project in VS Code
129
+ 2. When prompted, click "Reopen in Container" (or run `Dev Containers: Reopen in Container` from the command palette)
130
+ 3. The devcontainer will set up Ruby 3.3, Rails, and all dependencies automatically
131
+
132
+ ### Running Tests
133
+
134
+ The project includes a comprehensive test suite that runs against both SQLite and PostgreSQL.
135
+
136
+ ```bash
137
+ # Run all tests (SQLite + PostgreSQL)
138
+ ./bin/test
139
+
140
+ # Run tests for specific database
141
+ DB=sqlite ./bin/test # SQLite only
142
+ DB=postgres ./bin/test # PostgreSQL only
143
+ ```
144
+
145
+ ### Code Quality
146
+
147
+ ```bash
148
+ # Run RuboCop for style checking
149
+ ./bin/rubocop
150
+
151
+ # Auto-fix RuboCop offenses
152
+ ./bin/rubocop -a
153
+ ```
154
+
155
+ ### Building the Gem
156
+
157
+ ```bash
158
+ # Build the gem
159
+ gem build rails_uuid_pk.gemspec
160
+
161
+ # Install locally for testing
162
+ gem install rails-uuid-pk-0.1.0.gem
163
+ ```
164
+
165
+ ### Database Setup
166
+
167
+ For PostgreSQL testing, ensure PostgreSQL is running and accessible. The test suite uses these environment variables:
168
+ - `DB_HOST` (defaults to localhost)
169
+ - `RAILS_ENV=test_postgresql` for PostgreSQL tests
170
+
171
+ ## Contributing
172
+
173
+ Bug reports and pull requests are welcome on GitHub at https://github.com/seouri/rails-uuid-pk.
174
+
175
+ ## License
176
+
177
+ The gem is available as open source under the terms of the [MIT License](MIT-LICENSE).
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ require "bundler/setup"
2
+
3
+ require "bundler/gem_tasks"
@@ -0,0 +1,17 @@
1
+ # app/models/concerns/has_uuidv7_primary_key.rb
2
+ # (this file is copied by the generator - you can modify it later if needed)
3
+
4
+ module HasUuidv7PrimaryKey
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ before_create :assign_uuidv7_if_needed, if: -> { id.nil? }
9
+ end
10
+
11
+ private
12
+
13
+ def assign_uuidv7_if_needed
14
+ return if id.present?
15
+ self.id = SecureRandom.uuid_v7
16
+ end
17
+ end
@@ -0,0 +1,45 @@
1
+ module RailsUuidPk
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ source_root File.expand_path("templates", __dir__)
5
+
6
+ desc "Installs rails-uuid-pk: sets uuid primary key + includes UUIDv7 concern"
7
+
8
+ def add_concern_file
9
+ copy_file "has_uuidv7_primary_key.rb",
10
+ "app/models/concerns/has_uuidv7_primary_key.rb"
11
+ end
12
+
13
+ def show_next_steps
14
+ say "\nrails-uuid-pk was successfully installed!", :green
15
+
16
+ say "\n⚠️ IMPORTANT - Action Text & Active Storage compatibility", :red
17
+ say "─────────────────────────────────────────────────────────────"
18
+ say "When you run any of these commands:"
19
+ say " rails action_text:install"
20
+ say " rails active_storage:install"
21
+ say ""
22
+ say "You **MUST** manually edit the generated migration and add:"
23
+ say ""
24
+ say " t.references :record, null: false, polymorphic: true, index: false, type: :uuid"
25
+ say ""
26
+ say "Without this change you'll get type mismatch errors (bigint vs uuid)."
27
+ say "This is a Rails limitation - see Rails guides for details."
28
+ say "─────────────────────────────────────────────────────────────\n"
29
+
30
+ say "\nRecommended next steps:", :yellow
31
+ say " 1. Add to ApplicationRecord (if you prefer explicit include):"
32
+ say " class ApplicationRecord < ActiveRecord::Base"
33
+ say " primary_abstract_class"
34
+ say " include HasUuidv7PrimaryKey"
35
+ say " end\n"
36
+
37
+ say " 2. Or keep relying on Railtie automatic include (recommended for most cases)\n"
38
+
39
+ say " 3. Now you can run:", :cyan
40
+ say " rails g model User name:string email:string\n"
41
+ say " → will create table with uuid primary key + automatic uuidv7\n"
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,17 @@
1
+ # app/models/concerns/has_uuidv7_primary_key.rb
2
+ # (this file is copied by the generator - you can modify it later if needed)
3
+
4
+ module HasUuidv7PrimaryKey
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ before_create :assign_uuidv7_if_needed, if: -> { id.nil? }
9
+ end
10
+
11
+ private
12
+
13
+ def assign_uuidv7_if_needed
14
+ return if id.present?
15
+ self.id = SecureRandom.uuid_v7
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ module RailsUuidPk
2
+ module HasUuidv7PrimaryKey
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ before_create :assign_uuidv7_if_needed, if: -> { id.nil? }
7
+ end
8
+
9
+ private
10
+
11
+ def assign_uuidv7_if_needed
12
+ # Skip if id was already set (manual set, bulk insert with ids, etc)
13
+ return if id.present?
14
+
15
+ self.id = SecureRandom.uuid_v7
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,40 @@
1
+ module RailsUuidPk
2
+ class Railtie < ::Rails::Railtie
3
+ initializer "rails-uuid-pk.generators" do |app|
4
+ app.config.generators do |g|
5
+ g.orm :active_record, primary_key_type: :uuid
6
+ end
7
+ end
8
+
9
+ initializer "rails-uuid-pk.configure_database" do |app|
10
+ # For SQLite, use SQL schema format since schema.rb has issues with UUID types
11
+ if app.config.database_configuration&.dig(Rails.env, "adapter") == "sqlite3"
12
+ app.config.active_record.schema_format = :sql
13
+ end
14
+ end
15
+
16
+ initializer "rails-uuid-pk.include_concern" do
17
+ ActiveSupport.on_load(:active_record) do
18
+ ActiveRecord::Base.include RailsUuidPk::HasUuidv7PrimaryKey
19
+ end
20
+ end
21
+
22
+ initializer "rails-uuid-pk.configure_type_map" do
23
+ ActiveSupport.on_load(:active_record) do
24
+ if ActiveRecord::Base.connection.adapter_name == "SQLite"
25
+ # Define a custom UUID type for SQLite that reports as :uuid
26
+ uuid_type = Class.new(ActiveRecord::Type::String) do
27
+ def type
28
+ :uuid
29
+ end
30
+ end.new
31
+
32
+ # Map 'uuid' SQL type to our custom UUID type
33
+ ActiveRecord::Base.connection.send(:type_map).register_type "uuid" do |sql_type|
34
+ uuid_type
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,3 @@
1
+ module RailsUuidPk
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,6 @@
1
+ require "rails_uuid_pk/version"
2
+ require "rails_uuid_pk/concern"
3
+ require "rails_uuid_pk/railtie"
4
+
5
+ module RailsUuidPk
6
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :rails_uuid_pk do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails-uuid-pk
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Joon Lee
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rails
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '8.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '8.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: pg
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: 1.6.3
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 1.6.3
40
+ - !ruby/object:Gem::Dependency
41
+ name: sqlite3
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: 2.9.0
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: 2.9.0
54
+ description: Automatically use UUIDv7 for all primary keys in Rails applications.
55
+ Works with PostgreSQL and SQLite, zero configuration required.
56
+ email:
57
+ - seouri@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - CHANGELOG.md
63
+ - MIT-LICENSE
64
+ - README.md
65
+ - Rakefile
66
+ - app/models/concerns/has_uuidv7_primary_key.rb
67
+ - lib/generators/rails_uuid_pk/install/install_generator.rb
68
+ - lib/generators/rails_uuid_pk/install/templates/has_uuidv7_primary_key.rb
69
+ - lib/rails_uuid_pk.rb
70
+ - lib/rails_uuid_pk/concern.rb
71
+ - lib/rails_uuid_pk/railtie.rb
72
+ - lib/rails_uuid_pk/version.rb
73
+ - lib/tasks/rails_uuid_pk_tasks.rake
74
+ homepage: https://github.com/seouri/rails-uuid-pk
75
+ licenses:
76
+ - MIT
77
+ metadata:
78
+ homepage_uri: https://github.com/seouri/rails-uuid-pk
79
+ source_code_uri: https://github.com/seouri/rails-uuid-pk
80
+ changelog_uri: https://github.com/seouri/rails-uuid-pk/blob/main/CHANGELOG.md
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: 3.3.0
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubygems_version: 4.0.3
96
+ specification_version: 4
97
+ summary: Dead-simple UUIDv7 primary keys for Rails apps
98
+ test_files: []