Это - больше вопроса о стиле, я задаюсь вопросом, что делают другие люди.
Скажем, у меня есть поле в моей базе данных, названной "состоянием" для сообщения в блоге. И я хочу, чтобы это имело несколько возможных значений, как "проект", "ожидая обзора", и "отправленный", так же, как пример.
Очевидно, мы не хотим к "твердому коду" в этих, волшебство оценивает каждый раз, который не был бы DRY.
Таким образом, то, что я иногда делаю, является чем-то вроде этого:
class Post
STATUS = {
:draft => "draft",
:awaiting_review => "awaiting review",
:posted => "posted"
}
...
end
Затем я могу написать код, относящийся к нему позже как STATUS[:draft]
или Post::STATUS[:draft]
и т.д.
Это работает хорошо, но существует несколько вещей, мне не нравится приблизительно он.
STATUS[:something_that_does_not_exist]
это не бросит ошибку, это просто возвращает ноль и может закончить тем, что установило это в базе данных, и т.д. прежде чем Вы когда-либо будете замечать ошибкуif some_var == Post::STATUS[:draft]
...Я не знаю, что-то мне подсказывает, что существует лучший путь, но просто требуемый для наблюдения то, что делают другие люди.Спасибо!
Это распространенная проблема. Подумайте что-то вроде этого:
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
Вы можете использовать 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
Вы можете использовать метод класса для повышения исключения на отсутствующий ключ:
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
потенциально, вы также можете использовать этот метод для хранения статусов как целых чисел в базе данных, изменив свои строки в базу данных целые числа (в хэш), преобразуя типы столбцов и добавление добыта и установки.
Взгляните на ATTRETUTE_MAPPER GEM.
Есть Статья , которая показывает, как вы можете справиться с этой проблемой, как это (заимствовано из статьи):
class Post < ActiveRecord::Base
include AttributeMapper
map_attribute :status, :to => {
:draft => 1,
:reviewed => 2,
:published => 3
}
end
... что выглядит довольно стильно.
Я делаю так:
class Post
DRAFT = "draft"
AWAITING_REPLY = "awaiting reply"
POSTED = "posted"
STATUSES = [DRAFT, AWAITING_REPLY, POSTED]
validates_inclusion_of :status, :in => STATUSES
...
end
Таким образом, вы получаете ошибки, если неправильно написали одну из них. Если у меня несколько наборов констант, я могу сделать что-то вроде DRAFT_STATUS, чтобы отличить.