Właśnie zaczynam pracę z moją pierwszą aplikacją Ruby on Rails. Mam kilka różnych modeli, widoków, kontrolerów i tak dalej.
Chcę znaleźć dobre miejsce do przyklejenia definicji prawdziwie globalnych stałych, które mają zastosowanie w całej mojej aplikacji. W szczególności dotyczą one zarówno logiki moich modeli, jak i decyzji podjętych w moich poglądach. Nie mogę znaleźć SUCHEGO miejsca, w którym można by umieścić te definicje, w których są one dostępne zarówno dla wszystkich moich modeli, jak i we wszystkich moich widokach.
Aby podać konkretny przykład, chcę stałą COLOURS = ['white', 'blue', 'black', 'red', 'green']
. Jest to stosowane wszędzie, zarówno w modelach, jak i widokach. Gdzie mogę to zdefiniować w jednym miejscu, aby było dostępne?
Co próbowałem:
- Zmienne klasy stałej w pliku model.rb, z którymi są najbardziej skojarzone, takie jak
@@COLOURS = [...]
. Ale nie mogłem znaleźć rozsądnego sposobu, aby to zdefiniować, abym mógł pisać w swoich poglądach,Card.COLOURS
a nie coś w stylu kludgyCard.first.COLOURS
. - Metoda na modelu, coś w rodzaju
def colours ['white',...] end
- ten sam problem. - Metoda w application_helper.rb - do tej pory to robię, ale pomocniki są dostępne tylko w widokach, a nie w modelach
- Wydaje mi się, że mogłem wypróbować coś w application.rb lub environment.rb, ale te nie wydają się słuszne (i one też nie działają)
Czy po prostu nie ma sposobu, aby zdefiniować coś, co byłoby dostępne zarówno z modeli, jak i widoków? Mam na myśli, że wiem, że modele i widoki powinny być oddzielne, ale na pewno w niektórych domenach będą potrzebne momenty, aby odwoływać się do tej samej wiedzy specyficznej dla domeny?
źródło
Odpowiedzi:
Jeśli twój model jest naprawdę „odpowiedzialny” za stałe, powinieneś je tam przykleić. Możesz utworzyć metody klasowe, aby uzyskać do nich dostęp bez tworzenia nowej instancji obiektu:
Alternatywnie możesz utworzyć zmienne klas i akcesor. Jest to jednak odradzane, ponieważ zmienne klasowe mogą zadziwić dziedziczeniem i środowiskami wielowątkowymi.
Dwie powyższe opcje pozwalają zmienić zwracaną tablicę przy każdym wywołaniu metody akcesora, jeśli jest to wymagane. Jeśli masz prawdziwie niezmienną stałą, możesz również zdefiniować ją w klasie modelu:
Można również utworzyć stałe globalne, które są dostępne z dowolnego miejsca w inicjalizatorze, jak w poniższym przykładzie. Jest to prawdopodobnie najlepsze miejsce, jeśli twoje kolory są naprawdę globalne i używane w więcej niż jednym kontekście modelu.
Uwaga: kiedy zdefiniujemy stałe powyżej, często chcemy
freeze
tablicy. Zapobiega to późniejszemu (niezamierzonemu) zmodyfikowaniu tablicy przez inny kod, np. Poprzez dodanie nowego elementu. Po zamrożeniu obiektu nie można go już zmienić.źródło
config/initializers/my_constants.rb
touch tmp/restart.txt
def self.colours
przykład nie jest idealny. Za każdym razem, gdy dzwoniszdef self.colours
, zwracana jest nowa instancja tablicy .#freeze
nie pomoże w tym przypadku. Najlepszą praktyką jest zadeklarowanie jej jako stałej Ruby, w którym to przypadku zawsze otrzymasz ten sam obiekt.class Card; COLOURS = ['white', 'blue'].freeze; def self.colours; COLOURS; end; end
To powiedziawszy, przydzielanie tablicy w dowolnym języku może być potencjalnie problematyczne; po pierwsze, używa pamięci bez (dobrego) powodu. Jeśli ładujesz z DB i chcesz buforować wartość, możesz również użyć zmiennej instancji klasy, którą można leniwie załadować za pomocądef self.colours
metody. Zgodzili się jednak co do aspektu niezmienności.Niektóre opcje:
Używając stałej:
Lazy załadowane przy użyciu zmiennej instancji klasy:
Jeśli jest to prawdziwie globalna stała ( unikaj jednak globalnych stałych tego rodzaju ), możesz również rozważyć na przykład wprowadzenie stałej najwyższego poziomu
config/initializers/my_constants.rb
.źródło
extend
moduł w klasie, aby był dostępny zCard.COLOURS
.extend
nie działa dla mnie. Podczas korzystaniainclude
mogę uzyskać dostęp jak:Card::COLOURS
/models
. O wiele lepiej jest, jeśli utworzysz inicjator./models
, ale tylko jeśli jest w module, np.module Constants; COLOURS = ...; end
w pliku o nazwiemodels/constants.rb
.Od wersji Rails 4.2 możesz korzystać z
config.x
właściwości:Które będą dostępne jako:
Inna metoda ładowania niestandardowej konfiguracji:
W Railsach 5 i 6 możesz dodatkowo użyć tego
configuration
obiektu do niestandardowej konfiguracjiconfig.x
. Można go jednak używać tylko do konfiguracji zagnieżdżonej:Będzie dostępny jako:
źródło
Rails.configuration.colours
Najbardziej lubię (choć chciałbym, żeby nie było tak długo)config
Jest tak dobry jakconfiguration
. W pewnym momencie możemy spodziewać się skrótu :)ApplicationController
jeśli nie ma nic innego pomiędzy. Jeśli stała nie jest bezpośrednio związana z kontrolerami, nadal rozważałbym konfigurację globalną itp.Jeśli potrzebna jest stała w więcej niż jednej klasie, umieszczam ją w config / initializers / contant.rb zawsze we wszystkich wielkich literach (lista stanów poniżej jest obcięta).
Są one dostępne w całej aplikacji poza kodem modelu jako takim:
Aby użyć stałej w modelu, użyj attr_accessor, aby udostępnić stałą.
źródło
config/initializers/constants.rb
prawdopodobnie byłby jednak lepszym wyboremW przypadku ustawień dla całej aplikacji i stałych globalnych zalecam użycie Settingslogic . Ustawienia te są przechowywane w pliku YML i są dostępne w modelach, widokach i kontrolerach. Ponadto możesz tworzyć różne ustawienia dla wszystkich środowisk:
Gdzieś w widoku (wolę metody pomocnicze dla tego rodzaju rzeczy) lub w modelu można uzyskać np. Tablicę kolorów
Settings.colors.split(/\s/)
. Jest bardzo elastyczny. I nie musisz wymyślać roweru.źródło
Użyj metody klasowej:
Następnie
Model.colours
zwróci tę tablicę. Alternatywnie, utwórz inicjalizator i zawiń stałe w module, aby uniknąć konfliktów przestrzeni nazw.źródło
Staraj się utrzymywać stałą wartość w jednym miejscu. W mojej aplikacji utworzyłem folder stałych wewnątrz inicjatorów w następujący sposób:
i zwykle utrzymuję wszystko w tych plikach na stałym poziomie.
W twoim przypadku możesz utworzyć plik w folderze stałych jako
colors_constant.rb
colors_constant.rb
Nie zapomnij zrestartować serwera
źródło
Inna opcja, jeśli chcesz zdefiniować swoje stałe w jednym miejscu:
Ale nadal sprawiają, że są widoczne na całym świecie, bez konieczności uzyskiwania do nich dostępu w pełni wykwalifikowany sposób:
źródło
Wewnątrz znajduje się wspólne miejsce do umieszczania stałych globalnych dla całej aplikacji
config/application
.źródło
Zwykle mam program / tabelę „lookup” w moim programie railsowym i używam jej dla stałych. Jest to bardzo przydatne, jeśli stałe będą różne dla różnych środowisk. Ponadto, jeśli masz plan ich rozszerzenia, powiedz, że chcesz dodać „żółty” w późniejszym terminie, możesz po prostu dodać nowy wiersz do tabeli odnośników i gotowe.
Jeśli dasz administratorowi uprawnienia do modyfikowania tej tabeli, nie przyjdą do ciebie w celu konserwacji. :) SUCHY.
Oto jak wygląda mój kod migracji:
Używam seeds.rb, aby wstępnie wypełnić.
źródło
Zmienna globalna powinna być zadeklarowana w
config/initializers
kataloguźródło
W zależności od warunków możesz także zdefiniować niektóre zmienne środowiskowe i pobrać je za pomocą
ENV['some-var']
kodu ruby, to rozwiązanie może nie pasować do ciebie, ale mam nadzieję, że może pomóc innym.Przykład: można tworzyć różne pliki
.development_env
,.production_env
,.test_env
i załadować go według swoich środowisk aplikacji, zaznacz to gen dotenv barierkami , które automatyzują to dla twojego.źródło