What is a constant in Ruby?
A constant is a type of variable which always starts with a capital letter. They can only be defined outside of methods, unless you use metaprogramming.
Constants are used for values that aren’t supposed to change, but Ruby doesn’t prevent you from changing them.
They look like this:
FRUIT = "orange"
Now:
Because constants are an important topic we’re going to explore them in detail in this article!
How to Define Constants
A constant doesn’t require any special symbol or syntax to declare. You just need to make the first letter an uppercase letter.
The following are valid constants:
ABC = 1 Goo = 2 Foo = 3
Notice that you can’t define constants inside a method.
You will get this cryptic error message:
def the_method ABC = 1 end # "dynamic constant assignment"
So just define your constants outside methods, typically we want to have constant definitions at the top of your class so they are clearly visible.
class RubyBlog URL = "rubyguides.com" AUTHOR = "Jesus Castello" end
You can then access these constants inside the class methods or outside the class using the following syntax:
p RubyBlog::AUTHOR # "Jesus Castello"
We are going to talk a bit more about the scope of constants later in this post, so stay tuned for that!
Uninitialized Constant Error
One common error that you may get is this:
puts Foo # "uninitialized constant Foo (NameError)"
I want you to mentally translate this error to “constant not found”.
One important point to understand this error is that Ruby classes are constants.
Examples:
Array String Hash
They are constants because the first letter is uppercase.
When you define a class, what you’re really doing is creating a Class
object, which is assigned to a constant.
The constant becomes the class name.
Why is this important?
Because the most likely reason that you are seeing an “uninitialized constant” error is that you forgot to require
a file or gem that defines the constant.
Or maybe you just misspelled the name of the constant.
So keep an eye open for that.
Constants Can Change
Like I mentioned in the introduction, Ruby constants can change.
Example:
ABC = 1 ABC = 2
But you will see this warning message:
2: warning: already initialized constant ABC
Your program will still work fine, but you want to avoid this.
There is no way to prevent a constant from changing because variables in Ruby are not containers, they are simply pointers to objects.
Or labels, if you prefer.
The best you can do is to use immutable objects.
Example:
AUTHOR = "Jesus Castello".freeze AUTHOR << "o" # RuntimeError: can't modify frozen String
Related article: Ruby mutability & the freeze method.
In this example, you can still change what the AUTHOR
constant is pointing to, the only thing freeze
protects you from is from changing the object itself.
Constant Methods
There are a few methods dedicated to working with constants:
Method | Description |
---|---|
constants | Returns an array of symbols that represent the constants defined in a class |
const_get | Returns value for a constant. Takes a symbol or string as parameter |
const_set | Sets the value for a constant. Takes two parameters: constant name as a symbol & constant value |
const_missing | Same as method_missing but for constants |
const_defined? | Returns true if a given constant (as a symbol) has been defined |
remove_const | Removes a constant |
private_constant | Makes a constant private so it can’t be accessed outside the class with Class::ABC syntax |
There are a few metaprogramming tricks you can do using these methods.
Example:
module Food class Bacon; end class Chocolate; end end puts "Classes defined inside #{Food}:" puts Food.constants
Also you can use a string like “Array” & get the actual class:
array_class = Object.const_get("Array")
But be careful with that one because a user could inject code if the string is coming from params
or some other form of user input.
In Rails, there is the constantize method which basically does const_get
for you, but keep in mind that it doesn’t do any security checks.
CheatSheet
Ruby Constant Scope
When you create a constant outside of any class, at the top-level of your code, that constant will be available anywhere.
Constants are also available in child classes.
class A FOO = 1 end class B < A def foo puts FOO end end B.constants # [:FOO]
Constants defined outside a nested module or class are also available inside the nested classes.
module Food STORE_ADDRESS = "The moon" class Bacon def foo; puts STORE_ADDRESS; end end end fb = Food::Bacon.new fb.foo # "The moon"
Module Mixing
Constants from mixed-in modules are also available:
module Mixin A = 123 end class Product include Mixin puts A end # 123
Notice that this works when including the module, it won’t work if you are extending it.
Example:
class Product extend Mixin puts A end # uninitialized constant Product::A
Also:
When you use a method that has been included from a module, Ruby will look for constants starting where that method is defined.
Example:
module Parent def print_value VALUE end end class Child include Parent VALUE = 1 end # Works p Child::VALUE # uninitialized constant Parent::VALUE p Child.new.print_value
Something to keep in mind!
Module Nesting
I want to show you one more example with nested classes (same for modules).
class A FOO = 1 end class A::B class C puts FOO end end
Notice the A::B
notation here, which we tried to use as a shortcut. But the problem is that class C
won’t have access to FOO
directly.
For that reason, you want to stick to this kind of nesting:
class A FOO = 1 end class A class B class C puts FOO end end end
In the first example, you can still do ::A::FOO
to access the constant, but if the class name changes then you will get an error.
This ::A::FOO
syntax works because it tells Ruby to look in the top-level scope, where constants like Array
& String
are defined.
Video
Summary
You learned about Ruby constants, a type of variable which has some interesting behavior. You can change the value of a constant but it will print a warning.
You also learned that class names are constants & that you should avoid const_get
with user input.
If you enjoyed this post don’t forget to share it so more people can understand how constants work.
Thanks for your post!
I just wanted to point out that it is possible to access a child-defined constant from the parent by prepending
self.class::
to the constant:Works
Also works
Thanks for reading & sharing this example with us 🙂