[FEATURE] Let the tables RubyLLM owns live in another database
Nobody has claimed this yet.
- Dominant language
- Ruby
- Stars
- 4.4k
- Forks
- 504
- Avg merge
- 1d 8h
- Merged PRs (30d)
- 11
Description
Scope check
- This is core LLM communication (not application logic)
- This benefits most users (not just my use case)
- This can't be solved in application code with current RubyLLM
- I read the Contributing Guide
Due diligence
- I searched existing issues
- I checked the documentation
What problem does this solve?
RubyLLM's four record classes (Model, ToolCall, Usage, Batch) inherit from ::ActiveRecord::Base, so they always resolve to the application's default connection.
An application whose chats and messages live in a secondary database cannot put RubyLLM's tables next to them. connects_to raises NotImplementedError on a concrete class, and establish_connection has to be repeated on all four and gives each its own pool.
The generated schema already says the two table sets belong together: create_chats_migration.rb.tt declares a foreign key from chats to ruby_llm_models. So the application picks the database for its half, and the gem pins its half to the default one. When those differ, the foreign key the install generator writes cannot be created.
Proposed solution
Add RubyLLM::ActiveRecord::Record as the abstract base class of the four, and change nothing else:
class Record < ::ActiveRecord::Base
self.abstract_class = true
end
The four keep their self.table_name assignments. Nothing changes by default: Record does not call connects_to, so all four stay on ActiveRecord::Base's pool. I measured an identical workload before and after — same 29 queries, same 4 transactions, one connection pool.
It gives an application one place to configure the connection:
# move them to another database
RubyLLM::ActiveRecord::Record.connects_to database: { writing: :llm }
# or join a pool the application already has, which keeps RubyLLM's
# writes inside the application's transactions
RubyLLM::ActiveRecord::Record.connection_specification_name =
SecondaryRecord.connection_specification_name
I verified the second form on Rails 7.1 through 8.1: the four classes land on the application's pool, and a rollback on the application's class takes the row RubyLLM wrote with it.
Why this belongs in RubyLLM
It cannot be solved in application code. Rails allows connects_to only on ActiveRecord::Base or an abstract class, and RubyLLM owns these four classes, so only RubyLLM can give them an abstract ancestor. Everything an application can reach for today is either a :nodoc: internal (connection_specification_name, connection_class) assigned four times over, or establish_connection per class, which fragments the pool.
This is the same problem every Rails framework gem with its own tables has, and they all solve it the same way: ActiveStorage::Record, ActionMailbox::Record, ActionText::Record, SolidQueue::Record, SolidCache::Record. All five are an abstract class and nothing else.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Locate the four record classes—Model, ToolCall, Usage, and Batch—and the create_chats_migration.rb.tt template; start by tracing their current ActiveRecord::Base inheritance and the generated foreign key. Done means one shared configurable connection applies to all four, default behavior remains unchanged, and the Rails 7.1–8.1 connection and rollback cases described in the issue work.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rails, ruby
- Domain
- database
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 72/100