Shopify / tapioca

The swiss army knife of RBI generation
MIT License
746 stars 128 forks source link

Missing type declaration ::Turbo::Streams::ActionHelper for turbo-rails. #671

Closed thomasdziedzic-census closed 1 year ago

thomasdziedzic-census commented 2 years ago

I created a brand new rails 7 project. The first thing I did was I added tapioca! I generated all the gem & dsl rbis, fixed all I could, but this one is not obvious and I bet others will have a problem with this as well.

The problem:

% bin/srb tc           
sorbet/rbi/dsl/rails/conductor/action_mailbox/inbound_emails_controller.rbi:16: Unable to resolve constant ActionHelper https://srb.help/5002
    16 |    include ::Turbo::Streams::ActionHelper
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  Autocorrect: Use `-a` to autocorrect
    sorbet/rbi/dsl/rails/conductor/action_mailbox/inbound_emails_controller.rbi:16: Replace with AbstractController::Callbacks::ActionFilter
    16 |    include ::Turbo::Streams::ActionHelper
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  Autocorrect: Use `-a` to autocorrect
    sorbet/rbi/dsl/rails/conductor/action_mailbox/inbound_emails_controller.rbi:16: Replace with Turbo::DriveHelper
    16 |    include ::Turbo::Streams::ActionHelper
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    sorbet/rbi/gems/actionpack@7.0.0.rbi:178: Did you mean: AbstractController::Callbacks::ActionFilter?
     178 |class AbstractController::Callbacks::ActionFilter
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    sorbet/rbi/gems/turbo-rails@1.0.0.rbi:66: Did you mean: Turbo::DriveHelper?
    66 |module Turbo::DriveHelper
        ^^^^^^^^^^^^^^^^^^^^^^^^^
...
Errors: 12

When I checked turbo-rails where that module lives, I found it at https://github.com/hotwired/turbo-rails/blob/main/app/helpers/turbo/streams/action_helper.rb which does not live in the lib path, but it looks like it is autoloaded by this line here: https://github.com/hotwired/turbo-rails/blob/main/lib/turbo/engine.rb#L13

Could you provide some guidance on how I would require that action_helper.rb file in my project so that tapioca will generate the appropriate type definitions?

Thanks for your time!

thomasdziedzic-census commented 2 years ago

For reference, I added a shim for now to get it to type check:

sorbet/rbi/shims/turbo-rails.rbi

# typed: true

# workaround for https://github.com/Shopify/tapioca/issues/671

module ::Turbo::Streams::ActionHelper
end
KaanOzkan commented 2 years ago

You can explicitly require that file in a sorbet/tapioca/require.rb file https://github.com/Shopify/tapioca#manual-gem-requires. Hope that helps.

thomasdziedzic-census commented 2 years ago

@KaanOzkan How would I explicitly require that file? When I include the following line:

require 'app/helpers/turbo/streams/action_helper'

tapioca errors out with:

LoadError: cannot load such file -- app/helpers/turbo/streams/action_helper
KaanOzkan commented 2 years ago

You should pass the "full path" so prepend turbo-rails: require 'turbo-rails/app/helpers/turbo/streams/action_helper'

thomasdziedzic-census commented 2 years ago

@KaanOzkan with the line you provided I get:

LoadError: cannot load such file -- turbo-rails/app/helpers/turbo/streams/action_helper
KaanOzkan commented 2 years ago

I don't have a lot of experience with loading files on the app/ path. I'd expect require 'helpers/turbo/streams/action_helper' to work but locally it's still failing.

Feel free to use the shim for now.

paracycle commented 2 years ago

I've looked into this and this seems to be a loading problem that might take some time to fix.

Here is the problem: Tapioca knows that it should try to load the files in the autoload paths registered by Rails engines, and it tries to emulate how Rails does that as best as it can. However, in this case, the module defined inside app/helpers/turbo/streams/action_helper.rb defines itself as Turbo::Streams::ActionHelper (one-line form). However, no other file actually defines Turbo::Stream anywhere. So naturally, when that file is required, Ruby complains, saying that it doesn't know any Turbo::Streams definition. So Tapioca treats that as a best effort load and swallows the error and moves on.

Now, the way this works in Rails is based on Zeitwerk and Zeitwerk is able to deal with implicit namespaces properly, so the same thing works properly, there.

Tapioca needs a better strategy of loading these app files. I think we can take a look at this in the new year.