Skip to content

Commit ecc8afa

Browse files
authored
Fix namespaced models in Model migration and foreign key migrations (#399)
Fixes crmne/ruby_llm#397 (comment) and continues work from #398
1 parent c811173 commit ecc8afa

File tree

7 files changed

+47
-37
lines changed

7 files changed

+47
-37
lines changed

lib/generators/ruby_llm/install/install_generator.rb

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ def parse_model_mappings
5757
@model_names ||= parse_model_mappings
5858
@model_names[type]
5959
end
60+
61+
define_method("#{type}_table_name") do
62+
table_name_for(send("#{type}_model_name"))
63+
end
6064
end
6165

6266
def acts_as_chat_declaration
@@ -145,22 +149,22 @@ def create_migration_files
145149
# Create migrations with timestamps to ensure proper order
146150
# First create chats table
147151
migration_template 'create_chats_migration.rb.tt',
148-
"db/migrate/create_#{chat_model_name.tableize}.rb"
152+
"db/migrate/create_#{chat_table_name}.rb"
149153

150154
# Then create messages table (must come before tool_calls due to foreign key)
151155
sleep 1 # Ensure different timestamp
152156
migration_template 'create_messages_migration.rb.tt',
153-
"db/migrate/create_#{message_model_name.tableize}.rb"
157+
"db/migrate/create_#{message_table_name}.rb"
154158

155159
# Then create tool_calls table (references messages)
156160
sleep 1 # Ensure different timestamp
157161
migration_template 'create_tool_calls_migration.rb.tt',
158-
"db/migrate/create_#{tool_call_model_name.tableize}.rb"
162+
"db/migrate/create_#{tool_call_table_name}.rb"
159163

160164
# Create models table
161165
sleep 1 # Ensure different timestamp
162166
migration_template 'create_models_migration.rb.tt',
163-
"db/migrate/create_#{model_model_name.tableize}.rb"
167+
"db/migrate/create_#{model_table_name}.rb"
164168
end
165169

166170
def create_model_files
@@ -182,6 +186,12 @@ def install_active_storage
182186
rails_command 'active_storage:install'
183187
end
184188

189+
def table_name_for(model_name)
190+
# Convert namespaced model names to proper table names
191+
# e.g., "Assistant::Chat" -> "assistant_chats" (not "assistant/chats")
192+
model_name.underscore.pluralize.tr('/', '_')
193+
end
194+
185195
def show_install_info
186196
say "\n ✅ RubyLLM installed!", :green
187197

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
class Create<%= chat_model_name.pluralize %> < ActiveRecord::Migration<%= migration_version %>
1+
class Create<%= chat_model_name.gsub('::', '').pluralize %> < ActiveRecord::Migration<%= migration_version %>
22
def change
3-
create_table :<%= chat_model_name.tableize %> do |t|
4-
t.references :<%= model_model_name.tableize.singularize %>, foreign_key: true
3+
create_table :<%= chat_table_name %> do |t|
4+
t.references :<%= model_table_name.singularize %>, foreign_key: true
55
t.timestamps
66
end
77
end
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
class Create<%= message_model_name.pluralize %> < ActiveRecord::Migration<%= migration_version %>
1+
class Create<%= message_model_name.gsub('::', '').pluralize %> < ActiveRecord::Migration<%= migration_version %>
22
def change
3-
create_table :<%= message_model_name.tableize %> do |t|
4-
t.references :<%= chat_model_name.tableize.singularize %>, null: false, foreign_key: true
3+
create_table :<%= message_table_name %> do |t|
4+
t.references :<%= chat_table_name.singularize %>, null: false, foreign_key: true
55
t.string :role, null: false
66
t.text :content
7-
t.references :<%= model_model_name.tableize.singularize %>, foreign_key: true
7+
t.references :<%= model_table_name.singularize %>, foreign_key: true
88
t.integer :input_tokens
99
t.integer :output_tokens
10-
t.references :<%= tool_call_model_name.tableize.singularize %>, foreign_key: true
10+
t.references :<%= tool_call_table_name.singularize %>, foreign_key: true
1111
t.timestamps
1212
end
1313

14-
add_index :<%= message_model_name.tableize %>, :role
14+
add_index :<%= message_table_name %>, :role
1515
end
1616
end

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
class Create<%= model_model_name.pluralize %> < ActiveRecord::Migration<%= migration_version %>
1+
class Create<%= model_model_name.gsub('::', '').pluralize %> < ActiveRecord::Migration<%= migration_version %>
22
def change
3-
create_table :<%= model_model_name.tableize %> do |t|
3+
create_table :<%= model_table_name %> do |t|
44
t.string :model_id, null: false
55
t.string :name, null: false
66
t.string :provider, null: false
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
<%#- # Migration for creating tool_calls table with database-specific JSON handling -%>
2-
class Create<%= tool_call_model_name.pluralize %> < ActiveRecord::Migration<%= migration_version %>
2+
class Create<%= tool_call_model_name.gsub('::', '').pluralize %> < ActiveRecord::Migration<%= migration_version %>
33
def change
4-
create_table :<%= tool_call_model_name.tableize %> do |t|
5-
t.references :<%= message_model_name.tableize.singularize %>, null: false, foreign_key: true
4+
create_table :<%= tool_call_table_name %> do |t|
5+
t.references :<%= message_table_name.singularize %>, null: false, foreign_key: true
66
t.string :tool_call_id, null: false
77
t.string :name, null: false
88
t.<%= postgresql? ? 'jsonb' : 'json' %> :arguments, default: {}
99
t.timestamps
1010
end
1111

12-
add_index :<%= tool_call_model_name.tableize %>, :tool_call_id, unique: true
13-
add_index :<%= tool_call_model_name.tableize %>, :name
12+
add_index :<%= tool_call_table_name %>, :tool_call_id, unique: true
13+
add_index :<%= tool_call_table_name %>, :name
1414
end
1515
end

lib/generators/ruby_llm/upgrade_to_v1_7/templates/migration.rb.tt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,18 @@ class MigrateToRubyLLMModelReferences < ActiveRecord::Migration<%= migration_ver
1212
end
1313

1414
# Migrate foreign keys
15-
migrate_foreign_key(:<%= chat_table_name %>, chat_class, model_class, :<%= model_model_name.underscore %>)
16-
migrate_foreign_key(:<%= message_table_name %>, message_class, model_class, :<%= model_model_name.underscore %>)
15+
migrate_foreign_key(:<%= chat_table_name %>, chat_class, model_class, :<%= model_table_name.singularize %>)
16+
migrate_foreign_key(:<%= message_table_name %>, message_class, model_class, :<%= model_table_name.singularize %>)
1717
end
1818

1919
def down
2020
# Remove foreign key references
21-
if column_exists?(:<%= message_table_name %>, :<%= model_model_name.underscore %>_id)
22-
remove_reference :<%= message_table_name %>, :<%= model_model_name.underscore %>, foreign_key: true
21+
if column_exists?(:<%= message_table_name %>, :<%= model_table_name.singularize %>_id)
22+
remove_reference :<%= message_table_name %>, :<%= model_table_name.singularize %>, foreign_key: true
2323
end
2424

25-
if column_exists?(:<%= chat_table_name %>, :<%= model_model_name.underscore %>_id)
26-
remove_reference :<%= chat_table_name %>, :<%= model_model_name.underscore %>, foreign_key: true
25+
if column_exists?(:<%= chat_table_name %>, :<%= model_table_name.singularize %>_id)
26+
remove_reference :<%= chat_table_name %>, :<%= model_table_name.singularize %>, foreign_key: true
2727
end
2828

2929
# Restore original model_id string columns

spec/lib/generators/ruby_llm/install_generator_spec.rb

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,23 +29,23 @@
2929
let(:chat_migration) { File.read(File.join(template_dir, 'create_chats_migration.rb.tt')) }
3030

3131
it 'defines chats table' do
32-
expect(chat_migration).to include('create_table :<%= chat_model_name.tableize %>')
32+
expect(chat_migration).to include('create_table :<%= chat_table_name %>')
3333
end
3434

3535
it 'includes model reference' do
36-
expect(chat_migration).to include('t.references :<%= model_model_name.tableize.singularize %>')
36+
expect(chat_migration).to include('t.references :<%= model_table_name.singularize %>')
3737
end
3838
end
3939

4040
describe 'messages migration' do
4141
let(:message_migration) { File.read(File.join(template_dir, 'create_messages_migration.rb.tt')) }
4242

4343
it 'defines messages table' do
44-
expect(message_migration).to include('create_table :<%= message_model_name.tableize %>')
44+
expect(message_migration).to include('create_table :<%= message_table_name %>')
4545
end
4646

4747
it 'includes chat reference' do
48-
expect(message_migration).to include('t.references :<%= chat_model_name.tableize.singularize %>, null: false, foreign_key: true') # rubocop:disable Layout/LineLength
48+
expect(message_migration).to include('t.references :<%= chat_table_name.singularize %>, null: false, foreign_key: true') # rubocop:disable Layout/LineLength
4949
end
5050

5151
it 'includes role field' do
@@ -61,7 +61,7 @@
6161
let(:tool_call_migration) { File.read(File.join(template_dir, 'create_tool_calls_migration.rb.tt')) }
6262

6363
it 'defines tool_calls table' do
64-
expect(tool_call_migration).to include('create_table :<%= tool_call_model_name.tableize %>')
64+
expect(tool_call_migration).to include('create_table :<%= tool_call_table_name %>')
6565
end
6666

6767
it 'includes tool_call_id field' do
@@ -125,7 +125,7 @@
125125
let(:models_migration) { File.read(File.join(template_dir, 'create_models_migration.rb.tt')) }
126126

127127
it 'defines models table' do
128-
expect(models_migration).to include('create_table :<%= model_model_name.tableize %>')
128+
expect(models_migration).to include('create_table :<%= model_table_name %>')
129129
end
130130

131131
it 'includes model_id field' do
@@ -240,11 +240,11 @@
240240
it 'creates migrations in correct order' do
241241
migration_section = generator_content[/def create_migration_files.*?\n end/m]
242242

243-
# Look for the model name references which are in the migration paths
244-
chats_position = migration_section.index('chat_model_name')
245-
messages_position = migration_section.index('message_model_name')
246-
tool_calls_position = migration_section.index('tool_call_model_name')
247-
models_position = migration_section.index('model_model_name')
243+
# Look for the table name references which are in the migration paths
244+
chats_position = migration_section.index('chat_table_name')
245+
messages_position = migration_section.index('message_table_name')
246+
tool_calls_position = migration_section.index('tool_call_table_name')
247+
models_position = migration_section.index('model_table_name')
248248

249249
expect(chats_position).not_to be_nil
250250
expect(messages_position).not_to be_nil

0 commit comments

Comments
 (0)