How do I convert a Ruby class name to a underscore-delimited symbol?
How can I programmatically turn a class name, FooBar
, into a symbol, :foo_bar
? e.g. something like this, but that handles camel case properly?
FooBar.to_s.downcase.to_sym
Solution 1:
Rails comes with a method called underscore
that will allow you to transform CamelCased strings into underscore_separated strings. So you might be able to do this:
FooBar.name.underscore.to_sym
But you will have to install ActiveSupport just to do that, as ipsum says.
If you don't want to install ActiveSupport just for that, you can monkey-patch underscore
into String
yourself (the underscore function is defined in ActiveSupport::Inflector):
class String
def underscore
word = self.dup
word.gsub!(/::/, '/')
word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
word.tr!("-", "_")
word.downcase!
word
end
end
Solution 2:
Rails 4 .model_name
In Rails 4, it returns an ActiveModel::Name
object which contains many useful more "semantic" attributes such as:
FooBar.model_name.param_key
#=> "foo_bar"
FooBar.model_name.route_key
#=> "foo_bars"
FooBar.model_name.human
#=> "Foo bar"
So you should use one of those if they match your desired meaning, which is likely the case. Advantages:
- easier to understand your code
- your app will still work even in the (unlikely) event that Rails decides to change a naming convention.
BTW, human
has the advantage of being I18N aware.
Solution 3:
first: gem install activesupport
require 'rubygems'
require 'active_support'
"FooBar".underscore.to_sym
Solution 4:
Here's what I went for:
module MyModule
module ClassMethods
def class_to_sym
name_without_namespace = name.split("::").last
name_without_namespace.gsub(/([^\^])([A-Z])/,'\1_\2').downcase.to_sym
end
end
def self.included(base)
base.extend(ClassMethods)
end
end
class ThisIsMyClass
include MyModule
end
ThisIsMyClass.class_to_sym #:this_is_my_class