Fun with Rails Constantize

Visualization DiagramHave you ever found yourself working on a Rails project where you need certain behavior in a model based on type but STI[1] is not the right fit or you are already using STI and can not subtype again? I was working on a problem where a model utilized STI to create two types: Icon and Color. Within each type I had different data. Some of the data represented defaults for Icons or defaults for Colors and the others were specific. I’ve put together a little diagram on the right to illustrate this[2].

The way we had modeled the data made it very easy to pick out the specific icon or color theme (using an ActiveRecord finder for that type). However, based on the data instance returned by find I wanted to execute a series of methods to populate other models with data relevant to the Icon or Color instance.

A couple solutions presented themselves[3]:

  1. Refactor the model so that each type was represented by a model type (the orange boxes would become brown ones). We could then call the method we needed from that type.
    • Each data type in our environment would only have one record. Changing the model this way didn’t really make any sense in our situation.
  2. Create a map from data element name to a class that could be invoked to perform the required actions.
    • This would work, but I was feeling lazy and maintaining a map of names to types didn’t feel as DRY as I thought it could be.
  3. Take advantage of the Rails constantize method.
    • We could use the name of the record and dynamically map that string to a class with a method or methods that could be invoked at runtime.

While any of theses solutions could work, the one that I found the most interesting was the one involving constantize (Module
ActiveSupport::CoreExtensions::String::Inflections). If you have poked around the rails source you see that constantize is used for things like in_place_edit (do a find on an object based on a parameter string). If I haven’t lost you yet included below is a code snippet illustrating how this works and solving my problem. It’s important to note that you need to camelize specific_theme_type before calling constantize or it will raise a NameException. In the example below I’ve created a rescue block because not all of my types are mapped to a specific content class and I wanted to fall back to a default in those cases.

begin
  content_type = "Content::#{specific_theme_type.camelize}Content".constantize
rescue NameError
  content_type = Content::Default
end
content_type.content_method

I’ve only touched the surface of things you can do with constantize. If you have also used constantize or another similar trick, please share it in the comments.

Notes:

  1. Single Table Inheritance – Definition of STI, STI in Rails
  2. Apologies for the small digram, full size available here.
  3. I am sure there are other solutions, so feel free to leave comments detailing how you would have done it 😉
Advertisements
Explore posts in the same categories: DRY, rails

3 Comments on “Fun with Rails Constantize”


  1. Yup, Constantize rocks!

    Also don’t know how I’d live without hacks like Model.send (“foo_#{bar}”) or eval(“model.foo_#{bar}=true”).

  2. mike Says:

    Model.send (”foo_#{bar}=”,true) is perhaps a better option?

  3. Lex Sheehan Says:

    Nice example.

    However, as of rails v2.1.0, constantize has been deprecated.

    http://apidock.com/rails/Inflector/constantize


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: