Understand the underscore method provided by ActiveSupport in Ruby on Rails

Understand the underscore method provided by ActiveSupport in Ruby on Rails


The underscore method

This method is used to convert a string from CamelCase, also called PascalCase, to underscored snake_case.

The method is provided by ActiveSupport.


ActiveSupport

The ActiveSupport module in Rails plays a fundamental role in enhancing the functionality and convenience of the framework. It serves as an extension to the Ruby standard library, providing a bunch of utility methods and enhancements that enrich the development experience.


Naming conventions

Additionally, ActiveSupport actively contributes to the adherence of Rails' naming conventions by providing methods like underscore, which enables the seamless conversion of ConstantNames to file_names and other cases.


The underscore method usage

Database Table Names

When defining database tables in Rails, the convention is to use pluralized, underscored names. For example, if you have a class named UserGroup, calling underscore on it would return 'user_groups', which can be used as the corresponding database table name.


File Naming

Rails follows a consistent file naming convention, where files are named using snake_case and classes follow the camel case pattern.

For instance, if you have a model class named ArticleCategory, using underscore will convert it to 'article_category.rb', which is the expected filename.


URL Routes

Route URLs are typically defined in snake_case format. When generating URLs or working with routing, using underscore helps ensure consistency with route naming.

For example, if you have a route for ArticleCategoryController, calling underscore on it will provide 'article_category', which can be used in routing definitions.


Implementation

# File activesupport/lib/active_support/inflector/methods.rb, line 92
    def underscore(camel_cased_word)
      return camel_cased_word unless /[A-Z-]|::/.match?(camel_cased_word)
      word = camel_cased_word.to_s.gsub("::".freeze, "/".freeze)
      word.gsub!(inflections.acronyms_underscore_regex) { "#{$1 && '_'.freeze }#{$2.downcase}" }
      word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2'.freeze)
      word.gsub!(/([a-z\d])([A-Z])/, '\1_\2'.freeze)
      word.tr!("-".freeze, "_".freeze)
      word.downcase!
      word
    end

Scope resolution operator

The line return camel_cased_word unless /[A-Z-]|::/.match?(camel_cased_word) is going to check if the input contains any uppercase letters or the scope resolution operator ::.

If it doesn't, indicating that the word is already underscored or doesn't require conversion, the original word is returned as is.

If the word needs to be converted, the code proceeds with the conversion logic.


Name namespaces

The line word = camel_cased_word.to_s.gsub("::".freeze, "/".freeze) replaces the :: scope resolution operator with a forward slash /.

This step is done to handle namespaced class/module names and convert them into a path-like format.


Find acronyms

The next line word.gsub!(inflections.acronyms_underscore_regex) { "#{$1 && '_'.freeze }#{$2.downcase}" } handles special cases for acronyms.

It uses a regular expression defined in the inflections module to find acronyms within the word and replaces them with an underscore followed by the lowercase version of the acronym. This ensures consistent formatting of acronyms within the underscored word.


Conversion

The two subsequent gsub! lines handle the conversion of CamelCase to snake_case based on regular expressions.


Handle hyphens

The line word.tr!("-".freeze, "_".freeze) replaces any hyphens (-) with underscores (_) to handle cases where hyphens are used instead of spaces or underscores.


Convert to lowercase

word.downcase! converts the entire word to lowercase, ensuring consistency in the output format.


Return

The resulting word, which was created at the beginning of the mehtod, is then returned as the underscored version of the camel_cased_word (the input).


Be happy

You got here. Way to go!

The Office GIF - The Office Happy - Discover & Share GIFs


Let's connect


Final thoughts

I hope this article helped you. Let me know if you have any questions. Your thoughts, suggestions and corrections are more than welcome. By the way, feel free to drop your suggestions on new blog articles.

Hope to see you next time.