@@ -46,6 +46,7 @@ for a description of different tree storage algorithms.
4646- [ Polymorphic hierarchies with STI] ( #polymorphic-hierarchies-with-sti )
4747- [ Deterministic ordering] ( #deterministic-ordering )
4848- [ Concurrency] ( #concurrency )
49+ - [ Multi-Database Support] ( #multi-database-support )
4950- [ FAQ] ( #faq )
5051- [ Testing] ( #testing )
5152- [ Change log] ( #change-log )
@@ -61,11 +62,11 @@ Note that closure_tree only supports ActiveRecord 7.2 and later, and has test co
61623 . Add ` has_closure_tree ` (or ` acts_as_tree ` , which is an alias of the same method) to your hierarchical model:
6263
6364 ``` ruby
64- class Tag < ActiveRecord :: Base
65+ class Tag < ApplicationRecord
6566 has_closure_tree
6667 end
6768
68- class AnotherTag < ActiveRecord :: Base
69+ class AnotherTag < ApplicationRecord
6970 acts_as_tree
7071 end
7172 ```
@@ -82,7 +83,7 @@ Note that closure_tree only supports ActiveRecord 7.2 and later, and has test co
8283 You may want to also [add a column for deterministic ordering of children](#deterministic-ordering), but that' s optional.
8384
8485 ` ` ` ruby
85- class AddParentIdToTag < ActiveRecord::Migration
86+ class AddParentIdToTag < ActiveRecord::Migration[7.2]
8687 def change
8788 add_column :tags, :parent_id, :integer
8889 end
@@ -384,7 +385,7 @@ Polymorphic models using single table inheritance (STI) are supported:
3843852. Subclass the model class. You only need to add ```has_closure_tree``` to your base class:
385386
386387```ruby
387- class Tag < ActiveRecord::Base
388+ class Tag < ApplicationRecord
388389 has_closure_tree
389390end
390391class WhenTag < Tag ; end
@@ -411,7 +412,7 @@ By default, children will be ordered by your database engine, which may not be w
411412If you want to order children alphabetically, and your model has a ```name``` column, you' d do this:
412413
413414` ` ` ruby
414- class Tag < ActiveRecord::Base
415+ class Tag < ApplicationRecord
415416 has_closure_tree order: 'name'
416417end
417418` ` `
@@ -425,7 +426,7 @@ t.integer :sort_order
425426and in your model:
426427
427428` ` ` ruby
428- class OrderedTag < ActiveRecord::Base
429+ class OrderedTag < ApplicationRecord
429430 has_closure_tree order: 'sort_order', numeric_order: true
430431end
431432` ` `
@@ -525,14 +526,106 @@ If you are already managing concurrency elsewhere in your application, and want
525526of with_advisory_lock, pass ` ` ` with_advisory_lock: false` ` ` in the options hash:
526527
527528` ` ` ruby
528- class Tag
529+ class Tag < ApplicationRecord
529530 has_closure_tree with_advisory_lock: false
530531end
531532` ` `
532533
533534Note that you * will eventually have data corruption* if you disable advisory locks, write to your
534535database with multiple threads, and don' t provide an alternative mutex.
535536
537+ ### Customizing Advisory Lock Names
538+
539+ By default, closure_tree generates advisory lock names based on the model class name. You can customize
540+ this behavior in several ways:
541+
542+ ```ruby
543+ # Static string
544+ class Tag < ApplicationRecord
545+ has_closure_tree advisory_lock_name: ' custom_tag_lock'
546+ end
547+
548+ # Dynamic via Proc
549+ class Tag < ApplicationRecord
550+ has_closure_tree advisory_lock_name: ->(model_class) { "#{Rails.env}_#{model_class.name.underscore}" }
551+ end
552+
553+ # Delegate to model method
554+ class Tag < ApplicationRecord
555+ has_closure_tree advisory_lock_name: :custom_lock_name
556+
557+ def self.custom_lock_name
558+ "tag_lock_#{current_tenant_id}"
559+ end
560+ end
561+ ```
562+
563+ This is particularly useful when:
564+ * You need environment-specific lock names
565+ * You' re using multi- tenancy and need tenant- specific locks
566+ * You want to avoid lock name collisions between similar model names
567+
568+ # # Multi-Database Support
569+
570+ Closure Tree fully supports running with multiple databases simultaneously, including mixing different database engines (PostgreSQL , MySQL , SQLite ) in the same application. This is particularly useful for:
571+
572+ * Applications with read replicas
573+ * Sharding strategies
574+ * Testing with different database engines
575+ * Gradual database migrations
576+
577+ # ## Database-Specific Behaviors
578+
579+ # ### PostgreSQL
580+ * Full support for advisory locks via ` with_advisory_lock`
581+ * Excellent concurrency support with row- level locking
582+ * Best overall performance for tree operations
583+
584+ # ### MySQL
585+ * Advisory locks supported via ` with_advisory_lock`
586+ * Note: MySQL ' s row-level locking may incorrectly report deadlocks in some cases
587+ * Requires MySQL 5.7.12+ to avoid hierarchy maintenance errors
588+
589+ #### SQLite
590+ * **No advisory lock support** - always returns false from `with_advisory_lock`
591+ * Falls back to file-based locking for tests
592+ * Suitable for development and testing, but not recommended for production with concurrent writes
593+
594+ ### Configuration
595+
596+ When using multiple databases, closure_tree automatically detects the correct adapter for each connection:
597+
598+ ```ruby
599+ class Tag < ApplicationRecord
600+ connects_to database: { writing: :primary, reading: :replica }
601+ has_closure_tree
602+ end
603+
604+ class Category < ApplicationRecord
605+ connects_to database: { writing: :sqlite_db }
606+ has_closure_tree
607+ end
608+ ```
609+
610+ Each model will use the appropriate database-specific SQL syntax and features based on its connection adapter.
611+
612+ ### Testing with Multiple Databases
613+
614+ You can run the test suite against different databases:
615+
616+ ```bash
617+ # Run with PostgreSQL
618+ DATABASE_URL=postgres://localhost/closure_tree_test rake test
619+
620+ # Run with MySQL
621+ DATABASE_URL=mysql2://localhost/closure_tree_test rake test
622+
623+ # Run with SQLite (default)
624+ rake test
625+ ```
626+
627+ For simultaneous multi-database testing, the test suite automatically sets up connections to all three database types when available.
628+
536629## I18n
537630
538631You can customize error messages using [I18n](http://guides.rubyonrails.org/i18n.html):
0 commit comments