Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

super_scaffold:join_model hangs? #1457

Closed
swombat opened this issue May 13, 2024 · 8 comments · Fixed by bullet-train-co/bullet_train-core#845
Closed

super_scaffold:join_model hangs? #1457

swombat opened this issue May 13, 2024 · 8 comments · Fixed by bullet-train-co/bullet_train-core#845

Comments

@swombat
Copy link

swombat commented May 13, 2024

➜  promptcraft git:(main) rails generate super_scaffold:join_model InputItem::PromptExecution prompt_execution_id{class_name=PromptExecution} input_item_id{class_name=InputItem}
Generating model with 'bin/rails generate model InputItem::PromptExecution prompt_execution:references input_item:references'

This will just hang there until I kill it. Then:

^C/Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/bullet_train-super_scaffolding-1.7.4/lib/bullet_train/super_scaffolding/scaffolders/join_model_scaffolder.rb:46:in ``': Interrupt
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/bullet_train-super_scaffolding-1.7.4/lib/bullet_train/super_scaffolding/scaffolders/join_model_scaffolder.rb:46:in `run'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/bullet_train-super_scaffolding-1.7.4/lib/scaffolding/script.rb:212:in `<main>'
	from <internal:/Users/danieltenner/.rvm/rubies/ruby-3.3.0/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
	from <internal:/Users/danieltenner/.rvm/rubies/ruby-3.3.0/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/bootsnap-1.18.3/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/zeitwerk-2.6.13/lib/zeitwerk/kernel.rb:34:in `require'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/bullet_train-super_scaffolding-1.7.4/lib/bullet_train/super_scaffolding.rb:29:in `run'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/bullet_train-super_scaffolding-1.7.4/lib/generators/super_scaffold/join_model/join_model_generator.rb:26:in `generate'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/command.rb:28:in `run'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/invocation.rb:127:in `invoke_command'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/invocation.rb:134:in `block in invoke_all'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/invocation.rb:134:in `each'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/invocation.rb:134:in `map'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/invocation.rb:134:in `invoke_all'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/group.rb:232:in `dispatch'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/base.rb:584:in `start'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/railties-7.1.3.2/lib/rails/generators.rb:261:in `invoke'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/railties-7.1.3.2/lib/rails/commands/generate/generate_command.rb:26:in `perform'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/command.rb:28:in `run'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/invocation.rb:127:in `invoke_command'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/railties-7.1.3.2/lib/rails/command/base.rb:178:in `invoke_command'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor.rb:527:in `dispatch'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/railties-7.1.3.2/lib/rails/command/base.rb:73:in `perform'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/railties-7.1.3.2/lib/rails/command.rb:71:in `block in invoke'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/railties-7.1.3.2/lib/rails/command.rb:149:in `with_argv'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/railties-7.1.3.2/lib/rails/command.rb:69:in `invoke'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/railties-7.1.3.2/lib/rails/commands.rb:18:in `<main>'
	from <internal:/Users/danieltenner/.rvm/rubies/ruby-3.3.0/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
	from <internal:/Users/danieltenner/.rvm/rubies/ruby-3.3.0/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/bootsnap-1.18.3/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
	from bin/rails:4:in `<main>'

➜  promptcraft git:(main) ✗ /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/reline-0.5.5/lib/reline/line_editor.rb:196:in `handle_interrupted': Interrupt (Interrupt)
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/reline-0.5.5/lib/reline/line_editor.rb:167:in `handle_signal'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/reline-0.5.5/lib/reline/general_io.rb:49:in `block in getc'
	from <internal:kernel>:187:in `loop'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/reline-0.5.5/lib/reline/general_io.rb:48:in `getc'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/reline-0.5.5/lib/reline.rb:386:in `block in read_io'
	from <internal:kernel>:187:in `loop'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/reline-0.5.5/lib/reline.rb:385:in `read_io'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/reline-0.5.5/lib/reline.rb:353:in `block in inner_readline'
	from <internal:kernel>:187:in `loop'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/reline-0.5.5/lib/reline.rb:352:in `inner_readline'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/reline-0.5.5/lib/reline.rb:291:in `block (2 levels) in readline'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/reline-0.5.5/lib/reline/general_io.rb:40:in `with_raw_input'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/reline-0.5.5/lib/reline.rb:290:in `block in readline'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/reline-0.5.5/lib/reline.rb:288:in `synchronize'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/reline-0.5.5/lib/reline.rb:288:in `readline'
	from /Users/danieltenner/.rvm/rubies/ruby-3.3.0/lib/ruby/3.3.0/forwardable.rb:240:in `readline'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/line_editor/readline.rb:20:in `readline'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/line_editor.rb:7:in `readline'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/shell/basic.rb:336:in `ask_simply'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/shell/basic.rb:87:in `ask'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/shell/basic.rb:212:in `block in file_collision'
	from <internal:kernel>:187:in `loop'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/shell/basic.rb:211:in `file_collision'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/actions/create_file.rb:101:in `force_on_collision?'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/actions/create_file.rb:94:in `force_or_skip_or_conflict'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/actions/create_file.rb:78:in `on_conflict_behavior'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/actions/empty_directory.rb:115:in `invoke_with_conflict_check'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/actions/create_file.rb:61:in `invoke!'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/actions.rb:93:in `action'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/actions/create_file.rb:25:in `create_file'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/actions/file_manipulation.rb:124:in `template'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/railties-7.1.3.2/lib/rails/generators/named_base.rb:25:in `block in template'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/railties-7.1.3.2/lib/rails/generators/named_base.rb:45:in `inside_template'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/railties-7.1.3.2/lib/rails/generators/named_base.rb:24:in `template'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/activerecord-7.1.3.2/lib/rails/generators/active_record/model/model_generator.rb:38:in `create_module_file'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/command.rb:28:in `run'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/invocation.rb:127:in `invoke_command'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/invocation.rb:134:in `block in invoke_all'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/invocation.rb:134:in `each'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/invocation.rb:134:in `map'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/invocation.rb:134:in `invoke_all'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/group.rb:232:in `dispatch'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/invocation.rb:116:in `invoke'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/group.rb:277:in `block in _invoke_for_class_method'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/shell.rb:68:in `with_padding'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/group.rb:266:in `_invoke_for_class_method'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/group.rb:134:in `_invoke_from_option_orm'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/command.rb:28:in `run'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/invocation.rb:127:in `invoke_command'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/invocation.rb:134:in `block in invoke_all'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/invocation.rb:134:in `each'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/invocation.rb:134:in `map'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/invocation.rb:134:in `invoke_all'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/group.rb:232:in `dispatch'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/base.rb:584:in `start'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/railties-7.1.3.2/lib/rails/generators.rb:261:in `invoke'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/railties-7.1.3.2/lib/rails/commands/generate/generate_command.rb:26:in `perform'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/command.rb:28:in `run'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor/invocation.rb:127:in `invoke_command'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/railties-7.1.3.2/lib/rails/command/base.rb:178:in `invoke_command'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/thor-1.3.1/lib/thor.rb:527:in `dispatch'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/railties-7.1.3.2/lib/rails/command/base.rb:73:in `perform'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/railties-7.1.3.2/lib/rails/command.rb:71:in `block in invoke'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/railties-7.1.3.2/lib/rails/command.rb:149:in `with_argv'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/railties-7.1.3.2/lib/rails/command.rb:69:in `invoke'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/railties-7.1.3.2/lib/rails/commands.rb:18:in `<main>'
	from <internal:/Users/danieltenner/.rvm/rubies/ruby-3.3.0/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
	from <internal:/Users/danieltenner/.rvm/rubies/ruby-3.3.0/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
	from /Users/danieltenner/.rvm/gems/ruby-3.3.0/gems/bootsnap-1.18.3/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
	from bin/rails:4:in `<main>'

I think it's creating the files that it is creating correctly, but I guess some files are missing...

➜  promptcraft git:(main) ✗ gst     
On branch main
Your branch is up to date with 'origin/main'.

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	app/models/input_item/
	db/migrate/20240513091444_create_input_item_prompt_executions.rb

nothing added to commit but untracked files present (use "git add" to track)
class CreateInputItemPromptExecutions < ActiveRecord::Migration[7.1]
  def change
    create_table :input_item_prompt_executions do |t|
      t.references :prompt_execution, null: false, foreign_key: true
      t.references :input_item, null: false, foreign_key: true

      t.timestamps
    end
  end
end

app/models/input_item/prompt_execution.rb:

class InputItem::PromptExecution < ApplicationRecord
  belongs_to :prompt_execution
  belongs_to :input_item
end
@swombat
Copy link
Author

swombat commented May 13, 2024

All scaffolds that were used to get to this point are here: https://github.com/swombat/promptcraft/blob/main/SCAFFOLDING.md

@jagthedrummer
Copy link
Contributor

@swombat I don't know if it would help but you might try making the namespace for InputItem:: plural instead of singular. Generally having a namespace that exactly matches a model is a recipe for trouble of various sorts. So instead of InputItem::PromptExecution (singular namespace) I'd recommend trying InputItems::PromptExecution (plural namespace).

@swombat
Copy link
Author

swombat commented May 18, 2024

Ah, perhaps! I stopped using namespaces because of the other issues with them (sortable, etc), so I forgot this little trick... Will try again.

@jagthedrummer
Copy link
Contributor

@swombat I just ran all of the scaffolders from your repo (https://github.com/swombat/promptcraft/blob/main/SCAFFOLDING.md) and then experimented with the join model you listed in this issue. If I pluralize the namespace it doesn't hang.

$ rails generate super_scaffold:join_model InputItems::PromptExecution prompt_execution_id{class_name=PromptExecution} input_item_id{class_name=InputItem}
Generating model with 'bin/rails generate model InputItems::PromptExecution prompt_execution:references input_item:references'
Updating './app/models/input_items/prompt_execution.rb'.
Updating './app/models/input_items/prompt_execution.rb'.
Updating './app/models/input_items/prompt_execution.rb'.
No need to update './app/models/input_items/prompt_execution.rb'. It already has 'belongs_to :prompt_execution'.
Updating './app/models/input_items/prompt_execution.rb'.
Updating './app/models/input_items/prompt_execution.rb'.
Updating './app/models/input_items/prompt_execution.rb'.
No need to update './app/models/input_items/prompt_execution.rb'. It already has 'belongs_to :input_item'.
Updating './app/models/prompt_execution.rb'.
Updating './app/models/prompt_execution.rb'.
Updating './app/models/input_item.rb'.
Updating './app/models/input_item.rb'.

So far I haven't been able to figure out exactly what's happening when it does hang with the singular version.

@jagthedrummer
Copy link
Contributor

OK, I see what's causing the hang. If you run the model generation command that super scaffolding runs for you it asks if you want to overwrite the singularized input_item.rb file. But since the way that we shell out isn't interactive the question gets swallowed and there's no way to get a response back in.

$ rails generate model InputItem::PromptExecution prompt_execution:references input_item:references
      invoke  active_record
      create    db/migrate/20240603162946_create_input_item_prompt_executions.rb
      create    app/models/input_item/prompt_execution.rb
    conflict    app/models/input_item.rb
  Overwrite /Users/jgreen/projects/bullet-train-co/join-model-hang-test/app/models/input_item.rb? (enter "h" for help) [Ynaqdhm]

We should probably try to detect that the "namespace parent file" collides with an existing model, warn you about it, and bail out.

@jagthedrummer
Copy link
Contributor

We should probably try to detect that the "namespace parent file" collides with an existing model, warn you about it, and bail out.

@gazayas, just wanted to ping you and see if you have an immediate feel for where this should be done. In the JoinModelScaffolder seems like an obvious place, but it seems like we have some similar "namespace deconfliction" type stuff in scaffolding/script.rb and I'm not sure if we should try to lean on that or not. If you don't have an immediate idea I'm happy to figure it out.

@gazayas
Copy link
Contributor

gazayas commented Jun 4, 2024

@jagthedrummer I reflected on namespaces a little while back here, and I think it's more of a Bullet Train philosophy/framework-wide issue, so maybe script.rb would be a good place to check for the parent (can't say off the top of my head). Definitely not good if the script is hanging when we should be bailing out instead.

I'll try to think of a good spot for it in the meantime!

@jagthedrummer
Copy link
Contributor

I just confirmed that this same issue happens if you super scaffold a normal model (not a join model) with a namespace that matches an existing model.

For instance:

$ rails generate super_scaffold Prompt::Widget Prompt,Project,Team name:text_field description:trix_editor contents:text_area --sortable

Generating Prompt::Widget model with 'bin/rails generate model Prompt::Widget prompt:references name:string description:text contents:text'

Definitely seems like we need a common solution for both types of scaffolders.

jagthedrummer added a commit to bullet-train-co/bullet_train-core that referenced this issue Jun 4, 2024
Fixes: bullet-train-co/bullet_train#1457

Previously superscaffolding commands would hang indefinitely if you
tried to geneate a model that has a namespace that exactly matches an
existing class.

Now we'll detect that problem and will show you a message letting you
know that you need to deconflict the namespace.

```
$ rails generate super_scaffold:join_model InputItem::PromptExecution prompt_execution_id{class_name=PromptExecution} input_item_id{class_name=InputItem}
It looks like the namespace you gave for this model conflicts with an existing class: InputItem
You should use a namespace that doesn't clobber an existing class.

We reccomend using the pluralized version of the existing class.

For instance instead of InputItem use InputItems
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants