Вопрос о Стиле Ruby: хранение хеша, постоянного с различными возможными значениями

Это - больше вопроса о стиле, я задаюсь вопросом, что делают другие люди.

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

Очевидно, мы не хотим к "твердому коду" в этих, волшебство оценивает каждый раз, который не был бы DRY.

Таким образом, то, что я иногда делаю, является чем-то вроде этого:

class Post
  STATUS = {
    :draft => "draft",
    :awaiting_review => "awaiting review",
    :posted => "posted"
  }

  ...

end

Затем я могу написать код, относящийся к нему позже как STATUS[:draft] или Post::STATUS[:draft] и т.д.

Это работает хорошо, но существует несколько вещей, мне не нравится приблизительно он.

  1. Если Вы имеете опечатку и называете что-то как STATUS[:something_that_does_not_exist] это не бросит ошибку, это просто возвращает ноль и может закончить тем, что установило это в базе данных, и т.д. прежде чем Вы когда-либо будете замечать ошибку
  2. Это не выглядит чистым или рубиновый выход для записи материала как if some_var == Post::STATUS[:draft] ...

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

6
задан Brian Armstrong 21 January 2010 в 04:37
поделиться

5 ответов

Это распространенная проблема. Подумайте что-то вроде этого:

class Post < ActiveRecord::Base
  validates_inclusion_of :status, :in => [:draft, :awaiting_review, :posted]
  def status
    read_attribute(:status).to_sym
  end
  def status= (value)
    write_attribute(:status, value.to_s)
  end
end

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

class Post < ActiveRecord::Base
  symbolize :status
end
6
ответ дан 8 December 2019 в 12:59
поделиться

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

class Post
  STATUS = Hash.new{ |hash, key| raise( "Key #{ key } is unknown" )}.update(
    :draft => "draft",
    :awaiting_review => "awaiting review",
   :posted => "posted" )
end

Это немного грязно, но это работает.

irb(main):007:0> Post::STATUS[ :draft ]
=> "draft"
irb(main):008:0> Post::STATUS[ :bogus ]
RuntimeError: Key bogus is unknown
    from (irb):2
    from (irb):8:in `call'
    from (irb):8:in `default'
    from (irb):8:in `[]'
    from (irb):8
8
ответ дан 8 December 2019 в 12:59
поделиться

Вы можете использовать метод класса для повышения исключения на отсутствующий ключ:

class Post
  def self.status(key)
    statuses = {
      :draft => "draft",
      :awaiting_review => "awaiting review",
      :posted => "posted"
    }
    raise StatusError unless statuses.has_key?(key)
    statuses[key]
  end
end

class StatusError < StandardError; end

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

2
ответ дан 8 December 2019 в 12:59
поделиться

Взгляните на ATTRETUTE_MAPPER GEM.

Есть Статья , которая показывает, как вы можете справиться с этой проблемой, как это (заимствовано из статьи):

class Post < ActiveRecord::Base
  include AttributeMapper

  map_attribute :status, :to => {
    :draft => 1,
    :reviewed => 2,
    :published => 3
  }
end

... что выглядит довольно стильно.

1
ответ дан 8 December 2019 в 12:59
поделиться

Я делаю так:

class Post
  DRAFT = "draft"
  AWAITING_REPLY = "awaiting reply"
  POSTED = "posted"
  STATUSES = [DRAFT, AWAITING_REPLY, POSTED]

  validates_inclusion_of :status, :in => STATUSES
  ...
end

Таким образом, вы получаете ошибки, если неправильно написали одну из них. Если у меня несколько наборов констант, я могу сделать что-то вроде DRAFT_STATUS, чтобы отличить.

1
ответ дан 8 December 2019 в 12:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: