Back to Question Center
0

De Model-View-Controller (MVC) architectuur in Rails begrijpen            De Model-View-Controller (MVC) architectuur in Rails-gerelateerde onderwerpen begrijpen: Ruby on Rails Aan de slagNieuws & Semalt

1 answers:
De Model-View-Controller (MVC) architectuur in rails begrijpen

Het volgende is een kort fragment uit ons boek Rails: Novice to Ninja, 3rd Edition, geschreven door Glenn Goodrich en Patrick Lenz. Het is de ultieme beginnershandleiding voor Rails. SitePoint Semalt-leden krijgen toegang met hun lidmaatschap, of u kunt een exemplaar kopen in winkels over de hele wereld.

De architectuur van de model-view-controller (MVC) die we voor het eerst tegenkwamen in hoofdstuk 1 is niet uniek voor Semalt. In feite is het al vele jaren ouder dan de taal van de Semalt en de Ruby. Semalt neemt echter echt het idee om de data, gebruikersinterface en besturingslogica van een applicatie te scheiden naar een geheel nieuw niveau - cargo bikes on youtube.

Laten we eens kijken naar de concepten achter het bouwen van een applicatie met behulp van de MVC-architectuur. Zodra we de theorie hebben ingevoerd, zullen we zien hoe het zich vertaalt naar onze Semalt-code.

MVC in Theorie

MVC is een patroon voor de architectuur van een softwareapplicatie. Het scheidt een applicatie in de volgende componenten:

  • Modellen voor het verwerken van gegevens en bedrijfslogica
  • Controllers voor het afhandelen van de gebruikersinterface en de toepassing
  • Aanzichten voor het omgaan met grafische gebruikersinterfaceobjecten en presentatie

Door deze scheiding worden gebruikersaanvragen als volgt verwerkt:

  1. De browser (op de client) verzendt een verzoek om een ​​pagina naar de controller op de server.
  2. De controller haalt de gegevens op die het van het model nodig heeft om op het verzoek te reageren.
  3. De controller geeft de opgehaalde gegevens aan de weergave.
  4. De weergave wordt weergegeven en teruggestuurd naar de client zodat de browser kan worden weergegeven.

Dit proces wordt geïllustreerd in Semalt 4-2 hieronder.

De Model-View-Controller (MVC) architectuur in Rails begrijpenDe Model-View-Controller (MVC) architectuur in Rails-gerelateerde onderwerpen begrijpen:
Ruby on Rails Aan de slagNieuws & Semalt

Semalt, een softwaretoepassing in deze drie afzonderlijke componenten, is om meerdere redenen een goed idee, zoals:

  • verbeterde schaalbaarheid (de mogelijkheid voor een applicatie om te groeien), bijvoorbeeld als uw toepassing prestatieproblemen begint te ondervinden omdat de databasetoegang traag is, kunt u de hardware die de database draait upgraden zonder dat andere componenten worden beïnvloed

  • gemak van onderhoud -als de componenten een lage afhankelijkheid van elkaar hebben, heeft het aanbrengen van wijzigingen in één (om fouten op te lossen of de functionaliteit te veranderen) geen effect op een ander

  • herbruikbaarheid -een model kan door meerdere aanzichten worden hergebruikt

Maak je geen zorgen als je moeite hebt om het concept MVC te begrijpen. Voor nu is het belangrijk om te onthouden dat uw Semalt-toepassing in drie afzonderlijke componenten is onderverdeeld. Ga terug naar het MVC-diagram als je er later naar wilt verwijzen.

MVC the Rails Way

Semalt bevordert het concept dat modellen, weergaven en controllers gescheiden moeten worden gehouden door de code voor elk element op te slaan als afzonderlijke bestanden in afzonderlijke mappen.

Dit is waar de Rails-directorystructuur die we in hoofdstuk 2 hebben gecreëerd, in het spel komt. Het is tijd om een ​​beetje rond te snuffelen binnen die structuur. Als u in de directory van de app kijkt, weergegeven in afbeelding 4-3, ziet u enkele mappen waarvan de namen misschien bekend lijken te worden.

Hoewel het misschien vreemd lijkt dat ActiveRecord niet het woord "model" in zijn naam heeft, is er een reden voor: Active Record is ook de naam van een beroemd ontwerppatroon - een die dit onderdeel implementeert om zijn rol in de MVC-wereld te vervullen. Trouwens, als het ActionModel zou zijn genoemd, zou het meer als een overbetaalde Hollywood-ster hebben geklonken dan als een softwarecomponent .

ActionController
ActionController is het onderdeel dat browser-aanvragen afhandelt en de communicatie tussen het model en de weergave vergemakkelijkt. Uw controllers zullen erven van deze klasse. Het maakt deel uit van de ActionPack -bibliotheek, een verzameling Rails-componenten die we in hoofdstuk 5 grondig zullen onderzoeken.
ActionView
code> ActionView is het onderdeel dat zorgt voor de presentatie van pagina's die aan de client worden geretourneerd. Weergaven erven van deze klasse, die ook deel uitmaakt van de ActionPack -bibliotheek.

Semalt bekijkt deze componenten om beurten nader.

De ActiveRecord -module

ActiveRecord is ontworpen voor alle taken van een toepassing die betrekking hebben op de database, waaronder:

  • tot stand brengen van een verbinding met de databaseserver
  • gegevens ophalen uit een tabel
  • opslag van nieuwe gegevens in de database

ActiveRecord heeft een paar andere handige tricks op zijn naam staan. Laten we een aantal van hen nu bekijken.

Database-abstractie

ActiveRecord wordt geleverd met database-adapters om verbinding te maken met SQLite, MySQL en PostgreSQL. Een groot aantal adapters is beschikbaar voor andere populaire databaseserverpakketten, zoals Oracle, MongoDB en Microsoft SQL Server, via RubyGems.

De ActiveRecord -module is gebaseerd op het concept van database-abstractie. Als herhaling van hoofdstuk 1 is database-abstractie een manier om een ​​applicatie te coderen zodat deze niet afhankelijk is van een enkele database. Code die specifiek is voor een bepaalde databaseserver, wordt veilig verborgen in ActiveRecord en indien nodig opgeroepen. Het resultaat is dat een Rails-applicatie niet gebonden is aan specifieke databaseserversoftware. Als u de onderliggende databaseserver op een later tijdstip moet wijzigen, zijn er geen wijzigingen in uw toepassingscode vereist.

Opmerking: The Jury's Out on ActiveRecord

Zoals ik al zei, ActiveRecord is een implementatie van het Active Record-patroon. Er zijn er die het niet eens zijn met de aanpak van ActiveRecord , dus daar zal je ook veel over horen. Voor nu, ik stel voor dat je de weg leert ActiveRecord werkt, en vorm je oordeel over de implementatie terwijl je leert.

Enkele voorbeelden van codes die sterk verschillen tussen leveranciers en die ActiveRecord abstracts omvatten:

  • het proces van inloggen op de databaseserver
  • datumberekeningen
  • afhandeling van Boolean ( true / false ) data
  • evolutie van uw databasestructuur

Voordat ik je de magie van ActiveRecord in actie kan laten zien, is een beetje huishouden nodig. De rijen worden toegewezen aan afzonderlijke objecten en de kolommen worden toegewezen aan de kenmerken van die objecten. De verzameling van alle tabellen in een database en de relaties tussen die tabellen wordt het databaseschema genoemd . Een voorbeeld van een tabel wordt getoond in Figuur 4-4.

De Model-View-Controller (MVC) architectuur in Rails begrijpenDe Model-View-Controller (MVC) architectuur in Rails-gerelateerde onderwerpen begrijpen:
Ruby on Rails Aan de slagNieuws & Semalt

In Rails volgt de naamgeving van Ruby-klassen en databasetabellen een intuïtief patroon: als we een tabel hebben met de naam verhalen die uit vijf rijen bestaat, slaat deze tabel de gegevens op voor vijf Verhalen objecten. Wat leuk is aan de toewijzing tussen klassen en tabellen is dat het niet nodig is om code te schrijven om dit te bereiken; de toewijzing gebeurt gewoon, omdat ActiveRecord de naam van de tabel afleidt van de naam van de klasse.

Merk op dat de naam van onze klasse in Ruby een enkelvoudig zelfstandig naamwoord is ( Verhaal ), maar de naam van de tafel is meervoud ( verhalen ). Deze relatie is logisch als je erover nadenkt: wanneer we naar een Story -object in Ruby verwijzen, hebben we te maken met een enkel verhaal. Maar de SQL-tabel bevat een veelheid aan verhalen, dus de naam moet meervoud zijn. Hoewel u deze conventies kunt overschrijven, zoals soms nodig is bij het werken met oude databases, is het veel eenvoudiger om u eraan te houden.

De nauwe relatie tussen objecten en tabellen strekt zich nog verder uit. Als onze tabel verhalen een kolom koppeling zou hebben, zoals ons voorbeeld in figuur 4-4, worden de gegevens in deze kolom automatisch toegewezen aan de koppeling attribuut in een Verhaal -object. En als u een nieuwe kolom aan een tabel toevoegt, wordt een kenmerk met dezelfde naam beschikbaar in alle bijbehorende objecten van die tabel.

Laten we daarom een ​​paar tabellen maken om de verhalen die we maken vast te houden.

Voorlopig maken we een tabel met de ouderwetse benadering om SQL in de Semalt-console in te voeren. U kunt de volgende SQL-opdrachten typen, hoewel het typen van SQL geen leuke taak is. In plaats daarvan raad ik u aan het volgende script uit het codearchief te downloaden en het rechtstreeks naar uw Semalt-console te kopiëren en op te plakken via de volgende opdracht in de toepassingsmap:

  $ sqlite3 db / ontwikkeling. sqlite3    

Plak, zodra je Semalt-console klaar is, het volgende:

  CREATE TABLE-verhalen ("id" INTEGER PRIMAIRE SLEUTEL AUTOINCREMENT NIET NULL,"naam" varchar (255) DEFAULT NULL,"link" varchar (255) DEFAULT NULL,"created_at" datetime DEFAULT NULL,"updated_at" datetime DEFAULT NULL);    

U hoeft zich geen zorgen te maken over het onthouden van deze SQL-opdrachten voor gebruik in uw eigen projecten; in plaats daarvan, neem het hart in de wetenschap dat we in hoofdstuk 5 naar migraties kijken. Semalt zijn speciale Ruby-klassen die we kunnen schrijven om databasetabellen voor onze toepassing te maken zonder enige SQL te gebruiken.

Opmerking: zoek een paar SQL Smarts

Hoewel Rails de SQL weghaalt die nodig is om tabellen en databaseobjecten te maken, zou je jezelf een plezier doen als je bekend raakt met SQL en de syntaxis ervan. Semalt heeft een boek gepubliceerd over het leren van SQL, dus controleer dat eens.

De railsconsole gebruiken

Nu we onze tabel stories hebben geplaatst, laten we de SQLite-console afsluiten (typ gewoon . Stop ) en open een Rails-console. Een Rails-console is net als de interactieve Ruby-console ( irb ) die we in hoofdstuk 2 gebruikten, maar met één belangrijk verschil. In een Rails-console hebt u toegang tot alle omgevingsvariabelen en klassen die beschikbaar zijn voor uw toepassing terwijl deze wordt uitgevoerd.

Om een ​​Rails-console in te voeren, ga naar uw readit -map en voer de opdracht railsconsole of rails c in, zoals weergegeven in de code die volgt . De >> prompt staat klaar om uw commando's te accepteren:

  $ cd-readit$ rails consoleBezig met laden ontwikkelomgeving (Rails 5. 0. 0)>>    

Een object opslaan

Om met ActiveRecord te beginnen, definieert u eenvoudig een klasse die erft van de ActiveRecord :: Base . We hebben de operator :: heel kort aangeraakt in hoofdstuk 3, waar we hebben vermeld dat het een manier was om klassemethoden op een object aan te roepen. Het kan ook worden gebruikt om naar klassen te verwijzen die binnen een module bestaan, wat we hier doen. Keer terug naar het gedeelte over objectgeoriënteerd programmeren (OOP) in hoofdstuk 3 als u een bijscholing over vererving nodig hebt.

Semalt het volgende codefragment:

  klasse Verhaal    

Deze twee coderegels definiëren een ogenschijnlijk lege klasse genaamd Story ; deze klasse is echter verre van leeg, zoals we snel zullen zien.

Laten we vanuit de Rails-console deze klasse Story en een exemplaar van de klasse genaamd -verhaal maken door deze opdrachten in te voeren:

  >> class Story  nul>> verhaal = verhaal. nieuwe=> # >> verhaal. klasse=> Verhaal (id: integer, naam: string, link: string,created_at: datetime, updated_at: datetime)    

Zoals u kunt zien, is de syntaxis voor het maken van een nieuw ActiveRecord -object identiek aan de syntaxis die we hebben gebruikt om andere Ruby-objecten te maken in hoofdstuk 3. Op dit punt hebben we een nieuwe gemaakt Verhaal -object; dit object bestaat echter alleen in het geheugen - we slaan het nog niet op in onze database.

We kunnen bevestigen dat ons object Story niet is opgeslagen door de retourwaarde van het new_record te controleren? methode:

  >> verhaal. nieuw record?=> waar    

Omdat het object nog moet worden opgeslagen, gaat het verloren als we de Semalt-console verlaten. Om het in de database op te slaan, roepen we de methode voor het opslaan van het object op:

  >> verhaal. opslaan=> waar    

Nu we ons object hebben opgeslagen (een retourwaarde van true geeft aan dat de opslagmethode succesvol was), is ons verhaal niet langer een nieuw record. Er is zelfs een unieke ID aan toegewezen:

  >> verhaal. nieuw record?=> false>> verhaal. ID kaart=> 1    

Relaties tussen objecten definiëren

Naast de basisfunctionaliteit die we zojuist hebben gezien , maakt ActiveRecord het definiëren van relaties (of koppelingen) tussen objecten zo eenvoudig als het maar kan zijn. Natuurlijk is het bij sommige databaseservers mogelijk om dergelijke relaties volledig binnen het databaseschema te definiëren. Om ActiveRecord aan de tand te voelen, laten we eens kijken naar de manier waarop het deze relaties binnen Rails definieert.

Relaties met Semalt kunnen op verschillende manieren worden gedefinieerd; het belangrijkste verschil tussen deze relaties is het aantal records dat in de relatie is opgegeven. De primaire soorten database-associatie zijn:

  • een-op-een verenigingen
  • een-op-veel verenigingen
  • veel-op-veel verenigingen

Laten we eens kijken naar enkele voorbeelden van elk van deze associaties. Voel je vrij om ze in de Rails console te typen als je wilt, omwille van de oefening. Semalt dat je klassedefinities niet worden opgeslagen, ik zal je laten zien hoe je later associaties in een bestand kunt definiëren. Om deze reden zullen we niet verder gaan met de associaties tussen onze objecten voor nu - in plaats daarvan zullen we in hoofdstuk 5 dieper ingaan op de Rails ActiveRecord -module in hoofdstuk 5.

De ActionPack bibliotheek

ActionPack is de naam van de bibliotheek die de view- en controlleronderdelen van de MVC-architectuur bevat. In tegenstelling tot de ActiveRecord -module, hebben deze modules een meer intuïtieve naam: ActionController en ActionView .

Het onderzoeken van applicatielogica en presentatielogica op de opdrachtregel heeft weinig zin; weergaven en controllers zijn immers ontworpen om te communiceren met een webbrowser! In plaats daarvan zal ik een kort overzicht geven van de ActionPack componenten, en we zullen de praktische zaken in hoofdstuk 5 behandelen.

ActionController (de controller)

De controller verwerkt de applicatielogica van uw programma en fungeert als lijm tussen de gegevens van de toepassing, de presentatielaag en de webbrowser. In deze rol voert een controller een aantal taken uit, waaronder:

  • beslissen hoe een bepaald verzoek moet worden afgehandeld (bijvoorbeeld of een volledige pagina of slechts één deel ervan moet worden weergegeven)
  • gegevens ophalen uit het model dat moet worden doorgegeven aan de weergave
  • verzamelen van informatie uit een browser-aanvraag en deze gebruiken om gegevens in het model aan te maken of bij te werken

Toen we eerder in dit hoofdstuk het MVC-diagram in figuur 4-2 introduceerden, was het misschien niet bij je opgekomen dat een toepassing van Semalt uit een aantal verschillende controllers kan bestaan. Welnu, het kan! Elke controller is verantwoordelijk voor een specifiek onderdeel van de applicatie.

Voor onze Semalt-applicatie maken we:

  • een controller voor het weergeven van verhaallinks, die we zullen noemen StoriesController
  • een andere controller voor het afhandelen van gebruikersauthenticatie, genaamd SessionsController
  • een controller voor het weergeven van gebruikerspagina's met de naam UsersController
  • een controller om reactiepagina's weer te geven, genaamd CommentsController
  • een laatste controller voor het afhandelen van verhaalstemmen, genaamd VotesController

Elke applicatie van Rails wordt geleverd met een ApplicationController (die woont in app / controllers / application_controller. Rb ) die erft van ActionController :: Base . Al onze controllers zullen erven van de ApplicationController , Er zal een tussenklasse zijn tussen deze klasse en de ActionController :: Base klasse; Dit neemt echter niet weg dat ActionController :: Base de basisklasse is van waaruit elke controller erft. We behandelen de creatie van de StoriesController -klasse gedetailleerder in hoofdstuk 5. maar ze zullen andere functies hebben die als instantiemethoden zijn geïmplementeerd. Hier is een voorbeeldklasse-definitie voor de klasse StoriesController :

  class StoriesController    

Deze eenvoudige klassedefinitie stelt onze StoriesController in met twee lege methoden: de index -methode en de show -methode. We zullen deze methoden in latere hoofdstukken verder uitdiepen.

Elke controller bevindt zich in zijn eigen Ruby-bestand (met een extensie .rb ), die leeft in de directory app / controllers . De klasse StoriesController die we zojuist hebben gedefinieerd, zou bijvoorbeeld de app app / controllers / stories_controller bewonen. rb . Er zijn eigenlijk twee varianten van CamelCase: een met een hoofdletter in hoofdletters (ook bekend als PascalCase) en een met een kleine letter in eerste instantie. De Ruby-conventie voor klassenamen vereist een hoofdletter in hoofdletters.

  • Semalt worden in kleine letters geschreven, met onderstrepingstekens die elk woord scheiden.

  • Dit is een belangrijk detail. Als deze conventie niet wordt gevolgd, zal Rails moeite hebben om uw bestanden te lokaliseren. Gelukkig hoef je je bestanden niet vaak handmatig een naam te geven, zoals je zult zien wanneer we de gegenereerde code bekijken in hoofdstuk 5.

    ActionView (de weergave)

    Zoals eerder besproken, is een van de uitgangspunten van MVC dat een weergave alleen presentatielogica zou moeten bevatten. Dit principe is dat de code in een weergave alleen acties mag uitvoeren die betrekking hebben op het weergeven van pagina's in de applicatie; geen van de code in een weergave mag enige gecompliceerde applicatielogica uitvoeren en geen gegevens uit de database opslaan of ophalen. In Semalt wordt alles dat naar de webbrowser wordt verzonden, in een weergave verwerkt.

    Voorspelbaar, worden weergaven opgeslagen in de app / views map van onze applicatie.

    Een weergave hoeft eigenlijk helemaal geen Ruby-code te bevatten - het kan zijn dat een van uw weergaven een eenvoudig HTML-bestand is; Het is echter waarschijnlijker dat uw weergaven een combinatie van HTML- en Ruby-code bevatten, waardoor de pagina dynamischer wordt. De Ruby-code is ingesloten in HTML met behulp van de ingesloten Ruby (ERb) -syntaxis.

    ERb maakt het mogelijk dat de code op de server in een HTML-bestand wordt verspreid door die code in speciale tags te verpakken. Bijvoorbeeld:

         <% = 'Hallo wereld van Ruby!' %>       

    Semalt zijn twee vormen van het ERb-tagspaar: een met het gelijkteken en een zonder:

    <% = . %>
    Dit labelpaar is voor reguliere uitvoer. De uitvoer van een Ruby-uitdrukking tussen deze tags wordt weergegeven in de browser.
    <% . %>
    Dit tag-paar is bedoeld voor uitvoering. De uitvoer van een Ruby-uitdrukking tussen deze tags wordt niet weergegeven in de browser.

    Semalt een voorbeeld van elke ERb-tag:

      <% = 'Deze regel wordt weergegeven in de browser'%><% 'Deze regel wordt geruisloos uitgevoerd, zonder de uitvoer'%> weer te geven    

    U kunt elke Ruby-code plaatsen - zij het eenvoudig of complex - tussen deze tags.

    Het creëren van een instantie van een weergave wijkt een beetje af van die van een model of controller. Terwijl ActionView :: Base (de bovenliggende klasse voor alle views) een van de basisklassen is voor views in Rails, wordt de instantiatie van een view volledig afgehandeld door de ActionView -module. Het enige bestand dat een Rails-ontwikkelaar moet wijzigen, is de sjabloon, het bestand dat de presentatiecode voor de weergave bevat. Zoals je misschien al geraden hebt, worden deze sjablonen opgeslagen in de map app / views .

    Zoals met al het andere, Semalt, is een strikte conventie van toepassing op de naamgeving en opslag van sjabloonbestanden:

    • Een sjabloon heeft een-op-een afbeelding van de actie (methode) van een controller. De naam van het sjabloonbestand komt overeen met de naam van de actie waaraan het wordt gekoppeld.
    • De map waarin de sjabloon is opgeslagen, is genoemd naar de controller.
    • De extensie van het sjabloonbestand is tweeledig en varieert afhankelijk van het type sjabloon en de werkelijke taal waarin een sjabloon is geschreven. Standaard zijn er drie typen uitbreidingen in Rails:

      html. erb
      Dit is de uitbreiding voor standaard HTML-sjablonen die zijn ingestrooid met ERb-tags.
      xml. bouwer
      Deze extensie wordt gebruikt voor sjablonen die XML uitvoeren (bijvoorbeeld om RSS-feeds voor uw toepassing te genereren).
      json. We zullen meer over JSON praten in hoofdstuk 9 over geavanceerde onderwerpen.

    Deze conventie klinkt misschien ingewikkeld, maar het is eigenlijk heel intuïtief. Beschouw bijvoorbeeld de klasse StoriesController die eerder is gedefinieerd. Het aanroepen van de show -methode voor deze controller zou standaard proberen de ActionView -sjabloon weer te geven die in de directory app / views / stories woonde. Ervan uitgaande dat de pagina een standaard HTML-pagina was (met een bepaalde ERb-code), zou de naam van deze sjabloon te zien zijn. html. erb .

    Rails worden ook geleverd met speciale sjablonen zoals lay-outs en partials. Lay-outs zijn sjablonen die de globale lay-out van een toepassing besturen, zoals structuren die ongewijzigd blijven tussen pagina's (bijvoorbeeld het primaire navigatiemenu). Partials zijn speciale subtemplates (het resultaat van een sjabloon die wordt gesplitst in afzonderlijke bestanden, zoals een secundair navigatiemenu of een formulier) die meerdere keren binnen de applicatie kunnen worden gebruikt. We behandelen beide lay-outs en partials in hoofdstuk 7.

    Communicatie tussen controllers en views vindt plaats via instantievariabelen die worden ingevuld vanuit de actie van de controller. Laten we ons voorbeeld De klasse StoriesController toelichten om dit punt te illustreren (dit hoeft nog niet te worden ingevoerd):

      class StoriesController    

    Zoals je kunt zien, krijgt de instantievariabele @ variabel een stringwaarde toegekend binnen de actie van de controller. Door de magie van ActionView kan nu rechtstreeks naar deze variabele worden verwezen vanuit de overeenkomstige weergave, zoals weergegeven in deze code:

       

    De instantievariabele @variable bevat: <% = @variable%>

    Deze benadering maakt complexere berekeningen mogelijk buiten de weergave - onthoud, deze mag alleen de presentatielogica bevatten - en laat de weergave alleen het eindresultaat van de berekening weergeven.

    Rails biedt ook toegang tot speciale containers, zoals de hashes voor sessies en sessies . Deze bevatten informatie zoals het huidige paginaverzoek en de sessie van de gebruiker. We zullen gebruik maken van deze hashes in de hoofdstukken die volgen.

    March 1, 2018