2010-01-21 10 views
6

Bu daha fazla stil sorusu, başkalarının ne yaptığını merak ediyorum.Ruby Style Soru: farklı olası değerlerle karma sabitini saklamak

Veritabanımda blog yazısı için "durum" adı verilen bir alanım olduğunu varsayalım. Ve bir örnek olarak, "taslak", "inceleme bekleniyor" ve "yayınlanmış" gibi çeşitli olası değerlere sahip olmasını istiyorum.

Açıkçası, her seferinde bu sihirli değerlerde "sabit kod" yapmak istemiyoruz, bu DRY olmayacaktır.

Yani ne bazen yapmak böyle bir şeydir:

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

    ... 

end 

Sonra kod vb STATUS[:draft] veya Post::STATUS[:draft]

Bu, Tamam çalışan olarak daha sonra atıfta yazabilir ancak birkaç şey vardır Bundan hoşlanmıyorum.

  1. bunu bir hata atmaz bir yazım hatası ve STATUS[:something_that_does_not_exist] gibi bir şey ararsanız, sadece nil döndürür ve Hiç bir gýcýk fark etmeden vb veritabanında, bu ayarı sona erebilir
  2. It bilmiyorum

... temiz veya yakut-imsi if some_var == Post::STATUS[:draft] böyle şeyler yazmaya, bir şey daha iyi bir yoldur, ama sadece diğer insanların ne yaptığını görmek istedim söylüyor görünmüyor. Teşekkürler!

cevap

6

Bu yaygın bir sorundur. Böyle bir şey düşünün:

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 

Bu da kolaylaştırmak için symbolize denilen bir üçüncü taraf ActiveRecord eklentisi kullanabilirsiniz: Böyle yapmak

class Post < ActiveRecord::Base 
    symbolize :status 
end 
+0

Güzel John, teşekkürler! –

2

Sen Eksik anahtar üzerinde bir istisna yükseltmek için bir sınıf yöntemi kullanabilirsiniz:

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 

Potansiyel, ayrıca (tamsayılar için Dizelerinizi değiştirerek veritabanında tamsayı olarak durumlarını saklamak için bu yöntemi kullanabilirsiniz karma), sütun türlerini dönüştürmek ve bir alıcı ve ayarlayıcı eklemek.

1

:

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

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

Bu Birini yanlış yazarsın. Birden fazla sabit setim varsa, ayırt etmek için DRAFT_STATUS gibi bir şey yapabilirim.

+0

Bunu beğendim, ancak daha sonra "STATUSES [0]" olarak adlandırmak zorundasınız? Bu durumda oldukça okunabilir değil. –

8

Hash.new'yi kullanabilir ve bir anahtarın bilinmemesi durumunda çağrılan bir blok argümanı verebilirsiniz.

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

Biraz dağınık ama işe yarıyor.

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 
+0

İlginç, yayınladığınız için teşekkürler! –

+0

Bu yöntemi beğendim. Harici bağımlılıklar yok. –

1

attribute_mapper gemine bir göz atın.

bu (makalesinden ödünç) gibi, bildirimli sorunu işleyebilir nasıl gösteren bir related article var:

class Post < ActiveRecord::Base 
    include AttributeMapper 

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

... oldukça şık görünüyor ki.

+0

Çok havalı. Durum [: taslak] vs bir şey_else [: taslak] gibi birden fazla özniteliğiniz olması durumunda onları gruplandırmamak çok kötü, ancak genel olarak gördüğüm en iyi çözüm bu olabilir –

0

Bu eski bir yazı olsa da, birileri bu tökezletici için, size verilen anahtar bulunmazsa (varsayılan geçirilir) bir hata yükseltir Hash üzerinde fetch yöntemini kullanabilirsiniz.

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

STATUS.fetch(:draft) #=> "draft" 
STATUS.fetch(:invalid_key) #=> KeyError: key not found: invalid_key 
İlgili konular