Как хранить и сравнивать: символы в ActiveRecord (Ruby on Rails) - PullRequest
25 голосов
/ 27 января 2012

Я подумал, что было бы хорошо заполнить поле статуса в таблице 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

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

Ответы [ 7 ]

13 голосов
/ 04 мая 2014

В 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 }
9 голосов
/ 22 января 2013

Это немного поздно, но может помочь кому-то еще.

Если у вас есть классы с разными статусами, вы можете рассмотреть подход с использованием констант наряду с такими областями:

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])

Надеюсь, это поможет кому-то еще!

РЕДАКТИРОВАТЬ: Если вы больше в использовании драгоценных камней, simple_enum камень выглядит как отличная альтернатива.

7 голосов
/ 08 января 2015

Начиная с Rails 4.1, Active Record теперь поддерживает перечисления

Из примечаний к выпуску :

2.5 Перечисления Active Record

Объявите атрибут 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

7 голосов
/ 28 января 2012

По запросу ecoologic, вот мой комментарий в качестве ответа:

У ecoologic есть хорошее решение для вас, но я бы рекомендовал отойти от этого и сделать урок с постоянными. Что вы можете делать такие вещи, как e.status = Statuses :: CANCELED. А внутри это может быть строка, и это не имеет значения. Вы по-прежнему используете константы, и если эта константа не существует, произойдет ошибка, и она станет чище.

7 голосов
/ 27 января 2012

Если я хорошо помню, что символы в 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

Это, конечно, заставит значение всегда быть символом

** РЕДАКТИРОВАТЬ ПОСЛЕ ВОЗРАСТА ** Я думаю, что в этой ситуации хорошо, так как ясно, что в БД это строка и логика проста, но я настоятельно не рекомендую переопределять методы атрибута БД, чтобы добавить более сложную логику.

6 голосов
/ 27 марта 2012

Также вы можете перезаписать метод reader:

def status
  read_attribute(:status).to_sym
end
1 голос
/ 27 января 2012

С Программирование Ruby 1.9 относительно оператора == в классе Symbol (стр. 729):

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

Все, что вы сохранили в БД, всегда будет иметь object_id, отличный от фиксированного object_id символа (в данном случае указатель на строковый литерал).

...