Как обрабатывать значения перечисления в рельсах 4

Итак, у меня есть таблица subscription в моей базе данных.

Я хотел бы иметь столбец state, который будет иметь одно из следующих значений

Valid
Invalid
Cancelled
In Trial
Non Renewing
Future

Может кто-нибудь объяснить, как использовать эти значения в качестве значений enum в rails 4?

Ответы

Ответ 1

Кредит: https://hackhands.com/ruby-on-enums-queries-and-rails-4-1/

Объявить атрибут enum, где значения отображаются в целые числа в базе данных, но могут быть запрошены по имени. Пример:

class Conversation < ActiveRecord::Base
  enum status: [ :active, :archived ]
end

# conversation.update! status: 0
conversation.active!
conversation.active? # => true
conversation.status  # => "active"

# conversation.update! status: 1
conversation.archived!
conversation.archived? # => true
conversation.status    # => "archived"

# conversation.update! status: 1
conversation.status = "archived"

# conversation.update! status: nil
conversation.status = nil
conversation.status.nil? # => true
conversation.status      # => nil

Также будут предоставлены области, основанные на разрешенных значениях поля перечисления. В приведенном выше примере он создаст активную и архивированную область.

Вы можете установить значение по умолчанию из объявления базы данных, например:

create_table :conversations do |t|
  t.column :status, :integer, default: 0
end

Хорошей практикой является разрешение первого объявленного статуса по умолчанию.

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

class Conversation < ActiveRecord::Base
  enum status: { active: 0, archived: 1 }
end

Обратите внимание, что при использовании массива неявное сопоставление значений с целыми числами базы данных происходит из порядка, в котором значения отображаются в массиве. В примере: active сопоставляется с 0 как это первый элемент, а: заархивирован для отображения 1. В общем, i-й элемент сопоставляется с i-1 в базе данных.

Поэтому, как только значение добавляется в массив перечислений, его положение в массиве должно поддерживаться, а новые значения должны быть добавлены только в конец массива. Чтобы удалить неиспользуемые значения, следует использовать явный синтаксис Hash.

В редких случаях вам может потребоваться непосредственный доступ к сопоставлению. Отображения отображаются через метод класса с именем множественного атрибута:

Conversation.statuses # => { "active" => 0, "archived" => 1 }

Используйте этот метод класса, когда вам нужно знать порядковое значение перечисления:

Conversation.where("status <> ?", Conversation.statuses[:archived])

Если условия атрибута enum должны использовать порядковое значение перечисления.

Дополнительная информация: http://api.rubyonrails.org/v4.1.0/classes/ActiveRecord/Enum.html

Ответ 2

Вы можете использовать драгоценный камень, называемый Workflow. Он позволяет использовать пользовательские статусы и грациозно обрабатывать переходы между состояниями. Я использовал его во многих приложениях Rails3 и Rails 4.

Пример из документации.

class Article
  include Workflow
  workflow do
    state :new do
      event :submit, :transitions_to => :awaiting_review
    end
    state :awaiting_review do
      event :review, :transitions_to => :being_reviewed
    end
    state :being_reviewed do
      event :accept, :transitions_to => :accepted
      event :reject, :transitions_to => :rejected
    end
    state :accepted
    state :rejected
  end
end

И позже:

article = Article.new
article.accepted? # => false
article.new? # => true

Ответ 3

Изменить: Мой ответ здесь не использует ActiveRecord magic enums. Что я предлагаю ниже, работает для любой библиотеки БД (например, Sequel), и мне кажется, что она немного более надежна. Например, он не полагается на автоматическое упорядочение значений и использует ограничения внешнего ключа в СУБД, чтобы убедиться, что ваше значение действительно (в отличие от решения ActiveRecord). Однако это не идиоматическая методология Rails. См. Ответ Гири (копия/вставка страницы документации) для идиоматического ответа.


  • Создайте таблицу states в своей базе данных с этими строковыми значениями, заполненными вместе с уникальным идентификатором, например

    states
    id | name 
    ---+--------------
     1 | Valid
     2 | Invalid
     3 | Cancelled
     4 | In Trial
     5 | Non Renewing
     6 | Future
    
  • Используйте стандартную ассоциацию внешних ключей в таблице subscription, ссылаясь на запись из states.

  • В ваших моделях создайте класс State с константами, соответствующими идентификаторам, например:

    class State < ActiveRecord::Base
      VALID   = 1
      INVALID = 2
      # etc.
    end
    

Теперь вы: a) гарантируете, что ваши данные в таблице действительны, и b) вы можете использовать удобные ссылки, такие как запрос subscriptions

Subscription.where( state_id: State::VALID )