Skip to content

Commit 487d4e4

Browse files
feat: add Rails generator for RubyLLM models
The generator creates Chat, Message, and ToolCall models with migrations for seamless Rails integration. Users can run 'rails generate ruby_llm:install' to automatically set up all required models and database tables. - Add install_generator with templates for models and migrations - Update Rails integration guide with generator instructions - Update README with two integration options - Update Railtie to register the generator - Add CLAUDE.md for agent assistance 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 5623bee commit 487d4e4

File tree

12 files changed

+202
-4
lines changed

12 files changed

+202
-4
lines changed

CLAUDE.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# RubyLLM Development Guidelines
2+
3+
## Commands
4+
- Run all tests: `bundle exec rspec`
5+
- Run single test: `bundle exec rspec spec/path/to/file_spec.rb`
6+
- Run specific test: `bundle exec rspec spec/path/to/file_spec.rb:LINE_NUMBER`
7+
- Code style check: `bundle exec rubocop`
8+
- Auto-fix style issues: `bundle exec rubocop -A`
9+
- Record VCR cassettes: `bundle exec rake vcr:record[provider]` (where provider is openai, anthropic, gemini, etc.)
10+
11+
## Style Guidelines
12+
- Follow Standard Ruby style (https://github.com/testdouble/standard)
13+
- Use frozen_string_literal comment at top of files
14+
- Add YARD documentation comments for public methods
15+
- Use proper error handling with specific error classes
16+
- Follow consistent model naming conventions across providers
17+
- Keep normalized model IDs (separate model from provider)
18+
- Use consistent parameter naming across providers
19+
20+
## Testing Practices
21+
- Tests automatically create VCR cassettes based on their descriptions
22+
- Use specific, descriptive test descriptions
23+
- Check VCR cassettes for sensitive information
24+
- Write tests for all new features and bug fixes

README.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,37 @@ chat.with_model('gemini-2.0-flash').ask "What's your favorite algorithm?"
137137

138138
## Rails integration that makes sense
139139

140+
### Option 1: Create new models with the generator
141+
142+
Simply run the generator to set up all required models:
143+
144+
```bash
145+
rails generate ruby_llm:install
146+
```
147+
148+
This creates all necessary migrations, models, and database tables. Then just use them:
149+
150+
```ruby
151+
# In your controller
152+
chat = Chat.create!(model_id: "gpt-4o-mini")
153+
chat.ask("What's your favorite Ruby gem?") do |chunk|
154+
Turbo::StreamsChannel.broadcast_append_to(
155+
chat, target: "response", partial: "messages/chunk", locals: { chunk: chunk }
156+
)
157+
end
158+
159+
# That's it - chat history is automatically saved
160+
```
161+
162+
### Option 2: Add to your existing models
163+
164+
Or, add RubyLLM to your existing ActiveRecord models:
165+
140166
```ruby
141167
# app/models/chat.rb
142168
class Chat < ApplicationRecord
143169
acts_as_chat
144-
170+
145171
# Works great with Turbo
146172
broadcasts_to ->(chat) { "chat_#{chat.id}" }
147173
end

docs/guides/rails.md

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,32 @@ RubyLLM provides seamless integration with Rails through ActiveRecord models. Th
1212

1313
## Setup
1414

15-
### 1. Create Migrations
15+
### Using the Generator (Recommended)
1616

17-
First, create the necessary tables in your database:
17+
The easiest way to set up RubyLLM with Rails is to use the built-in generator:
18+
19+
```bash
20+
rails generate ruby_llm:install
21+
```
22+
23+
This will automatically:
24+
1. Create the necessary migrations for chats, messages, and tool calls
25+
2. Create model files with appropriate `acts_as_*` methods
26+
3. Set up proper relationships between models
27+
28+
After running the generator, simply run the migrations:
29+
30+
```bash
31+
rails db:migrate
32+
```
33+
34+
### Manual Setup
35+
36+
If you prefer to set up manually or need to customize the implementation, follow these steps:
37+
38+
#### 1. Create Migrations
39+
40+
Create the necessary tables in your database:
1841

1942
```ruby
2043
# db/migrate/YYYYMMDDHHMMSS_create_chats.rb
@@ -65,7 +88,7 @@ Run the migrations:
6588
rails db:migrate
6689
```
6790

68-
### 2. Set Up Models
91+
#### 2. Set Up Models
6992

7093
Create the model classes:
7194

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# frozen_string_literal: true
2+
3+
class Chat < ApplicationRecord
4+
acts_as_chat
5+
end
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# frozen_string_literal: true
2+
3+
class CreateChats < ActiveRecord::Migration<%= migration_version %>
4+
def change
5+
create_table :chats do |t|
6+
t.string :model_id
7+
t.timestamps
8+
end
9+
end
10+
end
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# frozen_string_literal: true
2+
3+
class CreateMessages < ActiveRecord::Migration<%= migration_version %>
4+
def change
5+
create_table :messages do |t|
6+
t.references :chat, null: false, foreign_key: true
7+
t.string :role
8+
t.text :content
9+
t.string :model_id
10+
t.integer :input_tokens
11+
t.integer :output_tokens
12+
t.references :tool_call
13+
t.timestamps
14+
end
15+
end
16+
end
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# frozen_string_literal: true
2+
3+
class CreateToolCalls < ActiveRecord::Migration<%= migration_version %>
4+
def change
5+
create_table :tool_calls do |t|
6+
t.references :message, null: false, foreign_key: true
7+
t.string :tool_call_id, null: false
8+
t.string :name, null: false
9+
t.jsonb :arguments, default: {}
10+
t.timestamps
11+
end
12+
13+
add_index :tool_calls, :tool_call_id
14+
end
15+
end
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# frozen_string_literal: true
2+
3+
# RubyLLM configuration
4+
RubyLLM.configure do |config|
5+
# Set your API keys here or use environment variables
6+
# config.openai_api_key = ENV["OPENAI_API_KEY"]
7+
# config.anthropic_api_key = ENV["ANTHROPIC_API_KEY"]
8+
# config.gemini_api_key = ENV["GEMINI_API_KEY"]
9+
# config.deepseek_api_key = ENV["DEEPSEEK_API_KEY"]
10+
11+
# Uncomment to set a default model
12+
# config.default_model = "gpt-4o-mini"
13+
14+
# Uncomment to set default options
15+
# config.default_options = { temperature: 0.7 }
16+
end
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# frozen_string_literal: true
2+
3+
class Message < ApplicationRecord
4+
acts_as_message
5+
end
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# frozen_string_literal: true
2+
3+
class ToolCall < ApplicationRecord
4+
acts_as_tool_call
5+
end

0 commit comments

Comments
 (0)