Правильное хранение «перечислимых» моделей в Rails - PullRequest
18 голосов
/ 16 ноября 2010

Извиняюсь, если вопрос немного неточный, но я опишу мою проблему ниже.

Я устанавливаю некоторые модели в проекте Rails, и одна вещь, которую я заметил, запущенав более чем несколько раз имеет дело с атрибутами, которые соответствуют следующим критериям:

  • Они могут быть установлены на одно из небольшого, предварительно определенного набора значений
  • Эти значения должны иметьи имя, и идентификатор (будь то числовой идентификатор, код и т. д.)
  • Значения будут меняться только в результате значительного изменения кода.

Например,одна из моих моделей должна иметь поле status, которое может быть установлено в одно из: Определение, Выполнено или Завершено.Мне нужно показать эти конкретные слова в интерфейсе, но я не хочу хранить строки в БД на случай, если мне потребуется изменить их в будущем (или интернационализировать, или что-то в этом роде).

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

Другой вариант - сохранить его как целое число и создать класс типа «перечисление», в котором хранится перевод этих значений - это, вероятно, будет работать нормально, но я обеспокоен тем, что потеряюассоциации и другие полезные вещи, которые я получаю от моделей ActiveRecord.

Какой совет, как лучше справиться с этой ситуацией?

Ответы [ 7 ]

13 голосов
/ 16 ноября 2010

Посмотрите на рубиновый камень, над которым я работал, и который называется classy_enum .Я уверен, что это именно то, что вы ищете.README имеет несколько примеров использования, но предпосылка заключается в том, что он позволяет вам определять несколько членов enum как классы, которые могут иметь разные свойства.

12 голосов
/ 16 ноября 2010

Определите varchar или ENUM в базе данных и проверьте поле в модели:

validates_inclusion_of :status, :in => %w(Defining Executed Completed)

Rails будет обрабатывать его как строковое поле, но все равно проверяет, какие значения.

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

class Foo < ActiveRecord::Base
  STATUS_DESCRIPTIONS = %w(Defining Executed Completed)

  def status
    STATUS_DESCRIPTIONS[ read_attribute(:status) ]
  end
end

Если что-то сложнее, попробуйте самоцвет @ Beerlington.

2 голосов
/ 14 января 2013

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

Если в ваших штатах содержится много специфических знаний о штатах, то идея автомата, предложенная Скани, может быть хорошей идеей. Другой вариант - использовать старый добрый шаблон состояния с гемом state_pattern .

1 голос
/ 16 ноября 2010

Как насчет того, чтобы поместить его в модуль и смешать в модели:

module StatusCodes
  DEFINING = 1
  EXECUTING = 2
  COMPLETED = 3

  def status
    return "" unless self[:status] # handle nil
    const_lookup = self[:status] - 1 # index to module constants
    StatusCodes.constants[const_lookup].to_s.downcase.camelcase # note: needs Ruby 1.9
  end
end

class MyModel < ActiveRecord::Base
  include StatusCodes
end

Теперь добавьте к модели столбец целых чисел status, и вы можете назначить так:

m = MyModel.new(:status=>StatusCodes::DEFINING)

и получить строку:

m.status # "Defining"
1 голос
/ 16 ноября 2010

звучит так, как если бы вы могли использовать state_machine, смотрите здесь: https://github.com/pluginaweek/state_machine

0 голосов
/ 23 ноября 2015

Для полноты картины Rails имеет класс Enum с 4.1.

0 голосов
/ 16 ноября 2010

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

http://github.com/jasondew/coded_options

(раньше работал с Джейсоном, и мы использовали его предшественника в нескольких приложениях rails, особенно если пользователь когда-либо выбирал опцию из тега select)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...