ClassyEnum vs other gems

Peter Brown edited this page Nov 30, 2013 · 1 revision
Clone this wiki locally

Someone asked a question as to whether ClassyEnum was a good fit for their use case. I thought it might be useful to others, so I moved my response to the Wiki. The original question can be found here.

I see at least four different options for state-like patterns that have similar, but different use cases.

  • Class-less enums
  • ClassyEnum
  • STI
  • State Machine

Class-less enums (enumerize, SimpleEnum) are great for simple use cases where you just need a field to represent one of a fixed set of values. The main issue I have with this solution is that it encourages conditionals scattered throughout your models, controllers and views. It's tempting to use these gems because they are the simplest to implement, but the long term payoff just isn't there IMO for anything but the simplest cases.

ClassyEnum was designed to solve the problem of having scattered conditional logic related to the different enums. You can still use it for simple collections that don't have logic, but when you do need to add logic (and you almost certainly will), you can push that into the individual enum classes and take advantage of polymorphism.

Single Table Inheritance, like ClassyEnum, lets you take advantage of polymorphism, but it's really solving a different problem. STI is best for cases where you need a full Active Record model that has a bunch of attributes persisted to the database. ClassyEnum on the other hand would be used to alter the behavior of a model based on a single attribute. I tend to use STI and ClassyEnum in conjunction much of the time. For example, say you had a User model that used STI where you had two types of users, AdminUser and RegularUser. This is a great use for STI because it lets you separate the behavior of these two users, and having shared logic in the parent User class. Where ClassyEnum comes in is if you wanted two different AdminUsers to behave differently based on a single property of their model. For example if you wanted to have different levels of admin users you could have a "level" attribute that used ClassyEnum. Sure, you could introduce another type of User like LimitedAdminUser, but if all the behavior is related to this one property, it makes more sense to use ClassyEnum and encapsulate the behavior in the enum class.

State Machine is typically what I end up using instead of ClassyEnum in some cases. The main advantage that State Machine has over ClassyEnum is that it gives you the ability to fire off callbacks when state changes. For example, if you wanted an email to be sent out when an alarm changed from low priority to high priority, state machine gives you this out of the box. ClassyEnum still has a few advantages though. 1) It is simpler to implement. There is no DSL to learn since the enum classes are just plan Ruby classes. The State Machine README is pretty intimidating for first time users. 2) ClassyEnum doesn't require you to define the state logic in the model itself. This lets you encapsulate the logic for each state in a separate class, but still access the model instance if needed.