Skip to content

Commit 8316ce5

Browse files
Merge pull request #1 from jamster/generators
Making class and table names optional
2 parents 9d8c2d6 + a239b34 commit 8316ce5

File tree

12 files changed

+116
-113
lines changed

12 files changed

+116
-113
lines changed

lib/generators/ruby_llm/install/templates/README.md renamed to lib/generators/ruby_llm/install/templates/README.md.tt

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,22 @@ Thanks for installing RubyLLM in your Rails application. Here's what was created
44

55
## Models
66

7-
- `Chat` - Stores chat sessions and their associated model ID
8-
- `Message` - Stores individual messages in a chat
9-
- `ToolCall` - Stores tool calls made by language models
7+
- `<%= options[:chat_model_name] %>` - Stores chat sessions and their associated model ID
8+
- `<%= options[:message_model_name] %>` - Stores individual messages in a chat
9+
- `<%= options[:tool_call_model_name] %>` - Stores tool calls made by language models
10+
11+
## Configuration Options
12+
13+
The generator supports the following options to customize model names:
14+
15+
```bash
16+
rails generate ruby_llm:install \
17+
--chat-model-name=Conversation \
18+
--message-model-name=ChatMessage \
19+
--tool-call-model-name=FunctionCall
20+
```
21+
22+
This is useful when you need to avoid namespace collisions with existing models in your application. Table names will be automatically derived from the model names following Rails conventions.
1023

1124
## Next Steps
1225

@@ -28,7 +41,7 @@ Thanks for installing RubyLLM in your Rails application. Here's what was created
2841
3. **Start using RubyLLM in your code:**
2942
```ruby
3043
# Create a new chat
31-
chat = Chat.create!(model_id: "gpt-4o-mini")
44+
chat = <%= options[:chat_model_name] %>.create!(model_id: "gpt-4o-mini")
3245

3346
# Ask a question
3447
response = chat.ask("What's the best Ruby web framework?")
Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
# frozen_string_literal: true
2-
3-
class Chat < ApplicationRecord
4-
acts_as_chat
1+
class <%= options[:chat_model_name] %> < ApplicationRecord
2+
<%= acts_as_chat_declaration %>
53
end

lib/generators/ruby_llm/install/templates/create_chats_migration.rb.tt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
# frozen_string_literal: true
2-
3-
class CreateChats < ActiveRecord::Migration<%= migration_version %>
1+
class Create<%= options[:chat_model_name].pluralize %> < ActiveRecord::Migration<%= migration_version %>
42
def change
5-
create_table :chats do |t|
3+
create_table :<%= options[:chat_model_name].tableize %> do |t|
64
t.string :model_id
75
t.timestamps
86
end

lib/generators/ruby_llm/install/templates/create_messages_migration.rb.tt

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
1-
# frozen_string_literal: true
2-
3-
# This migration must be run AFTER create_chats and create_tool_calls migrations
1+
# This migration must be run AFTER create_<%= options[:chat_model_name].tableize %> and create_<%= options[:tool_call_model_name].tableize %> migrations
42
# to ensure proper foreign key references
5-
class CreateMessages < ActiveRecord::Migration<%= migration_version %>
3+
class Create<%= options[:message_model_name].pluralize %> < ActiveRecord::Migration<%= migration_version %>
64
def change
7-
create_table :messages do |t|
8-
t.references :chat, null: false, foreign_key: true
5+
create_table :<%= options[:message_model_name].tableize %> do |t|
6+
t.references :<%= options[:chat_model_name].tableize.singularize %>, null: false, foreign_key: true
97
t.string :role
108
t.text :content
119
t.string :model_id
1210
t.integer :input_tokens
1311
t.integer :output_tokens
14-
t.references :tool_call, foreign_key: true
12+
t.references :<%= options[:tool_call_model_name].tableize.singularize %>
1513
t.timestamps
1614
end
1715
end
Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,14 @@
1-
# frozen_string_literal: true
2-
3-
# Migration for creating tool_calls table with database-specific JSON handling
4-
class CreateToolCalls < ActiveRecord::Migration<%= migration_version %>
1+
<%#- # Migration for creating tool_calls table with database-specific JSON handling -%>
2+
class Create<%= options[:tool_call_model_name].pluralize %> < ActiveRecord::Migration<%= migration_version %>
53
def change
6-
create_table :tool_calls do |t|
4+
create_table :<%= options[:tool_call_model_name].tableize %> do |t|
5+
t.references :<%= options[:message_model_name].tableize.singularize %>, null: false, foreign_key: true
76
t.string :tool_call_id, null: false
87
t.string :name, null: false
9-
10-
# Use the appropriate JSON column type for the database
11-
if postgresql?
12-
t.jsonb :arguments, default: {}
13-
else
14-
t.json :arguments, default: {}
15-
end
16-
8+
t.<%= postgresql? ? 'jsonb' : 'json' %> :arguments, default: {}
179
t.timestamps
1810
end
1911

20-
add_index :tool_calls, :tool_call_id
12+
add_index :<%= options[:tool_call_model_name].tableize %>, :tool_call_id
2113
end
2214
end

lib/generators/ruby_llm/install/templates/initializer.rb.tt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
# frozen_string_literal: true
2-
31
# RubyLLM configuration
42
RubyLLM.configure do |config|
53
# Set your API keys here or use environment variables
Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
# frozen_string_literal: true
2-
3-
class Message < ApplicationRecord
4-
acts_as_message
1+
class <%= options[:message_model_name] %> < ApplicationRecord
2+
<%= acts_as_message_declaration %>
53
end
Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
# frozen_string_literal: true
2-
3-
class ToolCall < ApplicationRecord
4-
acts_as_tool_call
1+
class <%= options[:tool_call_model_name] %> < ApplicationRecord
2+
<%= acts_as_tool_call_declaration %>
53
end

lib/generators/ruby_llm/install_generator.rb

Lines changed: 62 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,21 @@ module RubyLLM
77
# Generator for RubyLLM Rails models and migrations
88
class InstallGenerator < Rails::Generators::Base
99
include Rails::Generators::Migration
10+
namespace "ruby_llm:install"
1011

1112
source_root File.expand_path('install/templates', __dir__)
1213

14+
class_option :chat_model_name, type: :string, default: 'Chat',
15+
desc: 'Name of the Chat model class'
16+
class_option :message_model_name, type: :string, default: 'Message',
17+
desc: 'Name of the Message model class'
18+
class_option :tool_call_model_name, type: :string, default: 'ToolCall',
19+
desc: 'Name of the ToolCall model class'
20+
1321
desc 'Creates model files for Chat, Message, and ToolCall, and creates migrations for RubyLLM Rails integration'
1422

1523
def self.next_migration_number(dirname)
16-
ActiveRecord::Generators::Base.next_migration_number(dirname)
24+
::ActiveRecord::Generators::Base.next_migration_number(dirname)
1725
end
1826

1927
def migration_version
@@ -26,38 +34,75 @@ def postgresql?
2634
false
2735
end
2836

29-
def create_migration_files
30-
# Create migrations in the correct order with sequential timestamps
31-
# to ensure proper foreign key references:
32-
# 1. First create chats (no dependencies)
33-
# 2. Then create tool_calls (will be referenced by messages)
34-
# 3. Finally create messages (depends on both chats and tool_calls)
37+
def acts_as_chat_declaration
38+
acts_as_chat_params = []
39+
if options[:message_model_name]
40+
acts_as_chat_params << "message_class: \"#{options[:message_model_name]}\""
41+
end
42+
if options[:tool_call_model_name]
43+
acts_as_chat_params << "tool_call_class: \"#{options[:tool_call_model_name]}\""
44+
end
45+
if acts_as_chat_params.any?
46+
"acts_as_chat #{acts_as_chat_params.join(', ')}"
47+
else
48+
"acts_as_chat"
49+
end
50+
end
51+
52+
def acts_as_message_declaration
53+
acts_as_message_params = []
54+
if options[:chat_model_name]
55+
acts_as_message_params << "chat_class: \"#{options[:chat_model_name]}\""
56+
end
57+
if options[:tool_call_model_name]
58+
acts_as_message_params << "tool_call_class: \"#{options[:tool_call_model_name]}\""
59+
end
60+
if acts_as_message_params.any?
61+
"acts_as_message #{acts_as_message_params.join(', ')}"
62+
else
63+
"acts_as_message"
64+
end
65+
end
66+
67+
def acts_as_tool_call_declaration
68+
acts_as_tool_call_params = []
69+
if options[:message_model_name]
70+
acts_as_tool_call_params << "message_class: \"#{options[:message_model_name]}\""
71+
end
72+
if acts_as_tool_call_params.any?
73+
"acts_as_tool_call #{acts_as_tool_call_params.join(', ')}"
74+
else
75+
"acts_as_tool_call"
76+
end
77+
end
3578

79+
def create_migration_files
3680
# Use a fixed timestamp for testing and to ensure they're sequential
37-
@migration_number = Time.now.utc.strftime('%Y%m%d%H%M%S')
38-
migration_template 'create_chats_migration.rb.tt', 'db/migrate/create_chats.rb'
81+
# @migration_number = Time.now.utc.strftime('%Y%m%d%H%M%S')
82+
migration_template 'create_chats_migration.rb.tt', "db/migrate/create_#{options[:chat_model_name].tableize}.rb"
3983

4084
# Increment timestamp for the next migration
41-
@migration_number = (@migration_number.to_i + 1).to_s
42-
migration_template 'create_tool_calls_migration.rb.tt', 'db/migrate/create_tool_calls.rb'
85+
# @migration_number = (@migration_number.to_i + 1).to_s
86+
migration_template 'create_messages_migration.rb.tt', "db/migrate/create_#{options[:message_model_name].tableize}.rb"
4387

4488
# Increment timestamp again for the final migration
45-
@migration_number = (@migration_number.to_i + 2).to_s
46-
migration_template 'create_messages_migration.rb.tt', 'db/migrate/create_messages.rb'
89+
# @migration_number = (@migration_number.to_i + 2).to_s
90+
migration_template 'create_tool_calls_migration.rb.tt', "db/migrate/create_#{options[:tool_call_model_name].tableize}.rb"
4791
end
4892

4993
def create_model_files
50-
template 'chat_model.rb.tt', 'app/models/chat.rb'
51-
template 'message_model.rb.tt', 'app/models/message.rb'
52-
template 'tool_call_model.rb.tt', 'app/models/tool_call.rb'
94+
template 'chat_model.rb.tt', "app/models/#{options[:chat_model_name].underscore}.rb"
95+
template 'message_model.rb.tt', "app/models/#{options[:message_model_name].underscore}.rb"
96+
template 'tool_call_model.rb.tt', "app/models/#{options[:tool_call_model_name].underscore}.rb"
5397
end
5498

5599
def create_initializer
56100
template 'initializer.rb.tt', 'config/initializers/ruby_llm.rb'
57101
end
58102

59103
def show_readme
60-
readme 'README.md'
104+
content = ERB.new(File.read(source_paths.first + '/README.md.tt')).result(binding)
105+
say content
61106
end
62107
end
63108
end

lib/ruby_llm/active_record/acts_as.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def acts_as_message(chat_class: 'Chat', tool_call_class: 'ToolCall') # rubocop:d
3737
@chat_class = chat_class.to_s
3838
@tool_call_class = tool_call_class.to_s
3939

40-
belongs_to :chat, class_name: @chat_class
40+
belongs_to :chat, class_name: @chat_class, foreign_key: "#{@chat_class.underscore}_id"
4141
has_many :tool_calls, class_name: @tool_call_class, dependent: :destroy
4242

4343
belongs_to :parent_tool_call,
@@ -52,7 +52,7 @@ def acts_as_message(chat_class: 'Chat', tool_call_class: 'ToolCall') # rubocop:d
5252
def acts_as_tool_call(message_class: 'Message')
5353
@message_class = message_class.to_s
5454

55-
belongs_to :message, class_name: @message_class
55+
belongs_to :message, class_name: @message_class, foreign_key: "#{@message_class.underscore}_id"
5656

5757
has_one :result,
5858
class_name: @message_class,
@@ -170,4 +170,4 @@ def extract_content
170170
end
171171
end
172172
end
173-
end
173+
end

0 commit comments

Comments
 (0)