Search code examples
ruby-on-railsrubyruby-on-rails-4

Nested Helpers Issue


I'm trying to migrate a legacy app from 3 to 4 (and of course I'll go to 5 and 6 next). Basically it is a helper heavy app, and it encapsulates a lot of the logic on helpers.

I have some trouble loading helpers on rails 4 and I think I sorted it out but I seem to be having issues with nested helpers. I'm using the traceroute gem to validate that the routes on the routes.rb work properly and I'm coming with some issues there.

Example:

uninitialized constant Permissions
/home/app/helpers/permissions/charts_helper.rb:1:in `<top (required)>'

Charts helper (app/helpers/permissions/charts_helper.rb)

module Permissions::ChartsHelper

  ...

end

Importing of helpers on application.rb:

   config.autoload_paths << Rails.root.join('lib')
   # config.autoload_paths += Dir["#{config.root}/app/helpers/**/"]
   Dir["#{config.root}/app/models/concerns/**/*.rb"].each { |file| require file[0..-4]}
   Dir["#{config.root}/app/helpers/**/*.rb"].each { |file| require file[0..-4]}

(I had to comment out the second line in favor of the 4th line and it seemed to import some helpers but not all)

So basically I'm looking for:

1.) Best way to include these helpers on the applications.rb file 2.) Make the helpers work 3.) Any best practices or other advice that can help me move forward.


Solution

  • module Permissions
      module ChartsHelper
        # ...
      end
    end
    

    Define (and reopen) namespaced classes and modules using explicit nesting. Using the scope resolution operator can lead to surprising constant lookups due to Ruby’s lexical scoping, which depends on the module nesting at the point of definition.
    - the Ruby Style Guide

    Using :: is not a shorthand for explicit nesting and it requires that Permissions be loaded first to avoid a missing constant error.

    module Permissions::ChartsHelper
    end
    # NameError (uninitialized constant Permissions)
    

    It also sets the wrong module nesting:

    FOO = "I'm in the global scope"
    
    module Permissions
      FOO = "I'm Permissions::FOO"
    end
    
    module Permissions::ChartsHelper
      puts FOO # I'm in the global scope
      puts Module.nesting.inspect # [Permissions::ChartsHelper]
    end
    

    In Ruby only the module and class keywords change the current module nesting. By contrast if you explicitly nest the modules:

    FOO = "I'm in the global scope"
    
    module Permissions
      FOO = "I'm Permissions::FOO"
    end
    
    module Permissions
      module ChartsHelper
        puts FOO # I'm Permissions::FOO
        puts Module.nesting.inspect # [Permissions::ChartsHelper, Permissions]
      end
    end