Om in het verleden een webtoepassing te bouwen, had u de vaardigheden nodig om in uw bedrijfslogica en uw databasetaal te coderen. Meer recentelijk neigen back-end frameworks echter naar het gebruik van Object-Relational Mapping (ORM); dit is een techniek waarmee u uw database kunt beheren in de zakelijke logische taal waarmee u het meest vertrouwd bent.
Rails gebruikt een ORM in de vorm van Active Record. In deze zelfstudie duiken we in Active Record en kijken we wat het voor ons kan doen!
Zoals ik al zei, Active Record is een ORM. Dit betekent dat het een laag van Ruby-code is die tussen uw database en uw logische code loopt. Wanneer u wijzigingen in de database moet aanbrengen, schrijft u de Ruby-code en voert u vervolgens migraties uit, die we binnenkort zullen beoordelen. Deze migraties maken de feitelijke wijzigingen in de database. Het leuke is dat het niet uitmaakt welke database je gebruikt: Rails kunnen vrijwel alles aan. Rails gebruikt bijvoorbeeld SQLite lokaal tijdens het ontwikkelen. Laten we echter stellen dat u werkt aan Heroku, die PostreSQL gebruikt. Het enige wat je hoeft te doen is dit aan je toevoegen Gemfile
:
groep: productie doe edel 'pg' einde
Nu, wanneer u implementeert, zal Heroku diezelfde migraties uitvoeren (met behulp van de PostgreSQL-adapter). Dezelfde code, andere database, wat best cool is, naar mijn mening.
Dus dat is wat Active Record is; laten we dieper graven en kijken hoe het allemaal werkt.
Hoewel het technisch mogelijk is om Active Record buiten een Rails-app te gebruiken, zult u het negen keer op tien gebruiken binnen een Rails-app, dus dat is wat we hier zullen doen. Ik gebruik Rails 3.2.12, de nieuwste versie terwijl ik dit typ. Als je dat hebt geïnstalleerd, kun je beginnen met het maken van een nieuwe Rails-app.
rails nieuwe myapp cd myapp
Nu kunnen we beginnen met het maken van een model.
Zoals je zou verwachten, omdat Active Record samenwerkt met de database, is het de M in MVC van Rails: modellen. Vanaf de opdrachtregel maken we een model voor bijvoorbeeld een persoon. Eigenlijk, de rails genereren
opdracht is vrij flexibel: alle volgende opdrachten werken:
rails genereren model Persoon rails g model Persoon rails g model Persoon first_name last_name age: integer
De eerste twee regels hier doen hetzelfde; rails g
is gewoon een snelkoppeling voor rails genereren
. De derde geeft Rails een beetje meer informatie, zodat het wat meer werk voor ons kan doen. We zeggen dat we willen dat dit model drie velden heeft: Voornaam
, achternaam
, en leeftijd
. Voor Voornaam
en achternaam
, we specificeren geen type, dus het is standaard een string. Voor leeftijd
, we zeggen dat het een geheel getal moet zijn.
Wat doet dit eigenlijk? Je zou wat output moeten zien, dat uit te leggen. De belangrijke dingen zijn dit:
create db / migrate / 20130213204626_create_people.rb create app / models / person.rb
Het eerste bestand is uw migratiebestand (de tijdstempel zal natuurlijk anders zijn); de tweede is jouw Ruby-klasse.
U moet vertrouwd zijn met de syntaxis van het migratiebestand, omdat u de code vaak wilt aanpassen. Laten we het bekijken.
klasse CreatePeople < ActiveRecord::Migration def change create_table :people do |t| t.string :first_name t.string :last_name t.integer :age [ruby] t.timestamps end end end
Elke migratie is een klasse; deze heeft een enkele methode: verandering
. Als u bekend bent met Ruby, zou dit vrij duidelijk moeten zijn: deze migratie maakt een tabel met de naam "mensen" in de database. Deze tabel heeft zes kolommen. Dat klopt, zes. Daar is de Voornaam
, achternaam
, en leeftijd
velden die we hebben toegevoegd vanaf de opdrachtregel; in de create_table
blokkeren gebruiken we methoden die genoemd zijn naar het gegevenstype en geven ze een symbool door met de kolomnaam.
Dan is er t.timestamps
. Dit creëert nog twee kolommen in onze tabel: gemaakt bij
en updated_at
. Natuurlijk zijn deze van het type datum Tijd
(later meer over uw type-opties). Active Record zorgt voor deze velden gedurende de levensduur van uw records, stelt ze in en past ze indien nodig aan.
De zesde en laatste kolom is ID kaart
, die hier niet wordt vermeld omdat deze standaard is toegevoegd. Dat is de unieke primaire sleutel voor de tafel.
Het maken van tabellen is slechts één gebruik voor een migratieklasse; ze zijn je methode om de database aan te passen, onthoud, zodat ze elke databaseopdracht kunnen doen die je ooit zou kunnen doen. Maar een van de belangrijke ideeën met migraties is dat je ze kunt terugdraaien of hun effecten ongedaan kunt maken. Dit betekent dat elke migratieklasse voldoende informatie moet hebben om de effecten ongedaan te maken. Verschillende methoden kunnen "zichzelf ongedaan maken"; Het tegenovergestelde van het toevoegen van een tabel is bijvoorbeeld het verwijderen ervan, wat geen extra informatie vereist. Dit is de reden waarom we de verandering
methode hier. Als we echter iets doen dat niet automatisch ongedaan kan worden gemaakt, moeten we de acties specificeren voor het doen en ongedaan maken van onze migratie. In deze gevallen moet onze migratieklasse twee methoden hebben: omhoog
en naar beneden
. De omhoog
methode zal gedetailleerd beschrijven wat te doen bij het uitvoeren van de migratie, en de naar beneden
methode zal uitleggen hoe de migratie teruggedraaid kan worden.
Laten we onze eigen migratie helemaal opnieuw schrijven om deze rollback-functie eens te proberen. We beginnen met het genereren van een lege migratie:
rails g migratie do_stuff
(Normaal gesproken geeft u uw migratie een verstandige naam.)
Nu kunnen we openen db / migrate /
. Het zal de omhoog
/naar beneden
standaardmethoden, maar doe het en vervang dat met een single verandering
methode.
klasse DoStuff < ActiveRecord::Migration def change create_table :nothing do |t| t.string :blank end [ruby] add_column :people, :job, :string end end
We beginnen met het maken van een nutteloze tabel, met dezelfde syntaxis als de tabel hierboven. Vervolgens gebruiken we de add_column
methode om een kolom aan de persoonentabel toe te voegen: specifiek, a baan
kolom van het type string. Beide acties kunnen eenvoudig ongedaan worden gemaakt door de tabel te verwijderen en de kolom te verwijderen.
Laten we nu onze twee migraties uitvoeren. We doen dit via een rake-taak:
rake db: migreren
Je zou de uitvoer als volgt moeten zien:
== CreatePeople: migrating ===================== - create_table (: people) -> 0.0027s == CreatePeople: gemigreerd (0.0034s) ==== ======== == DoStuff: migrating ========================== - create_table (: niets) -> 0.0014s - add_column (: people,: job,: string) -> 0.0008s == DoStuff: gemigreerd (0.0037s) =================
Je kunt aan de output precies zien wat er is gedaan. De eerste migratie heeft de mensen
tafel; de tweede creëerde het niets
tabel en de kolom toegevoegd. Laten we nu de laatste migratie ongedaan maken die we hebben uitgevoerd. We kunnen dit doen door het volgende uit te voeren:
rake db: terugdraaien
Nogmaals, de uitvoer bevestigt:
== DoStuff: reverting ========================== - remove_column ("people",: job) -> 0.0134s - drop_table ( "nothing") -> 0.0004s == DoStuff: teruggezet (0.0140s) =================
En nu is de migratie die we van nul hebben geschreven ongedaan gemaakt.
Een belangrijke opmerking hier: als u nog relatief onbekend bent met Rails, vergeet u misschien dat migraties niet automatisch worden uitgevoerd wanneer u een nieuw model maakt. Je moet ze handmatig uitvoeren. Ja, ik ben dit mijn redelijk aantal keren vergeten en vroeg me af wat er aan de hand was, alleen om te beseffen dat de tafel waarmee ik probeerde te werken nog niet eens bestond.
behalve create_table
en add_column
, er zijn een heleboel andere methoden die je in je migratiebestanden kunt gebruiken. In deze zelfstudie kunnen we niet alles bespreken, maar als ze eruit zien als iets dat u nodig heeft, bekijkt u de migratiedocumenten.
add_column
add_index
add_timestamps
change_column
change_table
create_table
drop_table
remove_column
remove_index
remove_timestamps
rename_column
rename_index
rename_table
Laatste opmerking over migraties: hier is een lijst met de ondersteunde typen die u in uw migratieklassen kunt gebruiken:
binair
boolean
datum
datum Tijd
decimale
vlotter
geheel getal
hoofdsleutel
draad
tekst
tijd
tijdstempel
Nu we de database hebben opgezet, zijn we klaar om naar het andere deel van ons model te kijken: de Active Record-klasse. Dit is het stuk waarmee je daadwerkelijk communiceert vanuit je Rails-controllers. Toen we de Persoon
model, een bestand app / modellen / person.rb
werd opgericht; het ziet er zo uit:
klas Persoon < ActiveRecord::Base attr_accessible :age, :first_name, :last_name end
Als je eerder met Ruby hebt gewerkt, ben je misschien bekend met de attr_accessor
methode, die de getter- en settermethoden voor de betreffende attributen maakt. Nou ja, de attr_accessible
methode is anders; het is eigenlijk Rails-specifiek. Alle eigenschappen die dat zijn attr_accessible
-ized kan via massatoewijzing worden ingesteld. Dit betekent alleen maar het instellen van een aantal eigenschappen tegelijk op een object; dit wordt vaak gedaan bij het maken van een object, zoals zo:
Person.new first_name: "Andrew", achternaam: "Burgess", leeftijd: 22
Elk van de eigenschappen gedefinieerd met attr_accessible
moet een van de velden zijn die we in onze databasetabellen hebben gedefinieerd, in onze migraties (er zijn een paar uitzonderingen hierop). Maar dit betekent niet dat al onze eigenschappen moeten worden gedefinieerd als toegankelijk; er kunnen een aantal eigenschappen zijn die u opzettelijk wilt instellen; bijvoorbeeld, een beheerder
eigenschap die beheerdersbevoegdheden geeft voor een gebruikersrecord moet waarschijnlijk niet worden toegestaan in de massatoewijzing, waar het per ongeluk / kwaadwillig kan worden ingesteld.
Voor eenvoudige Active Record-klassen, alleen die regel van attr_accessible
eigenschappen zullen voldoende zijn. Er is feitelijk veel meer dat we aan onze modelklasse kunnen toevoegen om het robuuster te maken, maar laten we eerst deze person-modelrondrit nemen en zien hoe modelinstanties kunnen worden gemaakt.
In de app "Een normale dag in het leven van een Rails" worden alle databaserecords in de controller gemaakt. In deze zelfstudie gebruiken we echter de Rails-console. In de terminal kunt u de Rails-console openen door een van de volgende handelingen uit te voeren:
rails console rails c
Hiermee wordt een Ruby-console geopend waarin u al uw modelklassen kunt gebruiken.
Zoals je hierboven hebt gezien, kunnen we nieuwe databaserecords maken door een klasseninstantie te maken:
p = Person.new first_name: "John", achternaam: "Doe", leeftijd: 30 # => #
De tweede regel is de waarde van onze variabele p
: een nieuw Persoon
voorwerp. Merk op dat drie van de zes eigenschappen zijn ingesteld, terwijl de andere drie dat niet hebben gedaan. Die worden ingesteld wanneer het record in de database wordt opgeslagen, wat het momenteel niet is (als u hebt getypt Uitgang
op dit moment is er niets in de database opgeslagen). U kunt bevestigen dat het niet wordt opgeslagen door het uit te voeren
p.new_record? # => waar
Om de record in de database op te slaan, kunt u bellen met opslaan
methode:
p.save
Let op dit deel van de output:
INSERT IN "people" ("age", "created_at", "first_name", "last_name", "updated_at") VALUES (?,?,?,?,?) [["Age", 30], ["created_at ", Vr, 15 feb 2013 16:02:18 UTC +00: 00], [" voornaam "," John "], [" achternaam "," Doe "], [" updated_at ", vr, 15 feb 2013 16 : 02: 18 UTC +00: 00]]
Ja, dat is een SQL-statement. Let op, Active Record gebruikt de database-API eronder, dus de SQL moet nog steeds worden uitgevoerd. Dat is een van de kenmerken van de Rails-console: u kunt experimenteren met verschillende Active Record-methoden en precies zien hoe ze de database aanraken. Dit is handig als u methoden gebruikt die veel gegevens ophalen, bijvoorbeeld uit verschillende tabellen: u kunt de juiste methoden kiezen om de meest efficiënte SQL-query te krijgen.
Maar nu, bekijk ons record
p.new_record? # => valse p # => #
De ID kaart
, gemaakt bij
, en updated_at
velden zijn ingesteld.
Als u wilt, kunt u in één keer een nieuwe record maken en opslaan met de creëren
methode:
p2 = Person.create first_name: "Jane", last_name: "Doe", leeftijd: 25 # => #p2.new_record? # => false
Wanneer u met afzonderlijke records werkt, kunt u eigenschappen instellen of wijzigen door hun individuele methoden te gebruiken; Onthoud dat het instellen van een eigenschap deze niet opslaat in de database; dat vereist de opslaan
telefoontje.
p2.first_name = "Janice" p2.save
Als u meerdere kenmerken tegelijk wilt bijwerken, kunt u de update_attributes
, welke een hash neemt van al het attribuut dat je wilt wijzigen:
p.update_attributes first_name: "Jonathan", achternaam: "Doherty"
Een belangrijk verschil over update_attributes
is dat opslaan
wordt binnen die methode uitgevoerd; het is niet nodig om de wijzigingen zelf op te slaan.
Zoals ik al zei, echter, er is meer dat we kunnen doen in de modelklasse. Laten we dus teruggaan naar enkele van die andere functies.
Validaties vormen een belangrijk onderdeel van elke webapp; dit is waar we ervoor zorgen dat de gegevens die we in de database plaatsen, schoon en correct zijn.
Voordat we beginnen, is het belangrijk om te beseffen dat validatieregels die in uw modelklassen zijn gemaakt, de feitelijke database niet wijzigen. Bijvoorbeeld, het zeggen van een gegeven eigenschap is vereist in uw modelklasse maakt het niet vereist op databaseniveau (dat soort dingen zou u instellen in uw - wacht erop - migraties). Dit is niet echt iets waar je je zorgen over hoeft te maken, ik wil gewoon zeker weten dat je de grote afbeelding hier begrijpt.
Zo. Validaties. In de huidige versies van Rails gebruiken we de valideert
methode om al onze validaties in te stellen (het was anders in het verleden). Eerst geven we het veld door of velden die we valideren. Dan kunnen we het een hash doorgeven, de validatie-eigenschappen. Er zijn een aantal van deze validatiehulpmiddelen (zoals ze worden genoemd) die we kunnen gebruiken; hier zijn er verschillende die je altijd zult gebruiken.
Waarschijnlijk de meest gebruikelijke is alleen maar te valideren dat een bepaald veld is gevuld; hiervoor doen we een aanwezigheid
validatie:
validates: first_name,: last_name, presence: true
Hier hebben we validatie op de Voornaam
en achternaam
attributen. In onze validatie-eigenschappen hash, zetten we aanwezigheid
naar waar, wat betekent dat die attributen niet mogen worden verlaten nul
wanneer het record is opgeslagen.
Een andere veel voorkomende validatie is ervoor zorgen dat een veld uniek is. We kunnen dit doen met de unieke helper.
valideert: gebruikersnaam, uniciteit: waar
Verschillende validatiehelpers nemen niet alleen waar
of vals
; ze hebben nog een paar opties nodig. Eigenlijk is de Uniciteits-helper een van hen; wanneer we het gewoon hebben ingesteld waar
, zoals hierboven is hoofdlettergevoeligheid ingeschakeld. Echt waar, met gebruikersnamen, bob
en BOB
zou hetzelfde moeten zijn. Dus, we zouden dit moeten doen:
validates: gebruikersnaam, uniciteit: case_sensitive: false
Nu, bob
en BOB
zou hetzelfde worden beschouwd.
Soms wilt u dat een eigenschap een van een reeks opties is. Proberen inclusie
, die een array (of een ander opsombaar object) neemt.
valideert: account, opname: ['gratis', 'premium', 'business']
Het tegenovergestelde van inclusie
is uitsluiting
, die ervoor zorgt dat de veldwaarde niet in de gegeven reeks valt:
valideert: appt_day, exclusion: ['Sunday', 'Saturday']
Als je zeker wilt weten dat een veld een bepaalde lengte heeft? invoeren lengte
. Er zijn een aantal manieren om deze te gebruiken. Hier zijn een paar voorbeelden:
validates: gebruikersnaam, lengte: maximum: 15 validates: first_name, length: minimum: 1 validates: password, length: in: 10 ... 50
U kunt zelfs drempels instellen:
validates: age, length: greater_than: 18 validates: commission_percentage, length: less_than: 30
Mogelijk wilt u bevestigen dat een waarde een getal is. Gebruik hiervoor numericality
:
valideert: prijs, numericiteit: waar
numericality
kan ook omgaan met het beleid 'geen decimalen':
valideert: jaar, numericiteit: only_integers: true
De laatste die ik je laat zien is formaat
, waarmee u een reguliere expressie kunt instellen voor het overeenkomende veld:
# not a real email regex validates: email, format: with: /\w_@\\\\\\\\\
Er zijn er nog een paar, maar daarmee begin je. Een laatste feitje: u kunt uw eigen valideringshelperklassen maken. Bekijk de documentatie voor meer informatie hierover.
Er zijn verschillende veelvoorkomende opties die bij bijna alle validatiehelpers passen. Ten eerste kunnen we instellen allow_nil
om, nou, sta toe dat een eigenschap niet gevuld is.
valideert: bijnaam, lengte: in: 4 ... 10, allow_nil: true
Als een lege reeks acceptabel is, kunt u de allow_blank
in plaats daarvan.
Een meer gebruikelijke is bericht
; als een validatie mislukt, wordt een bericht aan het object toegevoegd (hier later meer over). Uiteraard hebben alle validatiehelpers standaard berichten, maar je kunt er zelf een instellen met bericht
.
valideert: jaar, aanwezigheid: waar, bericht: "Selecteer een jaar."
De laatste die ik noem is op
, welke bepaalt op welke voorwaarden de validatie zal worden uitgevoerd. De waarden kunnen zijn : maak
(de validatie wordt alleen uitgevoerd bij het opslaan van nieuwe records). :bijwerken
(het wordt alleen uitgevoerd bij het opslaan van eerder opgeslagen records), of :opslaan
(het wordt in beide gevallen uitgevoerd). Natuurlijk is het standaard ingesteld op :opslaan
.
validates: password, length: in: 10 ... 20, on:: create
Een model exemplaar is opslaan
methode retourneert waar
als het met succes is opgeslagen en vals
als dat niet zo was. Als je een krijgt vals
terug, wil je weten wat de fouten waren, goed?
Uw modelinstantie heeft een fout
eigendom, dat is een ActiveModel :: Fouten
aanleg. Nadat de validaties zijn uitgevoerd, wordt dit object gevuld met alle foutberichten voor mislukte validaties; deze worden op zichzelf gehouden berichten
proptery. Let op:
p = Persoon.new p.save # false p.errors.messages # : first_name => ["kan niet leeg zijn"],: last_name => ["kan niet leeg zijn"],: age => [ "kan niet leeg zijn", "is geen getal"] # alternatief: p.errors.full_messages # ["Voornaam mag niet leeg zijn", "Achternaam mag niet leeg zijn", "Leeftijd kan" t is blank "," Leeftijd is geen getal "]
Meestal wilt u deze fouten weergeven aan de gebruiker, waarschijnlijk naast een formulier dat ze hebben verzonden. Een van de gemakkelijkste manieren om dit te doen is om over de full_messages
eigendom van binnenuit uw form_for
blokkeren en ze in een lijst of iets dergelijks afdrukken. Nog eenvoudiger is om Rails al die markup door te laten werken form.error_messages
.
Terugbellen is een ander cool onderdeel van Active Record; ze laten je op een bepaald moment aangepaste methoden uitvoeren. Als je mijn Building Ribbit in Rails handleiding leest, weet je misschien nog dat we de before_save
terugbellen om de avatar_hash
eigendom van gebruikers voordat ze worden opgeslagen. We maken eerst de methode die we willen uitvoeren:
def create_avatar_hash self.avatar_hash = "http://www.gravatar.com/avatar/#Digest::MD5.hexdigest(self.email)?s=50" end
En dan registreren we gewoon de callback:
before_save: create_avatar_hash
Dit betekent dat wanneer we bellen opslaan
, onze methode wordt uitgevoerd net voordat het opslaan daadwerkelijk is voltooid.
We gebruikten ook een before_validation
terugbellen om het e-mailadres te verwijderen. Hoewel dit slechts twee van de callbacks zijn die u kunt gebruiken, zijn dit goede voorbeelden van deze callbacks die handig kunnen zijn. Dit zijn de anderen:
before_validation
/ after_validation
before_save
/ around_save
/ after_save
before_create
/ around_create
/ after_create
before_update
/ around_update
/ after_update
before_destroy
/ around_destroy
/ after_destroy
Vraagt u zich af over de in de omgeving van_*
callbacks? Dit zijn best cool. Ze worden opgeroepen voordat de actie is voltooid, maar dan kun je de actie vanuit de methode uitvoeren door te callen opbrengst
. Zodra de actie is voltooid, wordt de reset van de callback-methode uitgevoerd. Gaaf he?
De meeste relationele databases hebben meerdere tabellen die op de een of andere manier met elkaar in verband staan. Het is dus logisch dat Active Record dit kan verwerken: het doet dit via actieve recordkoppelingen. Laten we zeggen dat we een willen hebben Bestellen
tabel in onze database, en dat elk Persoon
kan meerdere bestellingen hebben. Hoe krijg je dit ingesteld?
We moeten beginnen met het maken van onze Bestellen
model:
rails g model Ordertotaal: integer person_id: integer
Het belangrijkste onderdeel hier is de person_id
veld; zoals je zou verwachten, zal dit onze buitenlandse sleutel zijn, de verbinding tussen de twee klassen. We noemen het person_id
omdat, zodra we onze modelklassen over de relatie vertellen, de Bestellen
klasse zoekt standaard naar een veld met die naam. Als we het iets anders wilden noemen, zoals orderer_identifier
, we zouden het moeten vertellen Bestellen
dat het veld niet is vernoemd naar de klas waarmee het verbinding maakt. Het is gemakkelijker om met de standaardinstellingen te werken.
De migratie die met deze opdracht wordt gemaakt, is alles wat we nodig hebben, dus ik ga nu migreren:
rake db: migreren
Nu moeten we de klassen informeren over de relatie. Binnen in de app / model / person.rb
, voeg deze regel toe:
has_many: bestellingen
Nu in app / model / order.rb
, Voeg dit toe:
behoort_naar: persoon
In Persoon
, we zeggen dat er veel orders kunnen zijn voor elk persoonsbestand; anders gezegd, elke persoon heeft veel
orders. Omgekeerd, elke bestelling hoort bij
een persoon instantie. Deze voegen gewoon een paar handige methodes toe aan onze Persoon
en Bestellen
instanties, die we in een beetje zullen zien.
Dus laten we deze relatie testen, zullen we? In de Rails-console:
p = Person.find (1) o = Order.new total: 100 o.person = p o.save p.orders # => [#]
De interessante regels hier zijn 3 en 5. We hadden het kunnen doen o.person_id = p.id
, maar vanwege onze toevoegingen aan de modellessen, o.person = p
is een kortere manier om hetzelfde te doen. Dan regel 5: dit is weer een van die toegevoegde methoden: het geeft een reeks van alle orders terug die onze persoon heeft. Handig, nee?
Dit is een goede samenvatting van het soort dingen dat u kunt doen met Active Record Associations; er is een ton meer, en het kan behoorlijk ingewikkeld worden. Bekijk de documentatie van de Verenigingen voor al het goede.
Al die tijd hebben we Active Record-klassen gebouwd of modelrecords gemaakt. Een groot deel van het werken met een Active Record-klasse is echter om die records terug te krijgen. Zoals je zou verwachten, zijn er een tiental methoden die we kunnen gebruiken.
De eerste en eenvoudigste zijn de methoden die alle records retourneren:
Person.all
De allemaal
methode retourneert een array van alle records.
Er is ook vind
, welke de ID kaart
als een parameter en retourneert de record met die id; het kan ook een reeks van aannemen ID kaart
s en retourneer de overeenkomende records:
Person.find 2 # => #Person.find [2,4,6] # => [# , # , # ]
Als u alleen de eerste of laatste record in de verzameling wilt, zijn daarvoor specifieke methoden:
Person.eerst Person.last
Een van de coolste functies van Active Record is de aangepaste vindmethode; daaronder, dit gebruikt het gewoon method_missing
, maar vanaf de bovenkant lijkt het pure magie. Hier is hoe het werkt: gebruik de methode naam find_by_
en geef de waarde voor die eigenschap door als parameter. Bijvoorbeeld:
Person.find_by_first_name "John" # => #
Je kunt zelfs eigenschappen koppelen; deze opdracht retourneert hetzelfde record:
Person.find_by_first_name_and_last_name "John", "Doe"
Als u de SQL-query's voor die laatste twee methoden bekijkt, ziet u dat we alleen het eerste resultaat retourneren (LIMIET 1
). Om alle gevonden records te vinden, gebruikt u de find_all_by
voorvoegsel. Zo:
Person.find_all_by_first_name "John" Person.find_all_by_first_name_and_last_name "John", "Doe"
Het wordt nog beter: je kunt het gebruiken find_or_create_by
voorvoegsel om een record aan te maken als er geen overeenkomende gevonden wordt:
p = Person.find_or_create_by_first_name_and_last_name_and_age "Bob", "Smith", 45
Ja, dit werkt echt. Realiseer je echter dat als er geen record wordt gevonden, dit hetzelfde is als hardlopen Person.create
, welke de validaties uitvoert. Dus, bijvoorbeeld, sinds achternaam
en leeftijd
vereist zijn, als dit wordt uitgevoerd, zullen er niet-opgeslagen fouten in de record worden aangebracht:
Person.find_or_create_by_first_name "Lindsey"
Als u niet wilt dat de nieuwe record meteen wordt opgeslagen, gebruikt u de find_or_initialize_by
voorvoegsel.
Person.find_or_initialize_by_first_name "Lindsey"
Er zijn een paar andere methoden die u mogelijk handig vindt bij het selecteren van records. Een heel nuttige is waar
wat een WAAR
clausule uit een SQL-instructie.
Person.where ("first_name like 'A%'")
Als u waarden van de gebruiker gebruikt voor gebruik in waar
, je moet ze niet interpoleren, uit angst voor SQL-injecties. U moet vraagtekens gebruiken in plaats daarvan en de waarden vervolgens als andere parameters doorgeven:
Person.where ("first_name like?", Params [: name_starts_with])
... of iets dergelijks.
Al deze methoden die we tot nu toe hebben bekeken, retourneren alle velden van de geretourneerde records. U kunt de kiezen
methode vóór een van hen om modelinstances alleen met een paar geselecteerde eigenschappen te retourneren:
Person.select (: first_name) .First Person.select ("last_name, age"). Find_by_first_name ("Andrew")
Andere veel voorkomende activiteiten voor SQL-instructies omvatten beperken en compenseren; een goed voorbeeld hiervan is pagineringsresultaten. De begrenzing
en compenseren
methoden nemen elk een enkele getalparameter. Als je ze alleen gebruikt, werken ze aan de hele verzameling; dit levert bijvoorbeeld vijf records op en slaat de eerste twee over:
Person.offset (2) .limit (5)
Maar u kunt de records kiezen om te beperken en te compenseren met een van de andere functies:
Person.select (: id) .limit (2) .offset (2) .find_all_by_first_name "Andrew"
Er zijn een paar andere query-methoden, maar we hebben degenen behandeld die u 90% van de tijd gaat gebruiken.
Als u complexe query's als deze uitvoert, is het een goed idee om zelf een querymethode te maken, in uw modellessen. Laten we zeggen dat we mensen laten zoeken naar andere gebruikers op hun achternaam, en we publiceren de resultaten met 10 gebruikers per pagina. De zoekopdracht kan er ongeveer zo uit zien:
Person.offset (0) .limit (10) .find_by_last_name (params [: SEARCH_TERM])
Behalve dat dit nogal lang is voor de controller, moet die offset voor elke pagina veranderen; 0
werkt alleen voor de eerste pagina. Dus, we schrijven een methode in onze Persoon
klasse:
def self.search (term, pagina = 1, per_page = 10) Persoon.offset (per_page * (pagina - 1)). limit (per_page) .find_all_by_last_name term einde
Dit geeft de set terug die we willen, en we kunnen kiezen welke pagina en hoeveel resultaten per pagina we willen hebben (of laten ze naar hun verstandige standaardwaarden.) En nog beter, het is een mooie nette methode die we kunnen bellen vanuit onze controller zoals deze. :
Person.search "Smith" # pagina 1 Person.search "Smith", 2 # pagina 2
Raadpleeg voor meer informatie over query's de query-documentatie voor Active Record.
Als u Rails net wilt gebruiken, heeft u zojuist alles geleerd over Active Record voor een tijdje. Natuurlijk, zoals elk ander onderdeel van Rails, is Active Record diep en rijk;