How do I Access Included Help Class Methods in a Rails Controller Using Ruby?

I was building a Rails utility class to handle file uploads when I hit a wall. My goal was simple: format file sizes into human-readable strings (like “2 KB” instead of “2048”) using Ruby Rails’ built-in number_to_human_size helper. But when I tried to call it inside a class method, I got slapped with a NoMethodError. Here’s how I unraveled the mystery and how you can avoid the same trap.

The Problem: “Why Can’t My Class Method See This Helper?”

I started with this code:

class UploadHelper
include ActionView::Helpers::NumberHelper

def instance_upload
puts "Uploading #{number_to_human_size(123)}" # Works!
end

def self.class_upload
puts "Uploading #{number_to_human_size(123)}" # NoMethodError!
end
end

What happened?

  • In instance_upload, the helper worked perfectly.
  • In self.class_upload, it crashed because number_to_human_size was “missing.”

It turns out, this is all about how Ruby shares methods between instances and classes. The include keyword adds methods to the instances of the class, not to the class itself.

The Fix: Two Workarounds (and Why They Work)

Use an Instance Inside the Class Method

def self.class_upload
# Create an instance to access the helper
puts "Uploading #{new.number_to_human_size(123)}" #
end

Why this works:

  • include adds methods to instances, not the class.
  • By creating new, I tap into the instance’s methods, making the helper accessible.

Extend the Module

class UploadHelper
# Add methods to both instances AND the class
include ActionView::Helpers::NumberHelper
extend ActionView::Helpers::NumberHelper # Now available in class methods!

def self.class_upload
puts "Uploading #{number_to_human_size(123)}" #
end
end

Why this works:

  • extend adds the module’s methods as class methods.
  • Now both instances and the class itself can call number_to_human_size.

Leveling Up Adding Extra Functionality

To practice further and add versatility to my utility class, I expanded it to handle more scenarios.

Format File Sizes in Class Methods

def self.upload_info(size_in_bytes)
human_size = new.number_to_human_size(size_in_bytes) # Uses Workaround 1
"File size: #{human_size}"
end

# Example:
UploadHelper.upload_info(2048) # => "File size: 2 KB"

Toggle Between Human-Readable and Raw Sizes

def self.upload_info(size, human: true)
size_str = human ? new.number_to_human_size(size) : size.to_s
"Size: #{size_str}"
end

# Example:
UploadHelper.upload_info(2048, human: false) # => "Size: 2048"

Log All Uploads

def self.log_upload(size)
Rails.logger.info "[Upload] #{upload_info(size)}"
end

Final Thoughts

Working with Rails helper methods inside class methods can be tricky if you’re not aware of how Ruby handles module inclusion. Here are the key takeaways from my experience:

  • include vs. extend Matters:
    • If your helper is for instances, use include.
    • If you need it in class methods, either extend the module or instantiate an object.
  • Avoid Over-Extending:
    Don’t extend modules globally unless necessary; it can clutter your class methods.
  • When in Doubt, Instantiate:
    Using new inside a class method is a safe, explicit way to access instance helpers.
  • Rails Helpers Are Everywhere:
    Modules like ActionView::Helpers are powerful not just for views. They can be leveraged in models, utility classes, or anywhere in your Rails application.

The next time you’re stuck with a NoMethodError in a class method, ask yourself: “Is this method living in instances or the class?” The answer might save you hours of debugging.

Related blog posts