Niet-ActiveRecord-modellen in rails 4

ActiveRecord wordt geleverd met een krachtige set validators en andere functies voor attributen van een persistent datamodel. Aan de andere kant zijn formulieren een van de oudste en belangrijkste bouwstenen van de hedendaagse webtoepassingen, een essentiële interface voor gebruikersinvoer. Van de twee vormen helpers die Rails levert, neemt "form_for" ook aan dat je met een soort van persistent object werkt. Het kan dus ten volle profiteren van alle actieve opnamefuncties, d.w.z. validaties.

Dit is allemaal geweldig voor persistente objecten met door databases ondersteunde representaties. Maar wat gebeurt er als je een complexe vorm nodig hebt die niet overeenkomt met een hardnekkig record van een soort?

In deze tutorial zal ik het hebben over de mogelijke oplossingen voor dit probleem en over de implementatie hiervan in Rails 4 (actieve modellen).

In deze zelfstudie bouwen we een applicatie met een formulier waarin een gebruiker feedback kan toevoegen die vervolgens in een database wordt opgeslagen. Deze applicatie heeft ook validaties en views, precies zoals u ze voor een database-gesteund model maakt, maar dan zullen we enkele van de veranderingen in het model doornemen om het zonder tableau te maken. En alle functies moeten werken zoals ze zijn, zonder verdere wijzigingen aan te brengen. Er zijn geen Update, Delete of Find acties voor feedback.

Eerste dingen eerst

Voor deze zelfstudie neem ik aan dat u een eenvoudige onderschatting van het Rails-framework hebt en eenvoudig basiscontrollers, modellen en views kunt maken of genereren. Ik neem aan dat je ook een beetje weet hoe routes en validaties werken. Op het moment van schrijven van deze tutorial, gebruikte ik Rails 4.2.5 en SQLite 3.8.10.2.

Invoering

Er kunnen veel situaties zijn wanneer u een klasse hebt die u wilt laten werken zoals een typisch ActiveRecord-model, maar u de gegevens niet wilt behouden in de database. U hebt bijvoorbeeld een contactformulier of iets complexer zoals een klachten- of feedbackformulier. 

In die situaties zou een oplossing om dit probleem op te lossen de form_tag helper-methode, die u voorziet van aangepaste formuliervelden die doen wat u nodig hebt, zonder ze met welk model dan ook te hoeven verbinden.

Dit werkt goed, maar form_tag kan snel vervelend worden om te schrijven en te onderhouden als u meer dan een paar velden verwerkt, vanwege de noodzaak om de vele kenmerken en hun validaties zelf te benoemen. Binnenkort zal je controller uiteindelijk te maken krijgen met veel logica en tonnen van vorm-params, wat waarschijnlijk geen ideale oplossing is.

Een schonere, meer flexibele benadering zou zijn als we op de een of andere manier hetzelfde zouden kunnen gebruiken form_for met een model en alle validaties en andere voordelen waar ze bij komen, maar zonder dat je database-gesteunde representaties van zijn attributen nodig hebt.

Rails biedt precies dit soort oplossing: de Actief model-dat is net een normaal model, maar zonder de tabellen. Het biedt precies dezelfde gemakkelijke manier van validatie en bijna alle andere goodies die met ActiveRecord worden geleverd. Het helpt u de applicatiestructuur consistent te houden, omdat u toch modellen gebruikt om objecten in uw app te representeren, routes gratis beschikbaar zijn en formulieren bouwen net zo eenvoudig is als voorheen form_for.

Laten we eerst een nieuwe applicatie maken

In deze stap genereren we een dummy-applicatie om mee te spelen tijdens deze tutorial.

Stap 1: bouwen

Start uw terminal en typ deze opdrachten om een ​​nieuwe applicatie te maken:

# Creëer een basis Rails App-rails nieuwe tableless cd tableless # Creëer een Controller met alleen nieuw, creëer en succes Acties rails genereren controller-feedbacks nieuw creëer succes --skip-routes # Maak een Model rails genereer model feedback naam: string email: string adres : stringbericht: tekstsuggestie: tekst 

Dit is hoe jouw Directorystructuur zal kijken.

Stap 2: bewerken

Hier geef ik de codefragmenten voor alle bestanden die u moet invullen. De code is vrij duidelijk. Je kunt deze app downloaden van de GitHub-repository die aan dit bericht is gelinkt of mijn stappen volgen om er zelf een te maken.

→ / Config /routes.rb

middelen: feedbacks,: alleen => [: nieuw,: maken] ontvang 'feedbacks / succes' => 'feedbacks # succes', als:: succes

→ /app/views/feedbacks/success.html.erb

<%= notice %>


<%= link_to 'Submit New Feedback', new_feedback_path %>

→ / app / views / feedbacks /new.html.erb 

Nieuwe feedback

<%= form_for(@feedback) do |f| %> <% if @feedback.errors.any? %>

<%= pluralize(@feedback.errors.count, "error") %> verboden deze feedback te worden opgeslagen:

    <% @feedback.errors.full_messages.each do |message| %>
  • <%= message %>
  • <% end %>
<% end %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :address %>
<%= f.text_field :address %>
<%= f.label :message %>
<%= f.text_area :message %>
<%= f.label :suggestion %>
<%= f.text_area :suggestion %>
<%= f.submit %>
<% end %> <%= link_to 'Back', feedbacks_path %>

→ /app/controllers/feedbacks_controller.rb

class FeedbacksController < ApplicationController def new @feedback = Feedback.new end def create @feedback = Feedback.new(feedback_params) respond_to do |format| if @feedback.save format.html  redirect_to success_path, notice: 'Feedback was successfully submitted.'  else format.html  render :new  end end end def success end private def feedback_params params.require(:feedback).permit(:name, :email, :address, :message, :suggestion) end end

→ / app /modellen / feedbacks.rb

class Feedback < ActiveRecord::Base # fields validation for the database. validates :name, presence: true validates :email, presence: true, length: in:5… 255 validates :address, presence: true validates :message, presence: true validates :suggestion, presence: true end

Stap 3: implementeren

Om het op uw lokale server te implementeren, moet u eerst de volgende opdrachten uitvoeren om de database in uw systeem aan te maken.

cd tabloos / rake db: migreren 

Als u de tutorial tot nu toe hebt gevolgd, moet de bovenstaande opdracht standaard een sqlite3-database maken. Om het te veranderen, kun je naar springen database.yml-in het belang van deze tutorial ga ik met sqlite3.

Ren nu rails s in uw terminal en u zou iets dergelijks moeten zien.

En hiermee zou je succesvol een dummy-applicatie moeten draaien.

Stap 4: Testen

Nu is het tijd om te testen wat we zojuist hebben gemaakt. Raak deze route aan in uw browser om te controleren of alles goed werkt: http: // localhost: 3000 / feedbacks / new

Je zou een formulier zoals hierboven moeten zien. Druk nu op de verzendknop zonder een veld in te vullen om te controleren of de validaties goed werken.

Super goed. U zou zes validatiefouten moeten zien, zoals hierboven. Nu kunnen we proberen de juiste waarden in te vullen en het formulier in te dienen.

Je zou iets soortgelijks op je scherm moeten zien. Laten we de database controleren op de record die we net hebben ingevoerd. 

Open je Terminal, ga naar je projectdirectory en typ de onderstaande commando's.

  • rails db om de databaseclient in uw console te starten.
  • SQLite> .tabellen om alle tabellen in uw database op te sommen (DB is standaard geselecteerd).
  • SQLite> .headers aan om de Kolomnamen in je resultaten.
  • SQLite> selecteer * uit feedbacks; om alle feedback in de database te zien.

En hier kunnen we zien dat de feedback met succes in de database is opgeslagen. Als u de logboeken bekijkt, kunt u ook de INSERT vraag.

En daarmee is onze test voorbij. Nu alles goed lijkt te werken, laten we eens kijken naar de oplossing.

De oplossing

Stap 1: Implementatie 

Implementeren Actief model, het eerste dat u hoeft te doen is de overerving van het feedbackmodel verwijderen < ActiveRecord::Base omdat we niet willen dat dit model een back-end van de database heeft. 

Zodra we dit doen, zal ons formulier niet langer werken, omdat de validators worden geleverd door ActiveRecord. Maar toevoegen omvatten ActiveModel :: Model op de volgende regel zou alles moeten herstellen.

Je model zou er nu zo uit moeten zien.

class Feedback omvat ActiveModel :: Model 

Het tweede ding is om toe te voegen attr_accessor om de getters en setters te genereren voor alle attributen, zoals deze.

attr_accessor: name,: email,: address,: message,: suggestion

Nu zou het eindresultaat van het model er zo uit moeten zien.

class Feedback omvat ActiveModel :: Model attr_accessor: name,: email,: address,: message,: suggestion # fields validation for the database. validates: naam, aanwezigheid: true validates: email, presence: true, length: in: 5 ... 255 validates: address, presence: true validates: message, presence: true validates: suggestion, presence: true end

Het repareren van het model is niet genoeg om ervoor te zorgen dat onze app zich gedraagt ​​zoals we dat willen. De controller verwacht nog steeds dat het ontvangen gegevensobject wordt opgeslagen in de database in de creëren methode. @ feedback.save zal niet werken omdat we geen back-end van de database hebben om de nieuwe feedback op te slaan.

We kunnen dit probleem oplossen door te veranderen @ feedback.save in @ feedback.valid? omdat we nu alleen de validaties in onze modellen uitvoeren en op basis van deze succesgebeurtenis kunt u elke gewenste taak binnen dit codeblok uitvoeren, d.w.z. meldingen verzenden, e-mail of logboekgebeurtenissen verzenden, enz..

class FeedbacksController < ApplicationController def create @feedback = Feedback.new(feedback_params) respond_to do |format| if @feedback.valid? # Something interesting can be done here # - send notifications # - send email # - log events format.html  redirect_to success_path, notice: 'Feedback was successfully submitted.'  else format.html  render :new  end end end

Stap 2: Testen

Laten we de tests herhalen die we eerder hebben uitgevoerd.

Raak de route http: // localhost: 3000 / feedbacks / new en legthet formulier zonder velden in te vullen. Alle validaties zouden moeten werken zoals eerder.

Super goed. Nu kunnen we het proberen door het formulier met geldige waarden in te dienen.

En hier gaat u - dezelfde succesboodschap.

Het enige dat we nog moeten controleren, is de database. 

Open daarvoor uw Terminal, ga naar je projectdirectory en typ de onderstaande commando's.

  • rails db om de databaseclient in uw console te starten.
  • SQLite> .tabellen om alle tabellen in uw database op te sommen (DB is standaard geselecteerd).
  • SQLite> .headers aan om de Kolomnamen in je resultaten.
  • SQLite> selecteer * uit feedbacks om alle feedback in de database te zien.

En deze keer, omdat ons model niet wordt ondersteund door een databasetabel, zult u de nieuw ingediende waarden niet vinden in de tabel.

Als u uw consolelogboeken controleert, zien we ook de INSERT vraag meer.

Conclusie

Dus hiermee zijn we klaar met de ActiveModel, en we zagen hoe gemakkelijk het is om een ​​tafelloos model te maken. ActiveModel is bezig met zware verbeteringen, zodat u enkele veranderingen in de komende versies van Rails kunt verwachten. 

We hebben zojuist de validaties en attribuutopdrachten in deze tutorial gebruikt om de dingen eenvoudig en duidelijk te houden. Maar kijk eens in de map met de code voor ActiveModel op GitHub.

We kunnen aan de hand van de lijst zien dat ActiveModel ook klassen bevat voor attributenmethoden, serialisatie, callbacks en dirty tracking, onder andere. Op deze manier kunt u de aankomende functies in de gaten houden en ook vertrouwd raken met anderen.