For a Rails 3.0 Todo app, I have a Tasks model with a Status field. What's the best way to store the Status field data (field type) and still display a human-readable version in a view (HTML table)? Status can be:
0 = Normal
1 = Active
2 = Completed
Right now I have this:
Rails Schema Here:
create_table "tasks", :force => true do |t|
t.integer "status", :limit => 1, :default => 0, :null => false
Rails Model Here:
class Task < ActiveRecord::Base
validates_inclusion_of :status, :in => 0..2,
:message => "{{value}} must be 0, 1, or 2"
Rails View Here:
<h1>Listing tasks</h1>
<table>
<tr>
<th>Status</th>
<th>Name</th>
<th></th>
<th></th>
<th></th>
</tr>
<% @tasks.each do |task| %>
<tr>
<td><%= task.status %></td>
<td><%= task.name %></td>
<td><%= link_to 'Show', task %></td>
<td><%= link_to 'Edit', edit_task_path(task) %></td>
<td><%= link_to 'Delete', task, :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
<% end %>
</table>
Requirements
Store a Task's status in the db such that the values are easily localizable, i.e. I'm not sure I want to store "normal", "active", "completed" as a string field.
Solution must work with Rails 3.0.
Questions:
Should I store the field as an integer (see above)? If so, how do I display the correct human readable status in an HTML table in my Rails view, e.g. show "Active" instead of "1" in the HTML table.
Should I use an enum? If so, is this easy to localize later?
Should I use straight strings, e.g. "Normal", "Active", "Completed"
Can you provide a quick code sample of the view helper, controller or view code to make this work?
Using integer to store the status is a good idea. Nonetheless, I think the code provided by the accepted answer is not elegant since it pollutes the whole model class just because of an attribute.
My suggestion is overriding the attribute getter:
The logic of transforming the integer into a string will be only in this getter method, so you don't need to make the class dirty.
1.It depends on how much you want to optimize queries on the DB.
2.Not really,
it is not supported 'out of the box' by AR.# As of Rails 4 enums are supported out of the box.3.IMHO you can use strings without a big performance penalty (just remember to add field to an index). I would do this because it's easier to internationalize and to maintain. However, you can go with integers if you need extra performance.
You may take a look on 2 SO threads here and here where this is debated.
4.If you want to keep them as integer, here is how you can accomplish this:
and in view:
If you want to use strings, it's more simplified:
The easiest thing to do would be to just store the actual strings in the field instead of adding another table. Depending on your point of view this is either a bad idea as your database will not be sufficiently normalized or a great idea as your app is now more efficient for being normalized.
If you opt to not do that and to keep the values in a separate table; you need to setup the relationships in the model.
Then in your view you can reference the value by:
I prefer to store "normal", "active", .. "completed" as string in the table because:
These days, I tend to decouple Rails constants from the database as much as I can. There are always some PHP/MSSQL/??DBA folks around us (who may not love Rails as much as we do ;-)
So, the answer is not integer nor enum (but a varchar ;-)
I have used Enum-Column for such use cases. The plugin allows you to define a enum column type in your migration script and creates a MYSQL enum column type for the attribute.
Now in your code you can do the following:
Works well with serialization too:
Other nice aspect is, the status values are displayed as strings when viewed using a regular DB client(E.g: mysql command console or phpMyAdmin)
The plugin provides optimal storage and user friendly access for the enumeration types.
Caveat:
The plugin is quite old and not maintained. I am using it extensively with MySQL DB. I had to patch the code to get it work on PostgreSQL. If you are using MySQL, this plugin is a good choice.
I know this is an old question but I wanted to mention 2 points that come from experience, especially if someone is looking for this now ( 2014 - OQ was in 2010) :