2012-01-27 17 views
22

Pomyślałem, że dobrze byłoby wypełnić pole statusu w tabeli activeRecord za pomocą stałych. Jeśli jednak chodzi o sprawdzenie, czy ten status ma określony status, mam problem.Jak przechowywać i porównywać: symbole w ActiveRecord (Ruby on Rails)

Gdybym wykonać następujące czynności,

e = Mytable.new 
e.status = :cancelled 
e.save 

następnie refind rekord i spróbować porównać swój status symbolu, sprawdzenie się nie powiedzie. Mam trochę wyjścia z konsoli, żeby to pokazać.

irb(main):060:0> e.status.eql?("cancelled") 
=> true 
irb(main):061:0> e.status.eql?(:cancelled) 
=> false 
irb(main):062:0> e.status == :cancelled 
=> false 
irb(main):063:0> e.status == "cancelled" 
=> true 
irb(main):064:0> e.status == :cancelled.to_s 
=> true 

Czy jest lepszy sposób na zachowanie statusu w rejestrze? Czy istnieje sposób sprawdzenia, czy aktualna wartość pola jest równa: symbol bez konwersji symbolu: na ciąg znaków? Myślę, że może istnieć operator, którego nie znam.

+1

ecoologic ma dobre rozwiązanie dla Ciebie, ale polecam może kierownicy z dala od tego i być może czyni klasę ze stałymi w nim. Że możesz robić rzeczy takie jak 'e.status = Statusy :: ANULOWANE' i co nie. Wewnętrznie może to być ciąg znaków i nie ma to znaczenia. Wciąż używasz stałych, a błąd będzie się pojawiał, jeśli ta stała nie istnieje i jest czystsza w ten sposób. – MrDanA

+0

dlaczego nie zastąpisz gettera swojej kolumny? – apneadiving

+0

Poprawiłem odpowiedź przed przeczytaniem tych dwóch komentarzy, ale chciałbym powiedzieć, że kocham rozwiązanie @MrDanA, powinieneś napisać odpowiedź i zagłosuję! – ecoologic

Odpowiedz

7

Na wniosek ecoologic, tu jest mój komentarz jako odpowiedź:

ecoologic ma dobre rozwiązanie dla Ciebie, ale polecam układu kierowniczego z dala od tego i dokonywania klasę stałych w nim. Że możesz robić rzeczy takie jak e.status = Statusy :: ANULOWANE. Wewnętrznie może to być ciąg znaków i nie ma to znaczenia. Wciąż używasz stałych, a błąd będzie się pojawiał, jeśli ta stała nie istnieje i jest czystsza w ten sposób.

+0

Co do najlepszej praktyki, gdzie byś postawił tę klasę? W swoim własnym pliku w lib lub pomocników? – seanyboy

+0

Umieściłem klasę statusu w pliku modelu. Działa dobrze. Dodałem również self.method do klasy, aby przekonwertować status na kolor. Tak więc zachowuje to wszystko w jednym miejscu. – seanyboy

+1

Zwykle umieszczam je w ich własnym pliku w lib, tak. Następnie możesz automatycznie ładować pliki (zamiast "wymagać" ich), edytując plik konfiguracyjny aplikacji. – MrDanA

7

Jeśli dobrze pamiętam symbole w ActiveRecord są przechowywane w formacie yaml, należy dokonać jakiejś konwersji, ponieważ nie ma czegoś takiego jak symbol w relacyjnym db (co przynajmniej jestem świadomym). Gdy go przeczytasz to wtedy łańcuch, który nie będzie pasował swój symbol i nawet nie ciąg symboli, w rzeczywistości powinno być coś takiego:

:x # => "--- :x\n" 

myślę, że ten plugin może rozwiązać problem, ale haven użyłem tego szczerze. https://github.com/zargony/activerecord_symbolize

* EDIT *

zostawiam wyżej bo pamiętam, że była sytuacja ja miałem i może być skorygowana, jeśli się mylę, to jednak próbuję to teraz i przechowywane value (Rails 3.1.3) to prosty ciąg znaków z wartością symbolu, więc poniższe elementy powinny wystarczyć.

class Example < ActiveRecord::Base 

    def aaa 
    super.to_sym 
    end 

    def aaa=(value) 
    super(value.to_sym) 
    aaa 
    end 

end 

To oczywiście wymusić wartość, aby zawsze być symbolem

** EDIT PO WIEKU ** myślę, że to dobrze w tej sytuacji jest oczywiste, że w db jest to ciąg znaków i logika jest prosta, ale zdecydowanie odradzam nadpisywanie metod atrybutu db, aby dodać bardziej złożoną logikę.

+1

należy również pamiętać, że użycie: to_sym na danych wejściowych użytkownika jest złym pomysłem: http://www.tricksonrails.com/2010/06/avoid-memory-leaks-in-ruby-rails-code-and-protect-against -denial-of-service/ – oseiskar

+0

yeap, warto wspomnieć, to jest zła praktyka – ecoologic

1

Od programowania Ruby 1.9, odnośnie operatora == w klasie Symbol (str 729).:

Returns true only if sym and obj are symbols with the same object_id. 

Cokolwiek przechowywane w DB zawsze będą miały inną object_id niż ustalone object_id z symbol (w tym przypadku wskaźnik do literału literowego).

5

Ponadto można nadpisać metodę reader:

def status 
    read_attribute(:status).to_sym 
end 
8

To jest trochę późno, ale może pomóc komuś innemu.

Jeśli masz zajęcia z różnych stanów, można rozważyć podejście przy użyciu stałych wraz z zakresów takich jak ten:

class Account < ActiveRecord::Base 
    #------------------------------------------------------------------------------- 
    # Configuration 
    #------------------------------------------------------------------------------- 

    # STATUS is used to denote what state the account is in. 
    STATUS = { :active => 1, :suspended => 2, :closed => 3 } 

    # Scopes 
    scope :active, where(:status => Account::STATUS[:active]) 
    scope :suspended, where(:status => Account::STATUS[:suspended]) 
    scope :closed, where(:status => Account::STATUS[:closed]) 
    ... 
end 

Następnie można łatwo znaleźć rekordy na podstawie statusu, tak jak poniżej:

# get all active accounts 
active_accounts = Consumer.active.all 
# get 50 suspended accounts 
suspended_accounts = Consumer.suspended.limit(50) 
# get accounts that are closed and [some search criteria] 
closed_accounts = Consumer.closed.where([some search criteria]) 

Mam nadzieję, że to pomoże komuś innemu!

EDYCJA: Jeśli bardziej interesuje Cię klejnot, klejnot simple_enum wygląda na doskonałą alternatywę.

12

W przypadku Rails 4.1.0 prawdopodobnie użyłbyś wyliczeń aktywnej rejestracji.

zacytować official release notes:

class Conversation < ActiveRecord::Base 
  enum status: [ :active, :archived ] 
end 
  
conversation.archived! 
conversation.active? # => false 
conversation.status  # => "archived" 
  
Conversation.archived # => Relation for all archived Conversations 
  
Conversation.statuses # => { "active" => 0, "archived" => 1 } 
6

Jak Rails 4.1, Active Record obsługuje teksty stałe

Z release notes:

2,5 Aktywnych teksty stałe Record

zadeklarować enum atrybut, gdzie wartości są mapowane na liczby całkowite w bazy danych, ale można zapytać o nazwę.

class Conversation < ActiveRecord::Base 
    enum status: [ :active, :archived ] 
end 

conversation.archived! 
conversation.active? # => false 
conversation.status # => "archived" 

Conversation.archived # => Relation for all archived Conversations 

Conversation.statuses # => { "active" => 0, "archived" => 1 } 

Dodatkowa dokumentacja tutaj: http://api.rubyonrails.org/v4.1.0/classes/ActiveRecord/Enum.html