Подтвердить что ты не робот

Как хранить и сравнивать: символы в 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

Есть ли лучший способ сохранить статус в записи? Есть ли способ тестирования, если текущее значение поля равно символу: без преобразования символа: в строку? Я думаю, что может быть оператор, о котором я не знаю.

4b9b3361

Ответ 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 символа (в этом случае указатель на строковый литерал).