Suppose you’re building a helper module inclusion pollutes your interface in Rails and want to use form_for from ActionView::Helpers::FormHelper. Including the module directly works, but it exposes all its methods publicly in your helper:
module ApplicationHelper
include ActionView::Helpers::FormHelper # Exposes form_for, form_tag, etc.
def custom_form
form_for(...) # Works, but now FormHelper's methods are public in ApplicationHelper.
end
end
This feels invasive, especially if you only need one or two methods from the included module. You might also encounter this issue when including route helpers (Rails.application.routes.url_helpers) in non-controller classes.
Include the Module and Privatize Its Methods
Ruby allows you to mark methods as private after including a module. This hides them from the public interface while still allowing internal use:
module ApplicationHelper
include ActionView::Helpers::FormHelper
# Privatize all methods from FormHelper
private(*ActionView::Helpers::FormHelper.public_instance_methods)
def custom_form
form_for(...) # Method works internally but isn't publicly exposed.
end
end
How It Works
include ActionView::Helpers::FormHelperadds all its public methods toApplicationHelper.private(*FormHelper.public_instance_methods)marks those methods as private, hiding them from the public interface.
Pros:
- Simple and idiomatic.
- Retains access to all methods internally.
Cons:
- If the included module has many methods, listing them explicitly might feel unwieldy (though
*public_instance_methodsautomates this).
Use Delegation to Expose Only What You Need
If you only need specific methods, consider delegating to an object that includes the module. For example, create a proxy object inside your class:
module ApplicationHelper
class FormProxy
include ActionView::Helpers::FormHelper
end
def custom_form
FormProxy.new.form_for(...) # Explicitly call form_for via the proxy.
end
end
How It Works
- The
FormProxyclass encapsulates the included module. - You call methods on an instance of the proxy instead of polluting
ApplicationHelper.
Pros:
- Zero pollution of the helper’s interface.
- Explicit control over which methods are used.
Cons:
- Requires instantiating a new object for each method call.
- May not work for modules that rely on Rails’ view context (e.g., methods needing access to
@output_buffer).
Refine the Module (Advanced)
Ruby’s refinements allow you to include a module’s methods in a limited scope. While less common in Rails, refinements can restrict method exposure:
module ApplicationHelper
module FormHelperIntegration
refine ApplicationHelper do
include ActionView::Helpers::FormHelper
end
end
using FormHelperIntegration # Activate refinement
def custom_form
form_for(...) # Available only within this module.
end
end
How It Works
- The
refineblock addsFormHelpermethods toApplicationHelperonly within the scope of the refinement. using FormHelperIntegrationactivates the refinement.
Pros:
- Methods are scoped to the module.
- No pollution of the public interface.
Cons:
- Refinements are lexically scoped, which can be confusing.
- Not widely used in Rails, so may surprise other developers.
Why Not Include Modules Inside Methods?
Including a module inside a method (e.g., inside custom_form) technically works but has downsides:
def custom_form extend ActionView::Helpers::FormHelper form_for(...) end
- Performance: Extending the module on every method call adds overhead.
- Maintenance: Repeating
extendacross multiple methods is error-prone.
Only use this approach for one-off cases where module inclusion is truly dynamic.
Final Thoughts
Ruby’s flexibility lets you balance convenience and cleanliness when including modules:
- Privatize methods for a quick, idiomatic solution.
- Delegate to a proxy for surgical precision.
- Refinements for advanced, scoped inclusion.
In Rails, most helpers (like form_for) are already included in the view context. If you’re working within standard helpers (e.g., ApplicationHelper), you likely don’t need to include anything just call the methods directly. For external classes, privatizing methods after inclusion keeps your interface tidy.

