ActiveRecord::Enum инициализирован хэшем или массивом?

Допустим, у нас есть эта простая модель:

class Project < ApplicationRecord
  enum stage: {Idea: "idea", Done: "done", "On hold": "on hold", Cancelled: "cancelled"}
  enum status: [:draft, :published, :archived]
end

Когда мы обращаемся к перечислениям из модели (Project.stages, Project.statuses), мы получаем в результате обработанный (ActiveRecord::Enum) ответ, оба в виде хеша.

irb(main):001:0> Project.stages
=> {"Idea"=>"idea", "Done"=>"done", "On hold"=>"on hold", "Cancelled"=>"cancelled"}
irb(main):002:0> Project.statuses
=> {"draft"=>0, "published"=>1, "archived"=>2}

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

Любая идея о том, как получить начальный хеш или массив из перечисления?

Зачем вам это знать? Какую проблему вы пытаетесь решить, определяя, как было определено перечисление? Хотели бы вы относиться к enum status: %i[draft published archived] и enum status: { draft: 0, published: 1, archived: 2 } по-разному?

mu is too short 19.11.2022 19:33

@muistooshort да, я работаю над функцией для Avo (avohq.io), где мне нужно относиться к ним немного по-другому

Droopy 19.11.2022 21:06

Если мы не можем понять это, нам нужно попросить разработчика указать тип перечисления, и мы пытаемся избежать этого.

Droopy 19.11.2022 21:07

Я не думаю, что вы можете, источник просто проверяет, как он может перебирать значения (each_pair, если это хеш, each_with_index в противном случае).

mu is too short 19.11.2022 23:01

Интересно, сможем ли мы каким-то образом получить этот values аргумент, который получает источник

Droopy 20.11.2022 00:12

Может быть, вам на самом деле нужно просто использовать Project.type_for_attribute('stages') для получения типа базового столбца базы данных?

max 20.11.2022 08:14

С другой стороны, enum stage: {Idea: "idea", Done: "done", "On hold": "on hold", Cancelled: "cancelled"} также очень однозначен, так как использование клавиш в верхнем регистре приведет к методам с именами в верхнем регистре, такими как Idea, Idea? и Idea!. Если вы вызовете Idea с неявным получателем (без себя), Ruby будет думать, что это константа. Не делай этого. Ваши ключи перечисления должны быть строчными и змеиными.

max 20.11.2022 08:43

Спасибо за ответы и за советы @max, я полностью с вами согласен. Как я упоминал в комментариях выше, этот вопрос возник, когда я разрабатывал для Avo. Мы стремимся к тому, чтобы Avo работал для каждого разработчика, даже если хостинг-приложение хорошо или плохо использует перечисления. В любом случае, Project.type_for_attribute('stage') дает ответ, который мы искали!!

Droopy 20.11.2022 14:14
Как настроить Tailwind CSS с React.js и Next.js?
Как настроить Tailwind CSS с React.js и Next.js?
Tailwind CSS - единственный фреймворк, который, как я убедился, масштабируется в больших командах. Он легко настраивается, адаптируется к любому...
LeetCode запись решения 2536. Увеличение подматриц на единицу
LeetCode запись решения 2536. Увеличение подматриц на единицу
Увеличение подматриц на единицу - LeetCode
Переключение светлых/темных тем
Переключение светлых/темных тем
В Microsoft Training - Guided Project - Build a simple website with web pages, CSS files and JavaScript files, мы объясняем, как CSS можно...
Отношения &quot;многие ко многим&quot; в Laravel с методами присоединения и отсоединения
Отношения &quot;многие ко многим&quot; в Laravel с методами присоединения и отсоединения
Отношения "многие ко многим" в Laravel могут быть немного сложными, но с помощью Eloquent ORM и его моделей мы можем сделать это с легкостью. В этой...
В PHP
В PHP
В большой кодовой базе с множеством различных компонентов классы, функции и константы могут иметь одинаковые имена. Это может привести к путанице и...
Карта дорог Беладжар PHP Laravel
Карта дорог Беладжар PHP Laravel
Laravel - это PHP-фреймворк, разработанный для облегчения разработки веб-приложений. Laravel предоставляет различные функции, упрощающие разработку...
1
8
65
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы не должны относиться к ним по-разному из-за принципа наименьшего удивления.

Enum status: [:draft, :published, :archived] — это просто неявное сокращение для определения перечисления, где отображение совпадает с индексами массива. Вот как это задокументировано, и когда ваш код делает что-то еще, открывается настоящий момент WTF.

Неявное определение перечислений также считается плохой практикой, поскольку добавление новых статусов в середину массива очень незаметно нарушит работу вашего приложения. Существует даже полицейский Rubocop, который обнаруживает использование массивов с помощью регулярного выражения в исходном коде.

На самом деле это просто небрежный способ написания enum status: { draft: 0, published: 1, archived: 2}. Вы не должны поощрять его использование.

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

Если вы ДЕЙСТВИТЕЛЬНО хотели это сделать, вы могли бы обезвредить метод перечисления:

module WonkyEnum
  # this is silly. Don't do this
  def enum(definitions)
    @_enum_definitions ||= []
    @_enum_definitions.push(definitions)
    super(definitions)
  end
end

Но какой бы ни была реальная проблема, скорее всего, есть лучшее решение.

Спасибо за подробное объяснение @max! Мы создаем поле выбора, в котором разработчик может использовать перечисление в качестве параметров. Мы не хотим использовать их по-другому, но после некоторой отладки мы обнаружили, что если мы хотим, чтобы выбор работал идеально, нам нужно предварительно обработать параметры по-разному, когда перечисление имеет простой массив или объявление хэша. PS: После некоторого расследования я заметил, что мы не использовали options_for_select() в нашем теге выбора, что исправило некоторые из наших проблем!

Droopy 20.11.2022 16:53

Другие вопросы по теме