I thought it would be good to populate a status field in an activeRecord table using constants. However, when it comes to checking if this status has a particular status, I\'m h
If I remember well symbols in ActiveRecord are stored in yaml format, some kind of conversion must be done because there is no such thing as a symbol in relational db (which I'm aware of, at least). When you read it it's then a string which will not match your symbol and not even the string of the symbol, in fact it should be something like:
:x # => "--- :x\n"
I think this plugin can solve your problem, but I haven't used it honestly. https://github.com/zargony/activerecord_symbolize
* EDIT *
I leave the above because I remember that was the situation I had and I can be corrected if I'm wrong, nonetheless I'm trying this right now and the stored value (Rails 3.1.3) is a simple string with the value of the symbol, so the following should be enough.
class Example < ActiveRecord::Base
def aaa
super.to_sym
end
def aaa=(value)
super(value.to_sym)
aaa
end
end
This of course will force the value to always be a symbol
** EDIT AFTER AGES ** I think it's fine in this situation as it's clear that in the db it's a string and the logic is simple, but I strongly discourage overriding db attribute methods to add more complex logic.
At the request of ecoologic, here is my comment as an answer:
ecoologic has a good solution for you, but I would recommend steering away from this and making a class with constants in it. That you can do things like e.status = Statuses::CANCELLED. And internally that could be a string and it doesn't matter. You're still using constants, and it will error out if that constant doesn't exist, and it's cleaner that way.
Also you can overwrite the reader
method:
def status
read_attribute(:status).to_sym
end
As of Rails 4.1, Active Record now supports enums
From the release notes:
2.5 Active Record enums
Declare an enum attribute where the values map to integers in the database, but can be queried by name.
class Conversation < ActiveRecord::Base
enum status: [ :active, :archived ]
end
conversation.archived!
conversation.active? # => false
conversation.status # => "archived"
Conversation.archived # => Relation for all archived Conversations
Conversation.statuses # => { "active" => 0, "archived" => 1 }
Additional documentation here: http://api.rubyonrails.org/v4.1.0/classes/ActiveRecord/Enum.html
With Rails 4.1.0, you'd probably want to use Active Record enums.
To quote the official release notes:
class Conversation < ActiveRecord::Base
enum status: [ :active, :archived ]
end
conversation.archived!
conversation.active? # => false
conversation.status # => "archived"
Conversation.archived # => Relation for all archived Conversations
Conversation.statuses # => { "active" => 0, "archived" => 1 }
From Programming Ruby 1.9, regarding the == operator in the Symbol class (p. 729):
Returns true only if sym and obj are symbols with the same object_id.
Whatever you have stored in the DB will always have different object_id than the fixed object_id of the symbol (a pointer to a string literal, in this case).