Repository navigation
Add an ActionMailerHelpers compiler for mailers' HelperMethods modules - #2761
Open
ndbroadbent wants to merge 2 commits into
Open
ndbroadbent wants to merge 2 commits into
ndbroadbent wants to merge 2 commits into
Conversation
…ts helpers A controller's `HelperMethods` includes its parent controller's module, and the compiler listed every module from that chain again in each controller's RBI. Rails calls `helper :all` on each direct subclass of `ActionController::Base` (`include_all_helpers`, on by default), so every controller below `ApplicationController` that has helpers of its own lists every module in app/helpers, and adding one helper module rewrites all of their RBIs. When the parent's module is one this compiler generates an RBI for, include it and only the modules the controller adds. A direct subclass of `ActionController::Base` still lists every module, because the gem RBI for `ActionController::Base::HelperMethods` can't know the helpers other gems add to it at runtime. The parent is found from the class chain, not from the gathered constants, so `tapioca dsl UserController` generates the same RBI as `tapioca dsl`.
A mailer that calls `helper` or `helper_method` gets its own `HelperMethods` module from `AbstractController::Helpers`, just like a controller, and its views include it. Tapioca generated these only for controllers, so Sorbet didn't know `NotifierMailer::HelperMethods` existed, nor the methods that `helper_method` and `helper do ... end` define in it. The new compiler writes the same module for mailers, without the `helpers`/`HelperProxy` pair, which mailers don't have. The code that builds the module moves from ActionControllerHelpers into `Tapioca::Dsl::Helpers::HelperMethodsHelper`, which both compilers include, so mailers also include their parent mailer's module and only the helper modules they add.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #2760: review that one first.
Motivation
A mailer that calls
helperorhelper_methodgets its ownHelperMethodsmodule fromAbstractController::Helpers, as a controller does, and its views include it. Tapioca generates these only for controllers, so Sorbet doesn't knowNotifierMailer::HelperMethodsexists, nor the methods thathelper_methodandhelper do ... enddefine in it. We hit this type-checking mailer views, whose classes include their mailer's module.Implementation
ActionMailerHelperscompiler writes each mailer'sHelperMethods, without thehelpersmethod andHelperProxyclass, which mailers don't have.ActionControllerHelpersintoTapioca::Dsl::Helpers::HelperMethodsHelper, which both compilers include, so mailers also include their parent mailer's module and only the modules they add.#: self as HelperMethodsHelper & Compiler[untyped]in the one method that callscreate_method_from_def, becauserequires_ancestorcan't name the genericCompiler. Happy to share the code another way if you prefer, for example a separate compiler with its own copy.Tests
action_mailer_helpers_spec.rb, modelled on the controller compiler's: which mailers it gathers, a module with an included helper, ahelper_methodwith a sig, one whose target doesn't exist and ahelperblock, a parent mailer's module, and a single requested mailer. The controller spec passes unchanged.