Pytanie Jak radzić sobie z wartościami wyliczonymi w szynach 4


Więc mam subscription tabela w mojej bazie danych.

Chciałbym mieć state kolumna, która będzie miała jedną z następujących wartości

Valid
Invalid
Cancelled
In Trial
Non Renewing
Future

Czy ktoś może wyjaśnić, jak wykorzystać te wartości jako wartości wyliczeniowe w szynach 4?


14
2018-03-08 17:36


pochodzenie




Odpowiedzi:


Kredyt do: https://hackhands.com/ruby-on-enums-queries-and-rails-4-1/

Deklaracja atrybutu enum, w którym wartości są odwzorowywane na liczby całkowite w bazie danych, ale można je wyszukiwać według nazwy. Przykład:

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

# conversation.update! status: 0
conversation.active!
conversation.active? # => true
conversation.status  # => "active"

# conversation.update! status: 1
conversation.archived!
conversation.archived? # => true
conversation.status    # => "archived"

# conversation.update! status: 1
conversation.status = "archived"

# conversation.update! status: nil
conversation.status = nil
conversation.status.nil? # => true
conversation.status      # => nil

Będą również dostępne zakresy oparte na dozwolonych wartościach pola wyliczeniowego. W powyższym przykładzie utworzy aktywny i zarchiwizowany zakres.

Możesz ustawić wartość domyślną z deklaracji bazy danych, na przykład:

create_table :conversations do |t|
  t.column :status, :integer, default: 0
end

Dobrą praktyką jest, aby pierwszy deklarowany status był domyślny.

Wreszcie możliwe jest również jawne odwzorowanie relacji między atrybutem a bazą danych integer za pomocą skrótu:

class Conversation < ActiveRecord::Base
  enum status: { active: 0, archived: 1 }
end

Zauważ, że gdy używana jest tablica, niejawne mapowanie z wartości na liczby całkowite z bazy danych uzyskuje się z kolejności, w jakiej wartości pojawiają się w tablicy. W przykładzie: aktywny jest odwzorowany na 0, ponieważ jest pierwszym elementem, a: zarchiwizowany jest odwzorowany na 1. Ogólnie i-ty element jest mapowany na i-1 w bazie danych.

Dlatego, po dodaniu wartości do tablicy enum, jej pozycja w tablicy musi być zachowana, a nowe wartości powinny być dodane tylko do końca tablicy. Aby usunąć nieużywane wartości, należy użyć jawnej składni skrótu.

W rzadkich przypadkach może być konieczne uzyskanie bezpośredniego dostępu do mapowania. Odwzorowania są ujawniane za pomocą metody klasy o pluralizowanej nazwie atrybutu:

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

Użyj tej metody klasy, gdy chcesz poznać wartość porządkową wyliczenia:

Conversation.where("status <> ?", Conversation.statuses[:archived])

Gdzie warunki atrybutu enum muszą używać wartości porządkowej wyliczenia.

Więcej informacji: http://api.rubyonrails.org/v4.1.0/classes/ActiveRecord/Enum.html


18
2018-03-08 18:23



Niestety działa to tylko w szynach4.1. Nie chcę teraz aktualizować mojej aplikacji do rails 4.1. - Omer Aslam
@cevaris Pierwotnie skopiowałem tę odpowiedź ze strony dokumentacji rails. Nie z linku, o którym wspomniałeś. Mam nadzieję, że szyny skopiowały kod ze źródła, o którym wspomniałeś - Giri


Możesz użyć klejnot o nazwie Przepływ pracy. Umożliwia używanie niestandardowych statusów i płynne przetwarzanie przejść między stanami. Używałem go w wielu aplikacjach Rails3 i Rails 4.

Przykład z dokumentacji.

class Article
  include Workflow
  workflow do
    state :new do
      event :submit, :transitions_to => :awaiting_review
    end
    state :awaiting_review do
      event :review, :transitions_to => :being_reviewed
    end
    state :being_reviewed do
      event :accept, :transitions_to => :accepted
      event :reject, :transitions_to => :rejected
    end
    state :accepted
    state :rejected
  end
end

I później:

article = Article.new
article.accepted? # => false
article.new? # => true

3
2018-03-12 23:06





Edytować:  Moja odpowiedź tutaj nie używa Magia wyrażeń ActiveRecord. Poniższe sugestie działają dla dowolnej biblioteki DB (np Dalszy ciąg) i wydaje mi się, że jest nieco bardziej solidny. Na przykład nie polega na automatycznym porządkowaniu wartości i używa ograniczeń klucza obcego w RDBMS, aby zapewnić poprawność wartości (w przeciwieństwie do rozwiązania ActiveRecord). Jednak nie jest to metodologia idiomatyczna Railsów. Zobacz odpowiedź Giri (kopia / wklej strony z dokumentacją) dla odpowiedzi idiomatycznej.


  1. Stwórz states tabeli w bazie danych z tymi wartościami łańcuchów wypełnionymi wraz z unikalnym identyfikatorem, np.

    states
    id | name 
    ---+--------------
     1 | Valid
     2 | Invalid
     3 | Cancelled
     4 | In Trial
     5 | Non Renewing
     6 | Future
    
  2. Użyj standardowego skojarzenia klucza obcego w twoim subscription tabela odwołująca się do wpisu z states.

  3. W swoich modelach utwórz a State klasa ze stałymi pasującymi do ID, np .:

    class State < ActiveRecord::Base
      VALID   = 1
      INVALID = 2
      # etc.
    end
    

Teraz masz pewność, że dane tabeli są prawidłowe, oraz b) możesz korzystać z wygodnych referencji, takich jak pytania subscriptions 

Subscription.where( state_id: State::VALID )

2
2018-03-08 18:24



To nie jest tak, jak Rails 4 obsługuje enum. Twoja odpowiedź nie jest zła, ale nie jest to metoda Rails 4, której potrzebuje odpowiedź na pytanie ... Spójrz api.rubyonrails.org/v4.1.0/classes/ActiveRecord/Enum.html - rizidoro
@rizidoro Dziękuję za informację. Osobiście uważam, że sposób Railsów jest mniej idealny, ponieważ polega na egzekwowaniu referencyjnej integralności w Ruby zamiast w bazie danych. Giri: proszę przełączyć zaakceptowaną odpowiedź na kopię / wklejenie dokumentacji Rails. - Phrogz
Nie podoba mi się pomysł kodów stałych jako stałych. Sparowuje twój kod z danymi w bazie danych. Zrobiłem to w przeszłości i nienawidziłem go tak bardzo, gdy muszę wdrożyć aplikację w wielu środowiskach (osobny db), lub napisać testy automatyczne ... Również unikałbym używania liczb całkowitych jako stanów, znajdziesz Jest to bardzo sprzeczne z intuicją, gdy trzeba pisać niestandardowe zapytania lub rozszerzenia i nie można sobie przypomnieć, który numer oznacza, bez patrzenia na kod. - Yurui Ray Zhang