定数を使用して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
レコードにステータスを保持するためのより良い方法はありますか? :symbolを文字列に変換せずに、現在のフィールド値が:symbolと等しいかどうかをテストする方法はありますか?知らないオペレーターがいるかもしれないと思っています。
生態学の要請で、ここに答えとしての私のコメントがあります:
ecoologicはあなたにとって良い解決策を持っていますが、私はこれから離れて、定数を含むクラスを作ることをお勧めします。 e.status = Statuses :: CANCELLEDのようなことができること。そして内部的にはそれは文字列である可能性があり、それは問題ではありません。まだ定数を使用していますが、その定数が存在しない場合はエラーが発生し、その方がクリーンです。
Rails 4.1.0の場合、ActiveRecord列挙型を使用することをお勧めします。
公式リリースノート を引用するには:
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_enum gemが優れた代替手段のように見えます。
Rails 4.1の時点で、ActiveRecordは列挙型をサポートするようになりました
リリースノート から:
2.5アクティブレコード列挙型
値がデータベース内の整数にマップされる列挙型属性を宣言しますが、名前で照会できます。
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
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属性メソッドをオーバーライドしてより複雑なロジックを追加することは強くお勧めしません。
また、reader
メソッドを上書きすることもできます。
def status
read_attribute(:status).to_sym
end
プログラミングRuby 1.9、Symbolクラス(p。729)の==演算子に関して:
Returns true only if sym and obj are symbols with the same object_id.
DBに保存したものはすべて、シンボルの固定object_id(この場合は文字列リテラルへのポインター)とは常に異なるobject_idを持ちます。