Prefer constant lookups over constantize

Rails constantize and safe_constantize methods are handy for writing dynamic code very quickly, but give maintainers no information about what should be allowed as a dependency. Data structures (sometimes known as registries) that take a known value and return a constant are easier to maintain and modify. This becomes especially important when class names have the possibility to be stored as strings in the database.

Bad 🔗

This code assumes some form of Step will be passed to a class; however, it will accept any string.

class Flow
  def current_step_from(step_name, params)
    step_name.constantize.new(params)
  end
end

# Flow.current_step_from("AboutYouStep", { foo: "bar" }) # => #<AboutYouStep { foo: "bar" }>
# Flow.current_step_from("Topic", { foo: "bar" }) # => instantiates an unexpected #<Topic { foo: "bar" }> object

Good 🔗

A hash data structure helps maintainers know what types of objects should be returned from a dynamic function:

class Flow
  STEPS = {
    "AboutYouStep" => AboutYouStep,
    "PickKeywordsStep" => PickKeywordsStep,
    "CompleteStep" => CompleteStep,
  }

  def current_step_from(step_name, params)
    STEPS.fetch(step_name).new(params)
  end
end

# Flow.current_step_from("AboutYouStep", { foo: "bar" }) # => #<AboutYouStep { foo: "bar" }>
# Flow.current_step_from("Topic", { foo: "bar" }) # => raises KeyError