rails-uuid-pk 0.11.0 → 0.13.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.
data/SECURITY.md ADDED
@@ -0,0 +1,321 @@
1
+ # Security Considerations
2
+
3
+ ## Supported Versions
4
+
5
+ We take security seriously and actively maintain this gem. The following versions are currently supported with security updates:
6
+
7
+ | Version | Supported | Security Support Until |
8
+ | ------- | ------------------ | ---------------------- |
9
+ | 0.13.x | :white_check_mark: | Ongoing |
10
+ | 0.12.x | :white_check_mark: | 6 months from 0.13.0 |
11
+ | 0.11.x | :white_check_mark: | 6 months from 0.12.0 |
12
+ | < 0.11 | :x: | None |
13
+
14
+ ## Reporting a Vulnerability
15
+
16
+ **Please report security vulnerabilities responsibly.**
17
+
18
+ If you discover a security vulnerability in rails-uuid-pk, please:
19
+
20
+ 1. **DO NOT** create a public GitHub issue
21
+ 2. Email security concerns to: **seouri@gmail.com**
22
+ 3. Include detailed information about:
23
+ - The vulnerability description
24
+ - Steps to reproduce
25
+ - Potential impact assessment
26
+ - Your contact information for follow-up
27
+
28
+ **Response Time**: We will acknowledge receipt within 24 hours and provide a more detailed response within 72 hours indicating our next steps.
29
+
30
+ ## Cryptographic Security Analysis
31
+
32
+ ### UUIDv7 Cryptographic Properties
33
+
34
+ This gem uses **UUIDv7** (RFC 9562) for primary key generation, which provides the following security characteristics:
35
+
36
+ > **Privacy Consideration**: UUIDv7 includes a timestamp component that reveals approximate record creation time. Do not use if creation timestamp must be hidden.
37
+ >
38
+ > **Enhanced Privacy Documentation**: Added explicit warning about UUIDv7 timestamp exposure in SECURITY.md, clarifying that UUIDv7 includes a timestamp component that reveals approximate record creation time and advising against use when creation timestamps must be hidden.
39
+
40
+ #### Strengths
41
+ - **Cryptographically Secure Generation**: Uses Ruby's `SecureRandom.uuid_v7()` backed by system CSPRNG (OpenSSL or system entropy)
42
+ - **Monotonic Ordering**: Time-based ordering prevents index fragmentation while maintaining unpredictability
43
+ - **High Entropy**: 128-bit randomness with structured time component
44
+ - **RFC 9562 Compliance**: Follows latest UUID standards
45
+
46
+ #### Known Limitations
47
+ - **Timestamp Exposure**: First 48 bits contain millisecond-precision timestamp
48
+ - **Predictability Window**: Generated UUIDs reveal creation time ± milliseconds
49
+ - **No Forward Secrecy**: Compromised keys don't affect future UUID security
50
+
51
+ ### Timestamp Exposure Considerations
52
+
53
+ ```ruby
54
+ # Example: UUIDv7 reveals generation timestamp
55
+ uuid = "017f22e2-79b0-7cc3-98c4-dc0c0c07398f"
56
+ timestamp_ms = uuid[0..7].to_i(16) >> 4 # Extract 48-bit timestamp
57
+ # This reveals the UUID was generated at: 2023-11-15 10:30:45.123 UTC
58
+ ```
59
+
60
+ **Security Impact**: An attacker observing UUIDs can determine:
61
+ - Approximate creation time of records
62
+ - Rate of record generation
63
+ - Potential correlation between UUID sequences and business activities
64
+
65
+ **Mitigations**:
66
+ - Use UUIDv4 for applications requiring maximum unpredictability
67
+ - Implement rate limiting to prevent timing attacks
68
+ - Avoid exposing UUIDs in public APIs when timing data is sensitive
69
+
70
+ ## Database Security Implications
71
+
72
+ ### Primary Key Security
73
+
74
+ #### Sequential ID Vulnerabilities (Avoided)
75
+ Traditional auto-incrementing IDs create security risks:
76
+ - **Enumeration Attacks**: `SELECT * FROM users WHERE id > 1000` reveals user count
77
+ - **Resource Discovery**: Predictable URLs enable scraping
78
+ - **Race Conditions**: Concurrent requests can leak information
79
+
80
+ #### UUIDv7 Advantages
81
+ - **Non-Enumerability**: No predictable sequence for attackers to exploit
82
+ - **Global Uniqueness**: No collision risks across distributed systems
83
+ - **Index Efficiency**: Time-ordered UUIDs provide better B-tree performance
84
+
85
+ ### Foreign Key Security Considerations
86
+
87
+ #### Polymorphic Associations
88
+ When using polymorphic references with UUID primary keys:
89
+
90
+ ```ruby
91
+ # Migration
92
+ create_table :comments do |t|
93
+ t.references :commentable, polymorphic: true, type: :uuid
94
+ end
95
+ ```
96
+
97
+ **Security Implications**:
98
+ - Foreign keys become non-guessable
99
+ - Prevents enumeration of related records
100
+ - Complicates unauthorized data access patterns
101
+
102
+ #### Join Table Exposure
103
+ Many-to-many relationships expose UUIDs in join tables:
104
+
105
+ ```ruby
106
+ # users_posts join table contains UUID foreign keys
107
+ # An attacker seeing these can correlate users with content
108
+ ```
109
+
110
+ **Recommendations**:
111
+ - Use appropriate access controls regardless of key type
112
+ - Implement row-level security when needed
113
+ - Consider UUID visibility in audit logs
114
+
115
+ ## Performance-Security Trade-offs
116
+
117
+ ### Index Performance vs Security
118
+
119
+ | Aspect | Integer Keys | UUIDv7 Keys | Security Impact |
120
+ |--------|-------------|-------------|-----------------|
121
+ | **Index Size** | 4 bytes | 16 bytes | Neutral |
122
+ | **Cache Efficiency** | Excellent | Good | Neutral |
123
+ | **Predictability** | High Risk | Low Risk | Security Benefit |
124
+ | **Fragmentation** | None | Low (monotonic) | Security Benefit |
125
+
126
+ ### Query Performance Considerations
127
+
128
+ #### Range Queries on Time
129
+ UUIDv7's time-based ordering enables efficient time-range queries:
130
+
131
+ ```ruby
132
+ # Find records from last hour (efficient with UUIDv7)
133
+ User.where("id >= ? AND id < ?", min_uuid_for_hour, max_uuid_for_hour)
134
+ ```
135
+
136
+ **Security Benefit**: Enables efficient audit logging and temporal access controls
137
+
138
+ #### Index Bloat Monitoring
139
+ Large UUID indexes may require monitoring:
140
+
141
+ ```sql
142
+ -- Monitor index bloat (PostgreSQL example)
143
+ SELECT schemaname, tablename, attname, n_distinct, correlation
144
+ FROM pg_stats
145
+ WHERE tablename = 'users' AND attname = 'id';
146
+ ```
147
+
148
+ **Recommendation**: Monitor index statistics and plan maintenance windows
149
+
150
+ ## Side-Channel Attack Vectors
151
+
152
+ ### Timing Attacks
153
+
154
+ #### UUID Generation Timing
155
+ UUID generation is fast and constant-time, but bulk operations may reveal system load:
156
+
157
+ ```ruby
158
+ # Bulk UUID generation timing can reveal system capacity
159
+ start = Time.now
160
+ 100.times { User.create!(name: "User") }
161
+ duration = Time.now - start
162
+ # Duration reveals concurrent load and system performance
163
+ ```
164
+
165
+ **Mitigation**: Implement rate limiting and monitoring
166
+
167
+ ### Information Leakage Through Errors
168
+
169
+ #### Database Error Messages
170
+ UUID validation errors may leak information:
171
+
172
+ ```ruby
173
+ # Potential information leakage
174
+ User.find("invalid-uuid") # => ActiveRecord::RecordNotFound
175
+ # vs
176
+ User.find("550e8400-e29b-41d4-a716-446655440000") # => User or Not Found
177
+ ```
178
+
179
+ **Mitigation**: Use consistent error messages regardless of UUID validity
180
+
181
+ ### Cross-Application Correlation
182
+
183
+ #### UUID Reuse Across Services
184
+ Using the same UUID generation in multiple applications can create correlation vectors:
185
+
186
+ ```ruby
187
+ # Service A: User UUID
188
+ # Service B: Order UUID with same timestamp
189
+ # Correlation: Same user placed order at same millisecond
190
+ ```
191
+
192
+ **Recommendation**: Use service-specific UUID namespaces or additional entropy
193
+
194
+ ## Dependency Security
195
+
196
+ This gem has minimal dependencies with known security postures:
197
+
198
+ ### Runtime Dependencies
199
+ - **rails (~> 8.0)**: Monitored via Rails security advisories
200
+ - **Database adapters**: Follow respective project security practices
201
+ - **pg (~> 1.6.3)**: PostgreSQL adapter (compatible with PostgreSQL 18+)
202
+ - **mysql2 (~> 0.5.7)**: MySQL adapter (compatible with MySQL 9+)
203
+ - **sqlite3 (~> 2.9.0)**: SQLite adapter
204
+
205
+ ### Development Dependencies
206
+ - Testing frameworks with regular security updates
207
+ - Code quality tools (RuboCop, RuboCop-Rails)
208
+
209
+ ## Secure Usage Guidelines
210
+
211
+ ### 1. Application-Level Security
212
+ ```ruby
213
+ # DO: Use UUIDs for public-facing identifiers
214
+ class Post < ApplicationRecord
215
+ # UUID primary key is secure by default
216
+ end
217
+
218
+ # DON'T: Don't rely on UUID secrecy alone
219
+ class User < ApplicationRecord
220
+ # Still need authentication and authorization
221
+ def visible_posts
222
+ posts.where(published: true) # Business logic access control
223
+ end
224
+ end
225
+ ```
226
+
227
+ ### 2. API Security
228
+ ```ruby
229
+ # DO: Use UUIDs in APIs
230
+ get '/posts/:id' do
231
+ post = Post.find_by!(id: params[:id])
232
+ authorize! :read, post # Authorization still required
233
+ render post
234
+ end
235
+
236
+ # DON'T: Don't assume UUIDs prevent all attacks
237
+ # Rate limiting, input validation still essential
238
+ ```
239
+
240
+ ### 3. Database Security
241
+ ```ruby
242
+ # DO: Use appropriate access controls
243
+ class ApplicationPolicy
244
+ def show?
245
+ user.admin? || record.user_id == user.id
246
+ end
247
+ end
248
+
249
+ # DON'T: Don't expose UUIDs unnecessarily
250
+ # Consider using different identifiers for public APIs
251
+ ```
252
+
253
+ ## Security Testing Recommendations
254
+
255
+ ### Automated Security Testing
256
+ ```ruby
257
+ # Add to test suite
258
+ class SecurityTest < ActiveSupport::TestCase
259
+ test "UUIDs are not predictable" do
260
+ uuids = 1000.times.map { SecureRandom.uuid_v7 }
261
+ # Verify no obvious patterns
262
+ assert uuids.uniq.length == uuids.length
263
+ end
264
+
265
+ test "timing attack resistance" do
266
+ # Verify constant-time UUID generation
267
+ times = 100.times.map do
268
+ start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
269
+ SecureRandom.uuid_v7
270
+ Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
271
+ end
272
+
273
+ variance = times.max - times.min
274
+ assert variance < 0.001 # Less than 1ms variance
275
+ end
276
+ end
277
+ ```
278
+
279
+ ### Penetration Testing Checklist
280
+ - [ ] UUID enumeration attempts
281
+ - [ ] Timing attack analysis
282
+ - [ ] Information leakage through errors
283
+ - [ ] Cross-service correlation analysis
284
+ - [ ] Database access pattern analysis
285
+
286
+ ## Security Maintenance
287
+
288
+ ### Regular Security Reviews
289
+ - **Monthly**: Dependency updates and vulnerability scans
290
+ - **Quarterly**: Security architecture review
291
+ - **Annually**: Full security assessment
292
+
293
+ ### Security Monitoring
294
+ - Monitor for unusual UUID generation patterns
295
+ - Alert on potential enumeration attacks
296
+ - Track performance degradation that might indicate attacks
297
+
298
+ ## Compliance Considerations
299
+
300
+ ### GDPR and Privacy
301
+ - UUIDs as personal data: Generally not considered personal information
302
+ - Audit logging: UUIDs provide excellent audit trails
303
+ - Data minimization: Consider if UUID exposure meets data minimization requirements
304
+
305
+ ### Industry-Specific Security
306
+ - **Healthcare (HIPAA)**: UUIDs support proper access controls
307
+ - **Financial Services**: Enhanced audit capabilities
308
+ - **Government**: Supports classification and access controls
309
+
310
+ ## Conclusion
311
+
312
+ Rails-UUID-PK provides a secure foundation for UUIDv7 primary keys with proper cryptographic properties and database security benefits. However, security is defense-in-depth: UUIDs enhance security but don't replace proper authentication, authorization, and access controls.
313
+
314
+ **Key Takeaways**:
315
+ 1. UUIDv7 provides better security than sequential IDs
316
+ 2. Timestamp exposure is a known trade-off
317
+ 3. Application-level security controls remain essential
318
+ 4. Monitor performance and security metrics in production
319
+ 5. Regular security reviews and updates are critical
320
+
321
+ For questions about security or to report vulnerabilities, contact the security team at seouri@gmail.com.
@@ -0,0 +1,183 @@
1
+ require "rails/generators/base"
2
+
3
+ module RailsUuidPk
4
+ # Rails generators for the rails-uuid-pk gem.
5
+ #
6
+ # This module contains Rails generator classes that help with migration
7
+ # and setup tasks for applications using UUID primary keys.
8
+ #
9
+ # @see RailsUuidPk::Generators::AddOptOutsGenerator
10
+ module Generators
11
+ # Rails generator that scans all ActiveRecord models in a Rails application
12
+ # and adds `use_integer_primary_key` to models that have integer primary keys
13
+ # in the database schema.
14
+ #
15
+ # This generator helps migrate existing Rails applications that use integer
16
+ # primary keys to work correctly with the rails-uuid-pk gem, which assumes
17
+ # UUID primary keys by default.
18
+ #
19
+ # @example Run the generator
20
+ # rails generate rails_uuid_pk:add_opt_outs
21
+ #
22
+ # @example Run with dry-run to see what would be changed
23
+ # rails generate rails_uuid_pk:add_opt_outs --dry-run
24
+ #
25
+ # @see RailsUuidPk::HasUuidv7PrimaryKey
26
+ # @see https://github.com/seouri/rails-uuid-pk
27
+ class AddOptOutsGenerator < Rails::Generators::Base
28
+ include Thor::Actions
29
+
30
+ desc "Scans all ActiveRecord models and adds use_integer_primary_key to models with integer primary keys"
31
+
32
+ class_option :dry_run, type: :boolean, default: false, desc: "Show what would be changed without modifying files"
33
+ class_option :verbose, type: :boolean, default: true, desc: "Provide detailed output for each model processed"
34
+
35
+
36
+
37
+ # Analyzes all ActiveRecord models and modifies those with integer primary keys.
38
+ #
39
+ # This is the main generator method that orchestrates the entire process:
40
+ # 1. Finds all model files in the application
41
+ # 2. Analyzes each model for integer primary keys
42
+ # 3. Modifies model files to add opt-out calls
43
+ # 4. Reports results to the user
44
+ #
45
+ # @return [void]
46
+ def analyze_and_modify_models
47
+ say_status :info, "Analyzing ActiveRecord models for integer primary keys...", :blue
48
+
49
+ results = analyze_models
50
+
51
+ modified_count = 0
52
+ analyzed_count = results.size
53
+
54
+ results.each do |result|
55
+ if options[:verbose]
56
+ status = case
57
+ when result[:modified] then :modified
58
+ when result[:needs_opt_out] && !result[:already_has_opt_out] then :pending
59
+ else :skipped
60
+ end
61
+ say_status status, "#{result[:model_class].name} (table: #{result[:table_name]}, pk: #{result[:primary_key_type]})", :green
62
+ end
63
+
64
+ modified_count += 1 if result[:modified]
65
+ end
66
+
67
+ say_status :success, "Analyzed #{analyzed_count} models, modified #{modified_count} files", :green
68
+ end
69
+
70
+ private
71
+
72
+ def analyze_models
73
+ model_files = find_model_files
74
+ connection = ActiveRecord::Base.connection
75
+
76
+ model_files.map do |file_path|
77
+ class_name = extract_class_name_from_file(file_path)
78
+ next unless class_name
79
+
80
+ model_class = class_name.constantize
81
+ next unless model_class < ActiveRecord::Base
82
+
83
+ table_name = model_class.table_name
84
+ next unless connection.table_exists?(table_name)
85
+
86
+ primary_key_type = check_primary_key_type(table_name, connection)
87
+ already_has_opt_out = model_file_has_opt_out?(file_path)
88
+
89
+ needs_opt_out = primary_key_type == :integer && !already_has_opt_out
90
+
91
+ modified = false
92
+ if needs_opt_out && !options[:dry_run]
93
+ modified = add_opt_out_to_model(file_path, class_name)
94
+ end
95
+
96
+ {
97
+ model_class: model_class,
98
+ table_name: table_name,
99
+ primary_key_type: primary_key_type,
100
+ needs_opt_out: needs_opt_out,
101
+ already_has_opt_out: already_has_opt_out,
102
+ file_path: file_path,
103
+ modified: modified
104
+ }
105
+ end.compact
106
+ end
107
+
108
+ def find_model_files
109
+ Dir.glob(File.join(destination_root, "app/models/**/*.rb"))
110
+ end
111
+
112
+ def extract_class_name_from_file(file_path)
113
+ content = File.read(file_path)
114
+ # Simple regex to find class definition - this is a basic implementation
115
+ # In a real scenario, you'd want to use a Ruby parser for accuracy
116
+ match = content.match(/class\s+([A-Za-z_][A-Za-z0-9_]*(?:::[A-Za-z_][A-Za-z0-9_]*)*)/)
117
+ match[1] if match
118
+ end
119
+
120
+ def check_primary_key_type(table_name, connection)
121
+ columns = connection.columns(table_name)
122
+ pk_column = columns.find { |col| col.name == "id" }
123
+ return :unknown unless pk_column
124
+
125
+ # Map database types to our categories
126
+ case pk_column.type
127
+ when :integer then :integer
128
+ when :string then pk_column.limit == 36 ? :uuid : :string
129
+ when :uuid then :uuid
130
+ else :unknown
131
+ end
132
+ end
133
+
134
+ def model_file_has_opt_out?(file_path)
135
+ content = File.read(file_path)
136
+ content.include?("use_integer_primary_key")
137
+ end
138
+
139
+ def add_opt_out_to_model(file_path, class_name)
140
+ content = File.read(file_path)
141
+
142
+ # Find the class definition line
143
+ class_match = content.match(/^(\s*)class\s+#{Regexp.escape(class_name)}/)
144
+ return false unless class_match
145
+
146
+ indent = class_match[1]
147
+
148
+ # Find where to insert - after the class definition and any initial comments/constants
149
+ lines = content.lines
150
+ insert_index = nil
151
+
152
+ lines.each_with_index do |line, index|
153
+ if line.match?(/^#{Regexp.escape(indent)}class\s+#{Regexp.escape(class_name)}/)
154
+ # Start looking for insertion point after this line
155
+ (index + 1..lines.size - 1).each do |i|
156
+ current_line = lines[i]
157
+ next if current_line.strip.empty? || current_line.match?(/^#{Regexp.escape(indent)}\s*#/)
158
+
159
+ # Insert before the first indented content or end of class
160
+ if current_line.match?(/^#{Regexp.escape(indent)}\s+\S/) || current_line.match?(/^#{Regexp.escape(indent)}end$/) || i == lines.size - 1
161
+ insert_index = i
162
+ break
163
+ end
164
+ end
165
+ break
166
+ end
167
+ end
168
+
169
+ return false unless insert_index
170
+
171
+ # Insert the opt-out method call
172
+ opt_out_line = "\n#{indent} use_integer_primary_key\n"
173
+ new_content = lines.insert(insert_index, opt_out_line).join
174
+
175
+ File.write(file_path, new_content)
176
+ true
177
+ rescue => e
178
+ say_status :error, "Failed to modify #{file_path}: #{e.message}", :red
179
+ false
180
+ end
181
+ end
182
+ end
183
+ end
@@ -190,7 +190,10 @@ module RailsUuidPk
190
190
  return false unless conn.respond_to?(:table_exists?) && conn.table_exists?(table_name)
191
191
 
192
192
  pk_column = find_primary_key_column(table_name, conn)
193
- @uuid_pk_cache[table_name] = !!(pk_column && pk_column.sql_type.downcase.match?(/\A(uuid|varchar\(36\))\z/))
193
+ @uuid_pk_cache[table_name] = !!(pk_column && pk_column.sql_type&.downcase&.match?(/\A(uuid|varchar\(36\))\z/))
194
+ rescue StandardError
195
+ # Handle database connection errors gracefully
196
+ @uuid_pk_cache[table_name] = false
194
197
  end
195
198
 
196
199
  # Finds the primary key column for a given table.
@@ -200,7 +203,8 @@ module RailsUuidPk
200
203
  # @return [ActiveRecord::ConnectionAdapters::Column, nil] The primary key column or nil
201
204
  def find_primary_key_column(table_name, conn)
202
205
  pk_name = conn.primary_key(table_name)
203
- return nil unless pk_name
206
+ # Only consider standard Rails primary keys named 'id' for UUID detection
207
+ return nil unless pk_name == "id"
204
208
 
205
209
  conn.columns(table_name).find { |c| c.name == pk_name }
206
210
  end
@@ -4,74 +4,32 @@ module RailsUuidPk
4
4
  # MySQL adapter extension for UUID type support.
5
5
  #
6
6
  # This module extends ActiveRecord's MySQL2 adapter to provide native UUID
7
- # type support. Since MySQL doesn't have a native UUID type, it maps UUIDs
8
- # to VARCHAR(36) columns and registers the custom UUID type handlers.
7
+ # type support. It includes the shared UUID adapter extension functionality
8
+ # and provides MySQL-specific connection configuration.
9
9
  #
10
- # @example Automatic type mapping
11
- # # MySQL tables with VARCHAR(36) columns are automatically treated as UUIDs
12
- # create_table :users do |t|
13
- # t.column :id, :uuid # Maps to VARCHAR(36) in MySQL
10
+ # @example UUID primary key and foreign key references
11
+ # # Primary key uses UUID type
12
+ # create_table :users, id: :uuid do |t|
13
+ # t.string :name
14
14
  # end
15
15
  #
16
+ # # Foreign key automatically detects and uses UUID type
17
+ # create_table :posts do |t|
18
+ # t.references :user # Automatically uses :uuid type
19
+ # t.string :title
20
+ # end
21
+ #
22
+ # @see RailsUuidPk::UuidAdapterExtension
16
23
  # @see RailsUuidPk::Type::Uuid
17
24
  # @see https://dev.mysql.com/doc/refman/8.0/en/data-types.html
18
25
  module Mysql2AdapterExtension
19
- # Defines native database types for MySQL UUID support.
20
- #
21
- # @return [Hash] Database type definitions including UUID mapping
22
- def native_database_types
23
- super.merge(
24
- uuid: { name: "varchar", limit: 36 }
25
- )
26
- end
27
-
28
- # Checks if a type is valid for this adapter.
29
- #
30
- # Overrides ActiveRecord's valid_type? to recognize the custom UUID type.
31
- #
32
- # @param type [Symbol] The type to check
33
- # @return [Boolean] true if the type is valid
34
- def valid_type?(type)
35
- return true if type == :uuid
36
- super
37
- end
38
-
39
- # Registers UUID type handlers in the adapter's type map.
40
- #
41
- # @param m [ActiveRecord::ConnectionAdapters::AbstractAdapter::TypeMap] The type map to register with
42
- # @return [void]
43
- def register_uuid_types(m = type_map)
44
- RailsUuidPk.log(:debug, "Registering UUID types on #{m.class}")
45
- m.register_type(/varchar\(36\)/i) { RailsUuidPk::Type::Uuid.new }
46
- m.register_type("uuid") { RailsUuidPk::Type::Uuid.new }
47
- end
48
-
49
- # Initializes the type map with UUID type registrations.
50
- #
51
- # @param m [ActiveRecord::ConnectionAdapters::AbstractAdapter::TypeMap] The type map to initialize
52
- # @return [void]
53
- def initialize_type_map(m = type_map)
54
- super
55
- register_uuid_types(m)
56
- end
26
+ include UuidAdapterExtension
57
27
 
58
28
  # Configures the database connection with UUID type support.
59
29
  #
60
30
  # @return [void]
61
31
  def configure_connection
62
32
  super
63
- register_uuid_types
64
- end
65
-
66
- # Overrides type dumping to properly handle UUID columns.
67
- #
68
- # @param column [ActiveRecord::ConnectionAdapters::Column] The column to dump
69
- # @return [Array] The type and options for the schema dump
70
- def type_to_dump(column)
71
- if column.type == :uuid
72
- return [ :uuid, {} ]
73
- end
74
- super
75
33
  end
76
34
  end
77
35
  end
@@ -33,13 +33,14 @@ module RailsUuidPk
33
33
  end
34
34
  end
35
35
 
36
- # Configures type mappings for SQLite and MySQL adapters.
36
+ # Configures type mappings for SQLite, MySQL, and Trilogy adapters.
37
37
  #
38
38
  # Registers the custom UUID type for adapters that don't have native UUID support.
39
+ # Supports both mysql2 and trilogy adapters for MySQL.
39
40
  initializer "rails-uuid-pk.configure_type_map", after: "active_record.initialize_database" do
40
41
  ActiveSupport.on_load(:active_record) do
41
42
  adapter_name = ActiveRecord::Base.connection.adapter_name
42
- if %w[SQLite MySQL].include?(adapter_name)
43
+ if %w[SQLite MySQL Trilogy].include?(adapter_name)
43
44
  RailsUuidPk::Railtie.register_uuid_type(adapter_name.downcase.to_sym)
44
45
  end
45
46
  end
@@ -57,6 +58,10 @@ module RailsUuidPk
57
58
  ActiveSupport.on_load(:active_record_mysql2adapter) do
58
59
  prepend RailsUuidPk::Mysql2AdapterExtension
59
60
  end
61
+
62
+ ActiveSupport.on_load(:active_record_trilogyadapter) do
63
+ prepend RailsUuidPk::TrilogyAdapterExtension
64
+ end
60
65
  end
61
66
 
62
67
  # Ensures UUID types are registered on all database connections.