JavaScript like object in Ruby on Rails

screenshot

One day, when I was explaining how the routing > params > controllers > views work, I wanted to keep things as simple as possible, so I needed a way to flexibly “mock” AR objects.

And the JavaScript-like objects would be a good-enough solution for it.

let obj = {}
obj.some_field
// undefined - N.B. no error raised
obj.some_field = "some value"
obj.some_field
// "some value" - JS "magic"

In contrast, the Ruby’s Object does not allow it.

The nearest Ruby’s type to flexibly fake a model is Hash.

But you need to use those [...] square brackets with key names

obj = {}
obj[:some_field]
# nil
obj[:some_field] = "some value"
obj[:some_field]
# "some value"

which breaks the controller and views code that expects it to be like this

<%= user.name %>
# and not
<%= user[:name] %>

It turns out that the Ruby on Rails already has this JS-like functionality.

Enter the ActiveSupport::OrderedOptions < Hash

obj = ActiveSupport::OrderedOptions.new
obj.some_field
# nil
obj.some_field = "some value"
obj.some_field
# "some value"

And it has a “bonus”. If you need it to raise an exception when the value is blank, just add a bang !

obj.some_empty_field!
# => raises KeyError: :some_empty_field is blank

Also, it has a useful “sibling” ActiveSupport::InheritableOptions which allows to initialize from other such objects or Hash-es.

obj = ActiveSupport::InheritableOptions.new({ some_field: "some value" })
obj.some_field
# "some value"
obj.some_empty_field
# nil

Yay 🎉

Disclaimer: I know that it is best to fake the AR models by introducing step by step all of the parts of the ActiveModel into a PORO. But for a person that’s new to the Rails it would be an unnecessary mental (over)loading at this stage. And the person already new the JavaScript 😅 so the choice was obvious.