Rails Integration
Rails + AI made simple. Persist chats with ActiveRecord. Stream with Hotwire. Deploy with confidence.
Table of contents
- Understanding the Persistence Flow
- Setting Up Your Rails Application
- Configuring RubyLLM
- Going further
- Next Steps
After reading this guide, you will know:
- How the RubyLLM persistence flow works inside a Rails request.
- Why the flow creates and rolls back assistant messages the way it does.
- What content validation constraints the flow imposes on your
Messagemodel. - How to set up a Rails application with the install generator.
- How to configure RubyLLM in a Rails initializer.
RubyLLM treats Rails as a first-class home. Chats and messages become ActiveRecord models, attachments ride on ActiveStorage, and streaming plugs straight into Hotwire. This page explains the persistence flow that everything else builds on, then gets you to a working install. The deeper topics live in the child guides linked under Going further.
Understanding the Persistence Flow
Before diving into setup, it’s important to understand how RubyLLM handles message persistence in Rails. This design influences model validations and real-time UI updates.
How It Works
When calling chat_record.ask("What is the capital of France?"), RubyLLM:
- Saves the user message with the question content
- Calls the
completemethod, which:- Makes the API call to the AI provider
- Creates an empty assistant message:
- With streaming: On receiving the first chunk
- Without streaming: Before the API call
- Processes the response:
- Success: Updates the assistant message with content and metadata
- Failure: Automatically destroys the empty assistant message
Why This Design?
This approach optimizes for real-time experiences:
- Streaming optimized: Creates DOM target on first chunk for immediate UI updates
- Turbo Streams ready: Works with
after_create_commitfor real-time broadcasting - Clean rollback: Automatic cleanup on failure prevents orphaned records
Content Validation Implications
You cannot use validates :content, presence: true on your Message model. The flow creates an empty assistant message before content arrives. See Customizing the Persistence Flow for an alternative approach.
Setting Up Your Rails Application
The fastest path to an AI-ready Rails app is the install generator. It writes the migrations, models, and initializer for you:
bin/rails generate ruby_llm:install
Then migrate and load the model registry:
bin/rails db:migrate
bin/rails ruby_llm:load_models # v1.13+
Your Rails app is now AI-ready. For everything the generators create, including the chat UI, conventional directory structure, and generator options, see Generators and App Conventions.
Configuring RubyLLM
Set up your API keys and other configuration in the initializer:
# config/initializers/ruby_llm.rb
RubyLLM.configure do |config|
config.openai_api_key = ENV['OPENAI_API_KEY']
config.anthropic_api_key = ENV['ANTHROPIC_API_KEY']
config.gemini_api_key = ENV['GEMINI_API_KEY']
# For custom Model class names (defaults to 'Model')
# config.model_registry_class = 'AIModel'
end
Going further
Each part of Rails integration has its own focused guide:
- Persistence with acts_as - wire up
acts_as_chat,acts_as_message, and friends, then work with chats, tools, attachments, and structured output. - Streaming with Hotwire/Turbo - broadcast tokens in real time with Turbo Streams and background jobs.
- Generators and App Conventions - the install and chat UI generators, view conventions, and the conventional app directory structure.
- Advanced Rails Configuration - provider overrides, custom contexts, raw provider payloads, and fiber-safe connections.
Next Steps
- Chatting with AI Models - the core chat API your persisted models expose.
- Using Tools - let the AI call your Ruby code.
- Streaming Responses - the streaming primitives behind Hotwire integration.
- Working with Models - the model registry and capability lookups.
- Error Handling - handle and recover from API failures.