Miks ei kasutata rööpmootoreid sagedamini? Ma ei tea vastust, kuid arvan, et „Kõik on mootor” üldistamine on varjanud probleemidomeenid, mida need aitavad lahendada.
Suurepärane Rails Guide dokumentatsioon Rails Enginesiga alustamiseks on Rails Engine'i juurutamisel neli populaarset näidet: Forem, Devise, Spree ja RefineryCMS. Need on fantastilised reaalses maailmas kasutatavad juhtumid mootorite jaoks, kes kasutavad Rails-rakendusega integreerimisel erinevat lähenemist.
Nende kalliskivide seadistamise ja koostamise osade uurimine annab edasijõudnutele edusamme Ruby on Rails arendajad väärtuslikud teadmised selle kohta, milliseid mustreid või tehnikaid looduses proovitakse ja katsetatakse, nii et kui teil on käes aeg, saate teil paar lisavõimalust hinnata.
Ma eeldan, et tunnete pealiskaudselt, kuidas mootor töötab, nii et kui tunnete, et midagi pole veel kokku jõudnud, tutvuge palun kõige suurepärasema rööbaste juhendiga Mootoritega alustamine .
Uurime pikemalt mõtlemata Railsi mootorite näidete metsikus maailmas!
simulatsioon võib kasutada mis tahes tõenäosuse jaotust, mille kasutaja määratleb.
Railsile mõeldud mootor, mille eesmärk on olla kõigi aegade parim väike foorumite süsteem
See pärl järgib mootorite rööbastejuhendi tähte. See on suur näide ja selle hoidla tutvumine annab teile aimu, kui kaugele saate põhiseadistust venitada.
See on ühe mootoriga pärl, mis kasutab peamise rakendusega integreerimiseks paari tehnikat.
module ::Forem class Engine Huvitav osa siin on Decorators.register!
klassi meetod, mille on paljastanud dekoraatorite pärl. See kapseldab laadimisfailid, mida ei kaasata rööbaste automaatse laadimise protsessi. Võib-olla mäletate, et kasutate selgesõnalist require
avaldused rikuvad automaatse laadimise arendusrežiimis, nii et see on elupäästja! Toimuva näitlikustamiseks on selgem kasutada juhendi näidet:
config.to_prepare do Dir.glob(Rails.root + 'app/decorators/**/*_decorator*.rb').each do |c| require_dependency(c) end end
Suurem osa Foremi seadistamise võludest leiab Forem
põhimooduli ülemisest määratlusest. See fail tugineb user_class
initsiaatorifailis seatav muutuja:
Forem.user_class = 'User'
Selle saavutate, kasutades mattr_accessor
kuid see kõik on Rails Guide'is, nii et ma ei korda seda siin. Kui see on paigas, kaunistab Forem kasutajaklassi kõigega, mida on vaja rakenduse käitamiseks:
module Forem class <'Forem::Post', :foreign_key => 'user_id' # ... def forem_moderate_posts? Forem.moderate_first_post && !forem_approved_to_post? end alias_method :forem_needs_moderation?, :forem_moderate_posts? # ...
Mis osutub üsna palju! Olen enamuse välja lõiganud, kuid olen jätnud seose definitsiooni ja eksemplari meetodi, et näidata teile tüüpide ridu, mida leiate seal.
Kogu faili pilguheitmine võib näidata, kui hallatav võib olla osa teie rakendusest mootorisse korduvkasutamiseks.
Kaunistamine on mängu nimi mootori vaikekasutuses. Gemsi lõppkasutajana saate mudeli, vaate ja kontrollerid alistada, luues klasside jaoks oma versioonid, kasutades dekoraatori pärl README-s sätestatud failiteed ja failinimede konventsioone. Selle lähenemisega kaasnevad kulud, eriti kui mootor saab suurema versiooniuuenduse - dekoratsioonide töökorras hoidmine võib kiiresti käest ära minna. Ma ei viita siin Foremile, ma usun, et nad on kindlalt kinni pidanud kitsastest põhifunktsioonidest, kuid pidage seda meeles, kui loote mootori ja otsustate kapitaalremondi teha.
Anname selle ühe kokkuvõtte: see on Railsi vaikemootori kujundusmudel, mis põhineb lõppkasutajatel, kes kaunistavad vaateid, kontrollereid ja mudeleid, ning lähtestusfailide kaudu konfigureerides põhiseadeid. See töötab hästi keskendunud ja seotud funktsionaalsuse korral.
Moto
Leiate, et mootor on rakendusega Rails väga sarnane, kusjuures views
, controllers
ja models
kataloogid. Devise on hea näide rakenduse kapseldamisest ja mugava integratsioonipunkti eksponeerimisest. Vaatame läbi, kuidas see täpselt töötab.
Need koodiread tunnete ära, kui olete olnud Railsi arendaja rohkem kui paar nädalat:
class User Iga parameeter edastati devise
meetod esindab moodulit Devise mootoris. Neid mooduleid on kümme, mis pärinevad tuttavast ActiveSupport::Concern
Need laiendavad teie User
klassi, kutsudes devise
meetod selle reguleerimisalasse.
Seda tüüpi integreerimispunkti olemasolu on väga paindlik, saate mootori täitmiseks vajaliku funktsionaalsuse taseme muutmiseks lisada mõne neist parameetritest või neid eemaldada. See tähendab ka seda, et te ei pea kodeerima, millist mudelit soovite lähtestusfailis kasutada, nagu soovitab mootorite rööbaste juhend. Teisisõnu pole see vajalik:
kuidas tarkvaraarendajat leida
Devise.user_model = 'User'
See abstraktsioon tähendab ka seda, et saate seda rakendada sama rakenduse raames rohkem kui ühele kasutajamudelile (näiteks admin
ja user
), samas kui konfiguratsioonifailide lähenemine jätaks teid autentimisega ühele mudelile. See pole küll kõige suurem müügiargument, kuid illustreerib probleemi lahendamiseks teistsugust viisi.
Seade laieneb ActiveRecord::Base
oma mooduliga, mis sisaldab devise
meetodi määratlus:
# lib/devise/orm/active_record.rb ActiveRecord::Base.extend Devise::Models
Kõik klassid, mis pärivad ActiveRecord::Base
on nüüd juurdepääs Devise::Models
määratletud klassi meetoditele:
#lib/devise/models.rb module Devise module Models # ... def devise(*modules) selected_modules = modules.map(&:to_sym).uniq # ... selected_modules.each do |m| mod = Devise::Models.const_get(m.to_s.classify) if mod.const_defined?('ClassMethods') class_mod = mod.const_get('ClassMethods') extend class_mod # ... end include mod end end # ... end end
(Oluliste osade esiletõstmiseks eemaldasin palju koodi (# ...
).)
Parafraseerides koodi devise
iga edastatud mooduli nime kohta meetod oleme:
- meie poolt määratud mooduli laadimine
Devise::Models
alla (Devise::Models.const_get(m.to_s.classify
) User
laiendamine klass ClassMethods
-ga moodul, kui see on olemas - sisaldama määratud moodulit (
include mod
), et lisada oma eksemplarimeetodid klassi, kutsudes devise
meetod (User
)
Kui soovite luua mooduli, mida saaks sel viisil laadida, peate veenduma, et see järgiks tavapäraseid ActiveSupport::Concern
liides, kuid nimeruumi Devise:Models
all kuna siin otsime konstandi hankimist:
module Devise module Models module Authenticatable extend ActiveSupport::Concern included do # ... end module ClassMethods # ... end end end end
Phew.
on c lihtne õppida
Kui olete varem kasutanud Rails’i muresid ja kogenud nende korduvkasutatavust, saate hinnata selle lähenemisviisi häid külgi. Lühidalt, funktsionaalsuse sel viisil lagundamine muudab testimise lihtsamaks, eraldades selle ActiveRecord
-st mudelil ja sellel on madalam üldkulutus kui vaikemustril, mida Forem kasutas funktsionaalsuse laiendamisel.
See muster seisneb teie funktsionaalsuse jagamises Rails-muredeks ja konfiguratsioonipunkti paljastamisest nende lisamiseks või välistamiseks antud ulatusega. Sel viisil moodustatud mootor on lõppkasutajale mugav - Devise edu ja populaarsuse soodustav tegur. Ja nüüd teate ka, kuidas seda teha!
Spree
Ruby on Rails täielik avatud lähtekoodiga e-kaubanduse lahendus
Spree tegi tohutuid jõupingutusi, et viia oma monoliitne rakendus kontrolli alla, liikudes mootorite kasutamisele. Arhitektuurikujundus, millega nad nüüd veerevad, on Spree pärl, mis sisaldab palju mootori kalliskive.
Need mootorid loovad partitsioonid käitumises, mida võite olla harjunud nägema monoliitses rakenduses või jaotatud rakenduste vahel:
- spree_api (RESTful API)
- spree_frontend (kasutajatele suunatud komponendid)
- spree_backend (Administraatori ala)
- spree_cmd (käsurea tööriistad)
- spree_core (Mudelid ja postitajad, Spree põhikomponendid, ilma milleta see ei tööta)
- spree_sample (näidisandmed)
Hõlmav pärl ühendab need kokku, jättes arendajale valiku funktsionaalsuse taseme osas, mida nõuda. Näiteks võite käivitada ainult spree_core
Mootor ja keerake oma liides selle ümber.
Peamine Spree pärl nõuab neid mootoreid:
# lib/spree.rb require 'spree_core' require 'spree_api' require 'spree_backend' require 'spree_frontend'
Seejärel peab iga mootor kohandama oma engine_name
ja root
tee (viimased viitavad tavaliselt tipptasemel kalliskivile) ja konfigureerida ennast initsialiseerimise protsessi abil:
# api/lib/spree/api/engine.rb require 'rails/engine' module Spree module Api class Engine :load_config_initializers do |app| app.config.spree = Spree::Core::Environment.new end # ... end end end
Võite selle initsialiseerimismeetodi ära tunda või mitte: see on osa Railtie
ja on konks, mis annab teile võimaluse Rails raamistiku initsialiseerimisel lisada või eemaldada samme. Spree tugineb sellele konksule tugevalt, et seadistada oma kõigi mootorite jaoks keeruline keskkond.
Kasutades ülaltoodud näidet käitusajal, on teil juurdepääs oma seadetele, kui pääsete juurde ülemisele tasemele Rails
konstant:
Rails.application.config.spree
Selle ülaltoodud Railsi mootori kujunduse mustrijuhendi abil võiksime seda nimetada päevaks, kuid Spree'l on palju hämmastavat koodi, nii et uurime, kuidas nad kasutavad lähtestamist mootorite ja peamise rööparakenduse vahel konfiguratsiooni jagamiseks.
Spree'l on keeruline eelistuste süsteem, mille ta laadib, lisades initsialiseerimise sammu:
# api/lib/spree/api/engine.rb initializer 'spree.environment', :before => :load_config_initializers do |app| app.config.spree = Spree::Core::Environment.new end
Siin kinnitame app.config.spree
uus Spree::Core::Environment
näiteks. Rööparakenduses saate sellele juurde pääseda Rails.application.config.spree
kaudu kõikjalt - mudelid, kontrollerid, vaated.
Allapoole liikudes on Spree::Core::Environment
meie loodud klass näeb välja selline:
module Spree module Core class Environment attr_accessor :preferences def initialize @preferences = Spree::AppConfiguration.new end end end end
See paljastab :preferences
muutuja määrati Spree::AppConfiguration
uuele eksemplarile klass, mis omakorda kasutab a preference
meetodis määratletud Preferences::Configuration
klass, et määrata rakenduse üldkonfiguratsiooni vaikeseadetega suvandid:
kuidas kontoplaani luua
module Spree class AppConfiguration Ma ei näita Preferences::Configuration
faili, sest see vajab natuke selgitamist, kuid sisuliselt on see eelistuste hankimiseks ja seadistamiseks süntaktiline suhkur. (Tegelikult on see selle funktsionaalsuse liiga lihtsustamine, kuna eelistuste süsteem salvestab andmebaasi olemasolevate või uute eelistuste jaoks muud vaikeväärtused kui mis tahes ActiveRecord
klassi veerus :preference
- aga te ei pea seda teadma.)
Siin on üks nendest võimalustest.
module Spree class Calculator Kalkulaatorid kontrollivad Spree'is igasuguseid asju - saatmiskulusid, sooduspakkumisi, toote hinna korrigeerimisi -, nii et mehhanism nende sel viisil vahetamiseks suurendab mootori laiendatavust.
Nende eelistuste vaikeseadete alistamiseks on üks paljudest võimalustest Rails'i peamise rakenduse initsialiseerija:
# config/initializergs/spree.rb Spree::Config do |config| config.admin_interface_logo = 'company_logo.png' end
Kui olete läbi lugenud RailsGuide mootoritele , kaalusid nende kujundusmustreid või ehitasid ise mootori, teate, et on tühine paljastada initsiaatorifailis setter, et keegi seda saaks kasutada. Nii et võite mõelda, miks kogu seadistamise ja eelistuste süsteemiga kära? Pidage meeles, et eelistuste süsteem lahendab Spree domeeniprobleemi. Initsialiseerimisprotsessi haaramine ja Rails raamistikule juurdepääsu saamine võib aidata teil oma nõuetele hooldataval viisil vastata.
See mootori kujundusmudel keskendub raamide raamistiku kasutamisele konstandina paljude liikuvate osade vahel, et salvestada seadeid, mis käituse ajal (üldiselt) ei muutu, kuid rakenduste installide vahel muutuvad.
Kui olete kunagi proovinud valge silt Rails rakendus, võite olla tuttav selle eelistuste stsenaariumiga ja olete tundnud iga uue rakenduse pika häälestusprotsessi käigus keerdunud andmebaasi seadete tabelite valu. Nüüd teate, et on olemas teistsugune tee ja see on vinge - kõrge viis!
RafineerimistehasCMS
Konfiguratsiooni konventsioon keegi? Rööbaste mootorid võivad kindlasti tunduda kohati pigem konfiguratsiooniharjutusena, kuid RefineryCMS mäletab mõnda sellist Rööbaste maagiat. See on kogu selle lib
sisu kataloog:
# lib/refinerycms.rb require 'refinery/all' # lib/refinery/all.rb %w(core authentication dashboard images resources pages).each do |extension| require 'refinerycms-#{extension}' end
Vau. Kui te ei suuda seda öelda, teab rafineerimistehase meeskond tõesti, mida nad teevad. Nad veerevad mõistega extension
mis on sisuliselt teine Mootor. Nagu Spree'il, on ka sellel kõikehõlmav õmbluspärl, kuid see kasutab ainult kahte õmblust ja koondab mootorite kogu, et pakkuda täielikku funktsionaalsust.
Laiendusi loovad ka Mootori kasutajad, et luua oma CMS-i funktsioonide ajaveebi, uudiste, portfellide, iseloomustuste, päringute jms jaoks (see on pikk nimekiri), mis kõik haakuvad RefineryCMSi tuumikuga.
See disain võib teie modulaarse lähenemise tõttu teie tähelepanu pälvida ja rafineerimistehas on selle Railsi kujundusmustri suurepärane näide. 'Kuidas see töötab?' Ma kuulen, kuidas sa küsid.
core
mootor kaardistab mõned konksud teiste mootorite jaoks kasutamiseks:
# core/lib/refinery/engine.rb module Refinery module Engine def after_inclusion(&block) if block && block.respond_to?(:call) after_inclusion_procs << block else raise 'Anything added to be called after_inclusion must be callable (respond to #call).' end end def before_inclusion(&block) if block && block.respond_to?(:call) before_inclusion_procs << block else raise 'Anything added to be called before_inclusion must be callable (respond to #call).' end end private def after_inclusion_procs @@after_inclusion_procs ||= [] end def before_inclusion_procs @@before_inclusion_procs ||= [] end end end
Nagu näete before_inclusion
ja after_inclusion
lihtsalt salvestage loend protsessidest, mida käivitatakse hiljem. Rafineerimistehase kaasamisprotsess laiendab praegu laaditud Rails-rakendusi rafineerimistehaste kontrollerite ja abimeestega. Siin on üks tegevuses:
# authentication/lib/refinery/authentication/engine.rb before_inclusion do [Refinery::AdminController, ::ApplicationController].each do |c| Refinery.include_once(c, Refinery::AuthenticatedSystem) end end
Olen kindel, et olete oma ApplicationController
i sisestanud autentimismeetodid ja AdminController
enne on see programmiline viis seda teha.
veebipakk sisaldab sõlme_mooduleid
Selle ülejäänud autentimismootori faili vaatamine aitab meil kokku saada veel mõned põhikomponendid:
module Refinery module Authentication class Engine <::Rails::Engine extend Refinery::Engine isolate_namespace Refinery engine_name :refinery_authentication config.autoload_paths += %W( #{config.root}/lib ) initializer 'register refinery_user plugin' do Refinery::Plugin.register do |plugin| plugin.pathname = root plugin.name = 'refinery_users' plugin.menu_match = %r{refinery/users$} plugin.url = proc { Refinery::Core::Engine.routes.url_helpers.admin_users_path } end end end config.after_initialize do Refinery.register_extension(Refinery::Authentication) end # ... end end
Kapoti all on rafineerimistehaste laiendites tähis Plugin
süsteemi. initializer
samm näeb Spree koodi analüüsist tuttav ette, siin olid alles kohtumised register
meetodite nõuded, mis lisatakse Refinery::Plugins
loendisse et core
laiendus jälgib ja Refinery.register_extension
lihtsalt lisab mooduli nime klassi juurdepääsuprogrammi salvestatud loendisse.
Siin on šokk: the Refinery::Authentication
klass on tõesti Devise'i ümbris, mõningate kohandustega. Nii et see on kilpkonnad kogu tee!
Laiendused ja pistikprogrammid on kontseptsioonid, mida rafineerimistehas on välja töötanud, et toetada nende rikkalikku minirööpaste rakenduste ja tööriistade ökosüsteemi - mõtle rake generate refinery:engine
Siinne disainimuster erineb Spree'st, kehtestades Rails Mootori ümber täiendava API, mis aitab nende koostist hallata.
Rööbastee kõnekäänd on rafineerimistehase keskmes ja seda rohkem nende mini-rööpade rakendustes esineb, kuid väljastpoolt te seda ei tea. Piiride kujundamine rakenduse koostise tasemel on sama oluline, võib-olla veelgi olulisem, kui puhta API loomine oma Rails-rakendustes kasutatavate klasside ja moodulite jaoks.
Koodi pakkimine, mille üle teil pole otsest kontrolli, on tavaline muster, see on ettenägelik hoolduse aja lühendamiseks, kui see kood muutub, piirates nende kohtade arvu, mida peate täienduste tegemiseks muutma. Selle tehnika rakendamine koos jaotamise funktsionaalsusega loob paindliku platvormi kompositsiooniks ja siin on reaalse maailma näide, mis istub otse teie nina all - peate armastama avatud lähtekoodiga!
Järeldus
Railssi mootorimustrite kujundamiseks oleme näinud nelja lähenemisviisi, analüüsides populaarseid kalliskive, mida kasutatakse reaalsetes rakendustes. Tasub lugeda nende hoidlatest, et õppida juba rakendatud ja kordatud kogemustest. Seisa hiiglaste õlgadel.
Selles Rails-juhendis oleme keskendunud rööpmootorite ja nende lõppkasutajate Rails-rakenduste integreerimise kujundusmudelitele ja -tehnikatele, et saaksite nende teadmisi oma Rööbaste tööriistavöö .
Loodan, et olete selle koodi ülevaatamisest õppinud nii palju kui mina ja tunnete inspiratsiooni anda Rails Motorsi jaoks võimalus, kui see sobib arvega. Suur aitäh hooldajatele ja kaasaaitajatele kalliskividest, mida vaatasime. Suurepärased inimesed!
Seotud: Ajatempli kärpimine: Ruby on Rails ActiveRecord Tale