Ruby on Rails – hogyan lehet tökéletes Enumot létrehozni 5 lépésben

Másolás a vágólapra

amikor a projekt elindul, valószínűleg ERD diagramot vagy hasonlót tervez. Ezután minden alkalommal, amikor egy ügyfél új követelményeket ad át Önnek, módosítani kell. Ez a folyamat segít megérteni az adott területet, és tükrözi a valóságot. A modellezett entitások számos különböző típusú attribútumot tartalmaznak. Nagyon népszerű követelmény egy olyan Attribútum létrehozása, amely a rendelkezésre álló néhány érték egyikéhez rendelhető. A programozásban ezt a típust nevezzük felsorolás vagy csak enum.

például ez lehet egyfajta kézbesítés:” futár”,” csomagállomás “vagy”személyes”. Rails támogatja enums a 4.1-es verziótól.

ez a cikk 3 részből áll:

  1. alapvető megoldás-bevezetni ActiveRecord::Enum, a lehető legegyszerűbb
  2. 5 különböző lépéseket, hogy javítsa enums működését
  3. végső megoldás – wrap minden fejlesztést egy végrehajtási

hogy jobban megértsük a témát nézzük hozzá néhány valós háttér. Legutóbbi projektünkben egy műalkotásokkal kapcsolatos rendszeren dolgoztunk. Artworks gyűjtötték be Catalogs. A katalógus az alkalmazásunk egyik legnagyobb modellje volt. A sok attribútum közül 4 enum típusú volt.

state:

auction_type:

status:

localization:

alapvető megoldás

az enum hozzáadása egy meglévő modellhez nagyon egyszerű feladat. Először is létre kell hoznia egy megfelelő migrációt. Figyelje meg, hogy az oszlop típusa egész számra van állítva, és így tartja a Rails az Enums értékeket az adatbázisban.

rails g migration add_status_to_catalogs status:integer

class AddStatusToCatalogs < ActiveRecord::Migration def change add_column :catalogs, :status, :integer endend

a következő lépés az enum attribútum deklarálása a modellben.

class Catalog < ActiveRecord::Base enum status: end

Irányítsd a migrációt, és kész! Mostantól kihasználhatja az egész csomó extra módszert.

például ellenőrizheti, hogy az aktuális állapot adott értékre van-e állítva:

catalog.published? # false

vagy módosítsa az állapotot más értékre:

catalog.status = "published" # publishedcatalog.published! # published

az összes közzétett katalógus felsorolása:

Catalog.published

az összes megadott módszer megtekintéséhez ellenőrizze ActiveRecord::Enum.

ez az egyszerű megoldás nagy a kezdet, de lehet befut néhány bajok, amikor a projekt növekedni fog. Az előkészítéshez végrehajthat néhány fejlesztést, amelyek megkönnyítik az enum karbantartását:

deklarálja az enum-ot Hash not tömbként

biztonsági rés változás előtt: a deklarált értékek és az adatbázisban tárolt egész számok közötti leképezés a tömb sorrendjén alapul.

ebben a példában a leképezés a következő lenne:

class Catalog < ActiveRecord::Base enum localization: end
0 -> home1 -> foreign2 -> none

ez a megközelítés egyáltalán nem rugalmas. Képzelje el, hogy a követelmények csak megváltoztak. Mostantól az” idegen “lokalizációt” Amerikára “és”Ázsiára” kell osztani. Ebben az esetben távolítsa el a régi értéket, és adjon hozzá két újat. De … nem távolíthatja el a fel nem használt “idegen” típust, mert sérti a fennmaradó értékek sorrendjét. Ennek a helyzetnek az elkerülése érdekében az enum-ot Hash – ként kell deklarálnia. Nincs sok tennivaló:

class Catalog < ActiveRecord::Base enum localization: { home: 0, foreign: 1, none: 2 }end

ez a nyilatkozat nem függ a megrendeléstől, így képes lesz végrehajtani a változtatásokat, és megszabadulni a fel nem használt enum értéktől.

Activerecord Integrálása::Enum with PostgreSQL enum

biztonsági rés a változás előtt: értelmetlen egész értékek az adatbázisban.

az adatbázisban egész számok által képviselt attribútumokkal való munka bosszantó lehet. Képzelje el, hogy rails console – ben szeretne lekérdezni valamit, vagy akár létre kell hoznia egy hatókört az enum mező alapján. A háttérre támaszkodva tegyük fel, hogy vissza akarjuk adni az összes Catalogs – ot, amelyek még mindig naprakészek. Így írhatunk egy where clause – et így:

Catalog.where.not("state = ?", "finished")

hiba történt, ahogy vártuk:

ActiveRecord::StatementInvalid: PG::InvalidTextRepresentation:ERROR: invalid input syntax for integer: "finished"

ez a probléma csak a where clause tömb formátumban fordul elő, mert a második érték közvetlenül SQL where clause – be kerül, és nyilvánvalóan a “kész” nem egész szám.

hasonló eset fordulhat elő, ha a complex SQL query programot a ActiveRecord réteg kihagyásával valósítja meg. Ha a lekérdezés nem fér hozzá a modellhez, akkor elveszíti az értékekkel kapcsolatos értelmes információkat, és értelem nélküli tiszta egész számokkal marad. Ebben az esetben extra erőfeszítéseket kell tennie annak érdekében, hogy ezek az egész számok ismét értelmesek legyenek.

egy másik bosszantó helyzet fordulhat elő, ha egy ilyen örökölt adatbázissal dolgozik. Ön hozzáfér az adatbázishoz, és csak az ott tárolt adatok érdeklik. Nem tud azonnal információt kapni abból, amit lát. Ezeket a számokat mindig valós értékekre kell leképezni a tartományból.

érdemes megjegyezni, hogy amikor az integer enum elválik a modelljétől, mint a fenti példákban, akkor sajnos elveszítjük az információkat.

hogy még jobban meggyőzze önt, van biztonsági pont is. ActiveRecord::Enum deklarálásakor nincs garancia arra, hogy az Ön adatai csak a megadott értékekre korlátozódnak. Változtatásokat lehet tenni bármilyen SQL betoldások. Másrészt, ha deklarálja PostgreSQL enum kapsz kényszer adatbázis szinten. El kell döntenie, mennyire magabiztos akar lenni.

a PostgreSQL-t általában adatbázisként használják a Ruby on Rails projektekben. A PostgreSQL enum attribútumtípusként használható az adatbázis táblában.

lássuk, hogy néz ki ezúttal.

rails g migration add_status_to_catalogs status:catalog_status

meg kell változtatnia az attribútum típusát. Nem javaslom olyan típusok létrehozását, mint az “állapot”. Valószínű, hogy a jövőben egy másik állapot jelenik meg. Ezután egy kicsit meg kell változtatnia a migrációt. Leginkább visszafordíthatónak kell lennie, és végre kell hajtania az SQL-t.

nyilatkozat hasonló az előzőhöz:

class Catalog < ActiveRecord::Base enum status: { published: "published", unpublished: "unpublished", not_set: "not_set" }end

index hozzáadása az enum attribútumhoz

biztonsági rés a változás előtt: lekérdezések teljesítménye.

ez a pont egyszerű. Nagyon valószínű, hogy az enum attribútum az, ami megkülönbözteti az objektumokat egy adott modellen belül. Mint a mi állapotunkban: néhány Catalogs megjelent, mások pedig nem. Ennek következtében az adott attribútum szerinti keresés vagy szűrés meglehetősen gyakori feladat lesz, ezért érdemes indexet hozzáadni ehhez a mezőhöz. Módosítsuk a migrációt:

class AddIndexToCatalogs < ActiveRecord::Migration def change add_index :catalogs, :status endend

előtag vagy utótag opció használata az enums-ban

biztonsági rések a változás előtt:

  • Unintuitive hatókörök
  • a segítő módszerek rossz olvashatósága
  • hajlamos a hibákra

a legutóbbi projektünkre hivatkozva ismét volt néhány enum a Catalog modellben:

state:

auction_type:

status:

localization:

előtag vagy utótag hozzáadásához az enum-hoz elegendő ezt a lehetőséget hozzáadni a deklarációhoz, így:

lássuk, miért lehet ilyen hasznos. A Catalog modellben 4 enum és 12 érték van közöttük. Létrehoz 12 hatókörök, nagyon unintuitív hatókörök.

Catalog.not_setCatalog.liveCatalog.unpublishedCatalog.in_progress

meg tudja mondani könnyedén, hogy ezek a módszerek visszatérnek? Nem, mindig emlékezni kell arra, hogy néz ki a hatókör. Lehet, hogy bosszantó, igazán.

Catalog.status_not_setCatalog.live_auction_typeCatalog.status_unpublishedCatalog.state_in_progress

ez sokkal jobban néz ki.

tegyük fel, hogy most még egy enumot kell hozzáadnia a modelljéhez. Meg kell őriznie az egyes katalógusok sorrendjét a globális katalógusban. Előfordulhat, hogy egyes katalógusok sorrendje nincs megadva. A legfontosabb tudni, hogy melyik az első és melyik az utolsó. Létrehozhatunk egy másik enumot:

class Catalog < ActiveRecord::Base enum order: { first: "first", last: "last", other: "other", none: "none" }end

nyissuk meg a rails console – et az új hatókörök teszteléséhez:

Catalog.order

hiba történt. Magától értetődő.

 ArgumentError: You tried to define an enum named "order" on the model "Catalog", but this will generate a class method "first", which is already defined by Active Record.

Ok, meg tudjuk javítani:

és ismét egy másik hiba:

ArgumentError (You tried to define an enum named "order" on themodel "Catalog", but this will generate an instance method"none?", which is already defined by another enum.)

Oké, ez is nyilvánvaló. Elfelejtettük, hogy a “Nincs” értéket egy másik attribútumban is deklarálták.

előtag vagy utótag opciók tökéletesen illeszkednek az ilyen típusú problémák elkerüléséhez. Deklarálhatjuk az értékeket, ahogy akarjuk, nincs ok arra, hogy megváltoztassuk a leginkább leíró szavakat. Ebben a megközelítésben a hatókörök intuitívabbak és értelmesebbek. Az új attribútum szerint a nyilatkozatnak így kell kinéznie:

class Catalog < ActiveRecord::Base enum order: { first: "first", last: "last", other: "other", none: "none" }, _prefix: :orderend

Implement érték objektum enum

biztonsági rés kezelésére a módosítás előtt: Fat modell

két esetben javasolhatom az enum attribútum elválasztott érték objektumba történő kibontását:

  1. az Enum attribútumot sok modell között használják (legalább 2)
  2. az Enum attribútumnak sajátos logikája van, amely bonyolítja a modellt.

Ok, mutassuk be a minta helyzetét. Projektünkben az aukciós házakat (ahol műalkotásokat értékesítenek) az egész országban elhelyezik. Lengyelország 16 régióra oszlik, úgynevezett vajdaságoknak. Minden AuctionHouse modellnek van egy speciális Address, amely Voivodeship attribútumot tartalmaz. El tudod képzelni, hogy valamilyen oknál fogva szükség lesz csak az északi Aukciós házak vagy ezek felsorolására a legnépszerűbb vajdaságokból. Ebben az esetben extra logikát kell beépíteni a modellünkbe, ami kövérebbé teszi. Ennek elkerülése érdekében kivonhatja ezt a logikát egy másik osztályba, így újrafelhasználható és tisztább.

class Voivodeship VOIVODESHIPS = %w(dolnoslaskie kujawsko-pomorskie lubelskie lubuskie lodzkie malopolskie mazowieckie opolskie podkarpackie podlaskie pomorskie slaskie swietokrzyskie warminsko-mazurskie wielkopolskie zachodnio-pomorskie).freeze NORTHERN_VOIVODESHIPS = %w(warminsko-mazurskie pomorskie zachodnio-pomorskie podlaskie).freeze MOST_POPULAR_VOIVODESHIPS = %w(dolnoslaskie mazowieckie slaskie malopolskie).freeze def initialize(voivodeship) @voivodeship = voivodeship end def northern? NORTHERN_VOIVODESHIPS.include? @voivodeship end def popular? MOST_POPULAR_VOIVODESHIPS.include? @voivodeship end def eql?(other) to_s.eql?(other.to_s) end def to_s @voivodeship.to_s endend

ezután a megfelelő modellben felül kell írnia ezt az attribútumot. A projektünkben ez Address modell. A array_to_enum_hash csak segítő módszer, amely az enum értékek Arrayértékét Hash – re konvertálja.

itt van, amit elért. A vajdaságokkal kapcsolatos teljes logika egyetlen osztályba van beágyazva. Akkor meghosszabbítja azt, amit akar, és Address modell maradt vastag.

Most, amikor a Vajdaság attribútumot szeretné megkapni, a Voivodeship osztály objektumát adja vissza. Ez az érték objektum.

vessen egy pillantást arra, hogy mindkét vajdaságnak ugyanaz az értéke, de tárgyként nem azonosak. Segítő módszerünknek köszönhetően így ellenőrizhetjük az egyenlőséget:

voivodeship_a.eql? voivodeship_b# truevoivodeship_a.eql? voivodeship_c# false

és ami a legerősebb, kihasználhatja az összes meghatározott módszert, amely a korábban meghatározott követelményeket képviseli.

voivodeship_a.northern? # truevoivodeship_a.popular? # falsevoivodeship_c.northern? # falsevoivodeship_c.popular? # false

végső megoldás

Ok, 5 enum fejlesztésen ment keresztül. Most itt az ideje, hogy összefoglalja az összes lépést, és hozzon létre végső megoldás. Vegyük például a status attribute – et a Catalog modellből. A megvalósítás így néz ki:

migráció generálása:

rails g migration add_status_to_catalogs status:catalog_status

migráció:

ValueObject:

class CatalogStatus STATUSES = %w(published unpublished not_set).freeze def initialize(status) @status = status end # what you need hereend

katalógus modell & enum nyilatkozat:

következtetés

ennyi – 5 lépés az enums jobb megvalósításának felépítéséhez a Sínekben.

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé.