如何存储和比较:ActiveRecord中的符号(Ruby on Rails)

我认为使用常量填充activeRecord表中的状态字段会很好。 但是,当检查此状态是否具有特定状态时,我遇到了麻烦。

如果我做以下,

e = Mytable.new e.status = :cancelled e.save 

然后重新记录该记录并尝试将我的状态与符号进行比较,检查失败。 我有一些来自控制台的输出来显示这一点。

 irb(main):060:0> e.status.eql?("cancelled") => true irb(main):061:0> e.status.eql?(:cancelled) => false irb(main):062:0> e.status == :cancelled => false irb(main):063:0> e.status == "cancelled" => true irb(main):064:0> e.status == :cancelled.to_s => true 

是否有更好的方法在记录中保持身份? 有没有办法测试当前字段值是否等于:符号而不将:符号转换为字符串? 我想可能有一个我不知道的运营商。

在生态学的要求下,这是我的评论作为答案:

ecoologic有一个很好的解决方案,但我建议远离这个并制作一个带有常量的类。 你可以做像e.status = Statuses :: CANCELED这样的事情。 在内部可能是一个字符串,这无关紧要。 你仍然在使用常量,如果那个常量不存在则会出错,并且它更清晰。

使用Rails 4.1.0,您可能希望使用Active Record枚举。

引用官方发行说明 :

 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 } 

这有点晚了,但可能会帮助别人。

如果你有不同状态的类,你可能会考虑使用常量和范围这样的方法:

 class Account < ActiveRecord::Base #------------------------------------------------------------------------------- # Configuration #------------------------------------------------------------------------------- # STATUS is used to denote what state the account is in. STATUS = { :active => 1, :suspended => 2, :closed => 3 } # Scopes scope :active, where(:status => Account::STATUS[:active]) scope :suspended, where(:status => Account::STATUS[:suspended]) scope :closed, where(:status => Account::STATUS[:closed]) ... end 

然后,您可以根据状态轻松查找记录,如下所示:

 # get all active accounts active_accounts = Consumer.active.all # get 50 suspended accounts suspended_accounts = Consumer.suspended.limit(50) # get accounts that are closed and [some search criteria] closed_accounts = Consumer.closed.where([some search criteria]) 

希望这有助于其他人!

编辑:如果你更喜欢使用gem, simple_enumgem看起来是一个很好的选择。

如果我记得ActiveRecord中的符号是以yaml格式存储的,那么必须进行某种转换,因为关系数据库中没有符号(至少我知道)。 当你读它时,它就是一个与你的符号不匹配的字符串,甚至不符合符号的字符串,实际上它应该是这样的:

 :x # => "--- :x\n" 

我认为这个插件可以解决你的问题,但我并没有诚实地使用它。 https://github.com/zargony/activerecord_symbolize

*编辑*

我留下上面因为我记得那是我所拥有的情况,如果我错了我可以纠正,但是我现在正在尝试这个并且存储的值(Rails 3.1.3)是一个简单的字符串,其值为符号,所以以下应该足够了。

 class Example < ActiveRecord::Base def aaa super.to_sym end def aaa=(value) super(value.to_sym) aaa end end 

这当然会迫使价值永远是一个象征

**编辑后的时间**我认为在这种情况下它很好,因为很明显在db中它是一个字符串而且逻辑很简单,但我强烈反对覆盖db属性方法来添加更复杂的逻辑。

从Rails 4.1开始,Active Record现在支持枚举

从发行说明 :

2.5 Active Record枚举

声明一个枚举属性,其中值映射到数据库中的整数,但可以按名称查询。

 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 } 

其他文档: http : //api.rubyonrails.org/v4.1.0/classes/ActiveRecord/Enum.html

您也可以覆盖reader方法:

 def status read_attribute(:status).to_sym end 

Programming Ruby 1.9开始 ,关于Symbol类中的==运算符(p.729):

 Returns true only if sym and obj are symbols with the same object_id. 

无论您存储在数据库中的是什么,都将始终具有与符号的固定object_id不同的object_id(在这种情况下是指向字符串文字的指针)。