Open vinistock opened 2 years ago
This'd be very useful for me, I'm trying to move to tapioca's DSL generators from sorbet-rails and one major thing I'm missing is the "Extra helper includes" config option that sorbet-rails has.
I don't know if this will be particularly useful, but I've finally moved my Rails app over to Tapioca DSLs and created a custom DSL compiler to get this functionality working:
# typed: true
module Tapioca
module Compilers
# This compiler will generate RBIs for all the helper modules in the repo.
#
# Rails creates these helper modules with no parent class, so Sorbet
# doesn't know what should be included in them.
#
# This is based heavily on the Helpers RBI generator in the sorbet-rails
# gem.
class Helpers < Tapioca::Dsl::Compiler
extend T::Sig
ConstantType = type_member { { fixed: T.class_of(::ActiveRecord::Base) } }
sig { override.returns(T::Enumerable[Module]) }
def self.gather_constants
# API controller does not include ActionController::Helpers
if ApplicationController < ActionController::Helpers
helpers = ApplicationController.modules_for_helpers([:all])
end
# If ApplicationController doesn't work or doesn't return any helpers,
# try using ActionController::Base.
if ApplicationController < ActionController::Helpers && helpers.blank?
helpers = ActionController::Base.modules_for_helpers([:all])
end
# Collect all helpers
helpers
end
sig { override.void }
def decorate
root.create_path(constant) do |klass|
# Default includes:
klass.create_include('Kernel')
klass.create_include('ActionView::Helpers')
# CUSTOM INCLUDES GO HERE:
klass.create_include('Devise::Controllers::Helpers')
end
end
end
end
end
Hello @connorshea, can you share how can I use that helper on my own Rails application? I'm using Devise for authentication and I'm finding that Sorbet does not correctly identify the current_user
method.
@vmrocha I just created config/initializers/tapioca_compilers_helpers.rb
with the contents above and that does generate rbis for a lot of other helpers, but doesn't fix the issue with current_user
:(
Because view helpers are dynamically included by Rails, Sorbet is not aware that the modules will be included into certain classes. We can solve this by generating RBIs that add the right
requires_ancestor
to each helper.There are two possible behaviors outlined in the Rails documentation for include_all_helpers.
If
include_all_helpers
is turned on, then every helper is included intoActionView::Base
. If not, thenapplication_helper
is the only one included intoActionView::Base
and every other gets included only in the controller views they match with (e.g.:UsersHelper
gets included only in views fromUsersController
, but not into views from other controllers).Because Rails loads every module ending in
Helper
as a helper module, I suspect the DSL generator can just filterall_modules
based on whether their name ends withHelper
or not and then produce an RBI that looks like this (depending on the value of the configuration, which may alter therequires_ancestor
statement).