Rails: Перечисления с хешами, не возвращающими ha sh ключ: значение - PullRequest
0 голосов
/ 31 марта 2020

Я создаю Ruby на Rails Application, где у меня есть атрибуты модели, которые являются stati c, такими как Gender и Status. Я решил определить их как enums в моделях. Я использую гем ruby -enum для определения перечислений.

Я добавил гем ruby -enum в свой проект и запустил bundle install:

gem 'ruby-enum', '~> 0.8.0'

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

# app/models/concerns/status.rb

module Status
  extend ActiveSupport::Concern
  included do
    include Ruby::Enum

    define :ordered, 'Ordered'
    define :cancelled, 'Cancelled'
    define :waiting, 'Waiting'
  end
end

Я включил этот модуль в мою Users модель

class User < ApplicationRecord
  include Status
end

И моя модель Users имеет столбец для status:

create_table "users", force: :cascade do |t|
  t.string "first_name"
  t.string "last_name"
  t.string "status"
  t.datetime "created_at", precision: 6, null: false
  t.datetime "updated_at", precision: 6, null: false
end

Но когда я запрашиваю модуль Status в rails console:

Status.all

, я получаю сообщение об ошибке:

NoMethodError (undefined method `all' for Status:Module)

Когда я также запрашиваю модель User в консоли рельсов для всех statuses:

User.statuses.all

Я получаю ошибку:

ArgumentError (wrong number of arguments (given 2, expected 0..1))

Я также не знаю, как сделать это доступным в представлениях

  # app/views/users/_form.html.erb

  <%= form.label :status %><br />
  <%= form.select :status, User.statuses.keys.collect { |status| status },{} %>  

Буду признателен за некоторую помощь в правильном направлении о том, как go определить определения перечислений, а также вернуть значения ключей перечислений в представлении формы пользователя, чтобы можно было выбрать статус в форма. Спасибо.

1 Ответ

2 голосов
/ 31 марта 2020

Но когда я запрашиваю модуль Status в консоли rails:

Status.all

я получаю сообщение об ошибке:

NoMethodError (undefined method `all' for Status:Module)

.all запрашивает все записи класса ActiveRecord. Status не является классом ActiveRecord. Это даже не класс, это модуль.

Что касается User.statuses.all, я не вижу, где определяется statuses.


Ruby::Enum имеет добавил некоторые константы и методы, но Rails не знает о них. Вам придется интегрировать их в Rails самостоятельно.

В Rails уже есть интегрированные перечисления .

module Status
  extend ActiveSupport::Concern
  included do
    # It will take an Array, but it's good practice to be explicit.
    enum status: {ordered: 0, cancelled: 1, waiting: 2}
  end
end

User.statuses вернет HashWithIndifferentAccess ваших статусов.

Обратите внимание, что эти перечисления сопоставлены с целыми числами, строки побеждают точку перечисления. Сохранение вашего статуса в виде целого числа сэкономит вам потенциально много места. Rails будет обрабатывать отображение целых чисел в строки и обратно для вас.

Обязательно измените вашу таблицу, чтобы использовать целочисленный статус: t.string "status". Чтобы пользователи не имели статус «включено», вам нужно задать либо значение по умолчанию, либо null: false.


Я хочу видеть Порядок, а не порядок на странице просмотров. Я хочу видеть Не заказано и не не упорядочено на странице просмотров. Я также хочу, чтобы значения статуса сохранялись в базе данных, а не целые числа, такие как 0, 1, 2. - Promise Preston 12 сек. go

Подробно о том, как отображаются данные, не принадлежат в базе данных. Самое простое - это использовать humanize.

# ordered becomes Ordered. not_waiting becomes Not waiting.
User.statuses.keys.collect { |status| status.humanize }

Вы можете добавить sh в модуль Status.

module Status
  ...

  class_methods do
    def show_statuses
      statuses.keys.collect { |status| status.humanize }
    end
  end
end

User.show_statuses

Делать это как выберите ...

<%= f.select :status, User.statuses.collect { |status,id| [status.humanize,id] } %>

И вы также можете добавить sh в Status.

module Status
  ...

  class_methods do
    ...

    def statuses_for_select
      statuses.collect { |status,id| [status.humanize,id] }
    end
  end
end

<%= f.select :status, User.statuses_for_select %>

По мере усложнения деталей отображения ваши модели будут становиться толстыми. Тогда вам захочется добавить его в декоратор .

...