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

sea*_*boy 25 activerecord symbols ruby-on-rails ruby-on-rails-3

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

如果我这样做,

e = Mytable.new
e.status = :cancelled
e.save
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

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

jie*_*eng 13

使用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 }
Run Code Online (Sandbox Code Playgroud)


Mik*_*keH 9

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

如果您有具有不同状态的类,您可能会考虑使用常量和范围的方法,如下所示:

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
Run Code Online (Sandbox Code Playgroud)

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

# 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])
Run Code Online (Sandbox Code Playgroud)

希望这有助于其他人!

编辑:如果你更喜欢使用宝石,simple_enum宝石看起来是一个很好的选择.


eco*_*gic 7

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

:x # => "--- :x\n"
Run Code Online (Sandbox Code Playgroud)

我认为这个插件可以解决你的问题,但我没有诚实地使用它. 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
Run Code Online (Sandbox Code Playgroud)

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

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


MrD*_*anA 7

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

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


Rea*_*nly 7

从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 }
Run Code Online (Sandbox Code Playgroud)

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


fgu*_*len 6

您也可以覆盖该reader方法:

def status
  read_attribute(:status).to_sym
end
Run Code Online (Sandbox Code Playgroud)