Here you will find ideas and code straight from the Software Development Team at SportsEngine. Our focus is on building great software products for the world of youth and amateur sports. We are fortunate to be able to combine our love of sports with our passion for writing code.
The SportsEngine application originated in 2006 as a single Ruby on Rails 1.2 application. Today the SportsEngine Platform is composed of more than 20 applications built on Rails and Node.js, forming a service oriented architecture that is poised to scale for the future.
Let’s say you want to store something in the database where you'll have only a few valid choices (e.g., user’s status, page layout, or player skill level). Your first thought might to be to store the value (“Novice”, “Intermediate”, “Advanced”) right in the database. What happens when you want to change “Novice” to “Beginner”? You’ll have to change your code to reflect this and change the records in the database to reflect this new name.
Maybe instead, you make a hash of the values stored in the database versus the display value: {"novice" => "Beginner", "intermediate" => "Intermediate", "advanced" => "Advanced"}. Now you can change the display value without changing the data or code. But you’ve still got some headaches ahead of you. How do you validate that records contain a valid value? How do you refer specifically to the “beginner” display string in your views?
We run into this pattern throughout our application, so we wrote the enumerated_field gem to solve the problem for us, letting us focus less time on wrangling values and more time making NGIN awesome. Add gem enumerated_field to your Gemfile and you’re on your way.
Say you have a Player model which stores the player's skill level. You'd set that up like so:
class Player < ActiveRecord::Base
include EnumeratedField
enum_field :level, [
["Novice", "novice"],
["Intermediate", "intermediate"],
["Advanced", "advanced"],
]
end
This declares that you want the three choices “Novice”, “Intermediate”, and “Advanced” to display as choices for the level attribute in your model, which will be stored in the database as “novice”, “intermediate”, and “advanced”. You can change the display values all you want, right here in the declaration, without having any effect on the underlying database values.
Doing this also gets you plenty of convenience methods to work with the list of valid choices for your players’ skill level.
Take a look at the gem's documentation for even more methods at your disposal.
Out of the box, you also gain validation, by way of Rails validates_inclusion_of, to ensure that you don’t save invalid values. Feel free to disable this behavior by passing :validate => false after the list of values. If you want to keep validation, but allow blank values, pass :allow_blank => true, or to allow nil, pass :allow_nil => true.
enum_field :level, [
["Novice", "novice"],
["Intermediate", "intermediate"],
["Advanced", "advanced"],
], :validate => false
enum_field :level, [
["Novice", "novice"],
["Intermediate", "intermediate"],
["Advanced", "advanced"],
], :allow_nil => true
Often, people use integers for the database values, because they offer better performance than using strings. But strings provide human-readable queries. Why can’t you get amazing performance and human-readable queries? It turns out you can!
Many relational databases provide an enum type for which you supply a short list of valid values, which provide exactly this balance of performance and readability. Unfortunately, Rails doesn’t provide migrations for this type, but help is on the way. At TST Media, we use the enum_column gem to create enum columns in our database, like so:
add_column :players, :level, :enum,
:limit => ["novice", "intermediate", "advanced"]
This gem has helped us, using it nearly 30 times in NGIN so far, and we think it could help you, too. Go forth and install enumerated_field. Please also feel free to contribute on GitHub.