Как хранить и сравнивать: символы в 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
Есть ли лучший способ сохранить статус в записи? Есть ли способ тестирования, если текущее значение поля равно символу: без преобразования символа: в строку? Я думаю, что может быть оператор, о котором я не знаю.
Ответы
Ответ 1
По просьбе эколога, вот мой комментарий в качестве ответа:
ecoologic имеет хорошее решение для вас, но я бы рекомендовал отменить это и создать класс с константами в нем. То, что вы можете делать такие вещи, как e.status = Statuses:: CANCELED. И внутренне это может быть строка, и это не имеет значения. Вы по-прежнему используете константы, и он будет выходить из строя, если эта константа не существует, и она чище.
Ответ 2
С 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 }
Ответ 3
Это вроде поздно, но может помочь кому-то другому.
Если у вас есть классы с разными статусами, вы можете рассмотреть подход, использующий константы вместе с областями, например:
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])
Надеюсь, это поможет кому-то еще!
EDIT:
Если вы больше используете драгоценные камни, simple_enum драгоценный камень выглядит превосходной альтернативой.
Ответ 4
Если я помню, что символы хорошего качества в ActiveRecord хранятся в формате yaml, должно быть сделано какое-то преобразование, потому что в реляционной db (как мне известно, по крайней мере) нет такой вещи, как символ. Когда вы его читаете, это строка, которая не будет соответствовать вашему символу и даже строке символа, на самом деле это должно быть примерно так:
: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 для добавления более сложной логики.
Ответ 5
Начиная с Rails 4.1, Active Record теперь поддерживает перечисления
Из примечания к выпуску:
2.5 Активные записи записи
Объявить атрибут enum, где значения соответствуют целым числам в
базы данных, но может быть запрошено по имени.
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
Ответ 6
Также вы можете перезаписать метод reader
:
def status
read_attribute(:status).to_sym
end
Ответ 7
Из программирования Ruby 1.9 относительно оператора == в классе Symbol (стр. 729):
Returns true only if sym and obj are symbols with the same object_id.
Все, что вы сохранили в БД, всегда будет иметь другой object_id, чем фиксированный object_id символа (в этом случае указатель на строковый литерал).