Ar pykstate kiekvieną kartą, kai matote, kad rails valdiklyje filtruojant duomenis mutuoja egzemplioriaus kintamieji? Šis straipsnis skirtas jums. 🙂
Filtrai
Tikriausiai jau esate tai matę anksčiau:
# app/controllers/api/v1/things_controller.rb
modulis API
modulis V1
klasė ThingsController < BaseController
def index
@things = Thing.all
@things = @things.where(size: params[:size]) if params[:size]
@things = @things.where('name ILIKE ?', "%#{params[:name_contains]}%") if params[:name_contains]
render json: @things
end
end
end
end
Kodėl manau, kad tai yra blogai kodas? Todėl, kad dėl to mūsų valdiklis tiesiog storėja. IMHO turėtume iš valdiklių išgauti kuo daugiau logikos ir naudoti su tikslu susijusį komunalinių paslaugų ar paslaugų. Šiuo atveju įdiegsime bendrąjį filtrą, kurį galėsime naudoti daugelyje valdiklių.
Bet palaukite, pirmiausia išanalizuokime dabartinį kodą. Jis gali būti blogas, tačiau veikia. Turime tam tikrą pradinę taikymo sritį (Thing.all), o tada jį apriboja, jei naudotojas praėjo susijęs parametras. Kiekvieno filtro atveju tikriname, ar buvo perduotas parametras, ir, jei taip, tikriname, ar jis buvo perduotas, taikome filtrą. Antras dalykas - mums nereikia naudoti ivar, galime naudoti paprastus senus vietinius kintamuosius.
Gerai, tada. Ar negalėtume pradinei sričiai pakeisti naudoti kokį nors paslaugos objektą? Vykdymas gali atrodyti taip:
# app/controllers/api/v1/things_controller.rb
API modulis
modulis V1
klasė ThingsController < BaseController
def index
scope = Thing.all
things = Things::IndexFilter.new.call(scope, params)
atvaizduoti json: things
pabaiga
pabaiga
end
end
Dabar jis atrodo daug geriau, bet, žinoma, dar turime įdiegti filtrą. Atkreipkite dėmesį, kad skambučio parašas bus vienodas visiems ištekliams, todėl galime turėti tam tikra bendroji klasė, skirta šiai užduočiai atlikti.
Atrodo sudėtinga? Tikrai ne - visa magija vyksta #aikyti_filtrus!. Paimame pradinės srities dublikatą ir taikome jam kiekvieną filtrą.
Kai taikome apimtį, tai reiškia, kad mutuojame savo pradinės srities dublikatą. Tikimės, kad filtrai bus įdiegti kaip hash į self.filters metodas antrinės klasės. Padarykime tai.
Štai ir viskas! Parašėme daugiau kodo, bet paprasti filtrai atrodys taip pat būdas visiems ištekliams. Mes išvalėme valdiklį iš atsakingo kodo filtravimo ir pateikė ‘specializuotą’ klasę šiam tikslui, kuri labai aiškią konvenciją.