Non-ActiveRecord Modeller i Rails 4

ActiveRecord levereras med en kraftfull uppsättning av validatorer och andra funktioner för attribut av en persisted datamodell. Å andra sidan är formulär ett av de äldsta och viktigaste byggstenarna i dagens webbapplikationer - ett viktigt gränssnitt för användarinmatning. Av de två formulärhjälpare som Rails tillhandahåller antar "form_for" också att du arbetar med ett slags kvarhållet föremål. Så det kan dra full nytta av alla aktiva rekordfunktioner, det vill säga valideringar.

Detta är allt bra för kvarhållna föremål med databas-backade representationer. Men vad händer när du behöver en komplex form som inte speglar en beständig rekord av något slag?

I denna handledning talar jag om möjliga lösningar för detta problem och hur man implementerar en i Rails 4 (Active Models).

I denna handledning bygger vi en applikation med ett formulär där en användare kan lägga till en del återkoppling som sedan sparas i en databas. Den här applikationen kommer också att ha valideringar och visningar, precis som du skapar dem för en databasbaserad modell, men då går vi igenom några av förändringarna i modellen för att göra det tableless. Och alla funktioner måste fungera som de är, utan att göra några ytterligare ändringar. Det finns inga uppdateringar, raderingar eller hitta åtgärder för feedback.

Första saker först

För denna handledning antar jag att du har en grundläggande underskrift av ramarna Rails och kan enkelt skapa eller generera grundläggande kontroller, modeller och visningar. Jag antar att du också vet lite om hur vägar och valideringar fungerar. Vid skrivandet av denna handledning använde jag Rails 4.2.5 och SQLite 3.8.10.2.

Introduktion

Det kan finnas många situationer när du har en klass som du vill fungera som en typisk ActiveRecord-modell, men du vill inte fortsätta data i databasen. Du kan till exempel ha ett kontaktformulär eller något mer komplext som ett klagomål eller ett feedbackformulär. 

I dessa situationer, för att lösa detta problem skulle ett tillvägagångssätt vara att använda form_tag hjälparmetoden, som ger dig anpassade formulärfält som gör vad du behöver utan att behöva binda dem med någon modell alls.

Det fungerar bra, men form_tag kan snabbt bli tråkigt att skriva och underhålla om man hanterar mer än ett fåtal fält på grund av behovet av att hantera namngivning av sina många attribut och deras valideringar på egen hand. Snart kommer din kontrollant att sluta hantera en hel del logik och massor av formulärparametrar, vilket sannolikt inte är en idealisk lösning.

Ett renare, mer flexibelt tillvägagångssätt skulle vara om vi på något sätt kunde använda samma form_for med en modell och alla valideringar och andra förmåner som de kommer med, men utan att behöva ha databas-backade representationer av dess attribut.

Rails erbjuder exakt denna typ av lösning: Aktiv modell-vilket är precis som en vanlig modell men utan borden. Det ger exakt samma enkla sätt att validera och nästan alla andra godis som skickas med ActiveRecord. Det hjälper dig att hålla applikationsstrukturen konsekvent, eftersom du använder modeller för att representera objekt i din app, ändå finns rutter gratis och formgivning är så enkelt som tidigare form_for.

Låt oss skapa en ny applikation först

I det här steget genererar vi en dummy-applikation för att leka med under den här handledningen.

Steg 1: Byggnad

Starta din terminal och skriv dessa kommandon för att skapa en ny applikation:

# Skapa en grundläggande Rails Apprapportering nya tableless cd tableless # Skapa en kontroller med bara nya, skapa och framgång Åtgärder rails generera kontrollerns återkopplingar nya skapa framgång - fart-rutter # Skapa en modell rails generera modell feedback namn: sträng e-post: sträng adress : strängmeddelande: textförslag: text 

Så här är din Katalogstruktur ska titta.

Steg 2: Redigering

Här kommer jag att ge kodstycken för alla filer du behöver fylla i. Koden är ganska självklarande. Du kan antingen hämta den här appen från GitHub-arkivet som är länkat till det här inlägget eller följa mina steg för att skapa en själv.

→ / Config /routes.rb

resurser: feedbacks,: only => [: new,: create] få "feedbacks / success '=>' feedbacks # success ', som:: framgång

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

<%= notice %>


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

→ / app / vyer / återkopplingar /new.html.erb 

Ny feedback

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

<%= pluralize(@feedback.errors.count, "error") %> förbjudet att denna återkoppling sparas:

    <% @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

klass 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 /modeller / feedbacks.rb

klass återkoppling < 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

Steg 3: Implementera

För att distribuera den på din lokala server måste du först springa följande kommandon för att skapa databasen i ditt system.

cd tableless / rake db: migrera 

Om du har följt handledningen så här långt bör kommandot ovan skapa en sqlite3-databas som standard. För att ändra det kan du hoppa till database.yml-för denna handledning skull går jag med sqlite3.

Kör nu skenor s i din terminal och du bör se något liknande det här.

Och med det här borde du ha en bra applikation.

Steg 4: Testning

Nu är det dags att testa vad vi just skapat. Tryck på denna rutt i din webbläsare för att kontrollera om allt fungerar bra: http: // localhost: 3000 / kopplingar / new

Du borde se en blankett som ovan. Nu trycker du på Skicka-knappen utan att fylla i något fält för att kontrollera om valideringen fungerar bra.

Bra. Du bör se sex valideringsfel, som ovan. Nu kan vi försöka fylla i korrekta värden och skicka in formuläret.

Du borde se något liknande på din skärm. Låt oss kolla databasen för den post som vi just angett. 

Öppna din Terminal, gå till din projektkatalog och skriv kommandona nedan.

  • skenor db för att starta databasklienten i din konsol.
  • SQLite> .tables att lista alla tabeller i din databas (DB är vald som standard).
  • SQLite> .huvud på för att visa Kolumnnamn i dina resultat.
  • SQLite> välj * från feedback; för att se all feedback i databasen.

Och här kan vi se att feedbacken sparades med framgång i databasen. Om du tittar på loggarna kan du också hitta FÖRA IN fråga.

Och med detta är testningen över. Nu när allt verkar fungera bra, låt oss hoppa in i lösningen.

Lösningen

Steg 1: Implementering 

Att genomföra Aktiv modell, Det första du behöver göra är att ta bort återkopplingsmodellens arv till < ActiveRecord::Base eftersom vi inte vill att den här modellen ska ha en databasback-end längre. 

Så snart vi gör det, kommer vår form inte längre att fungera, eftersom validatorerna tillhandahålls av ActiveRecord. Men att lägga till Inkludera ActiveModel :: Modell på nästa rad bör återställa allt.

Din modell ska se ut så här nu.

klassens feedback inkluderar ActiveModel :: Model 

Det andra är att lägga till attr_accessor att generera getters och setters för alla attribut, så här.

attr_accessor: namn,: email,: adress,: meddelande,: förslag

Nu ska resultatet av modellen se ut så här.

klass feedback inkluderar ActiveModel :: Modell attr_accessor: namn,: email,: adress,: meddelande,: förslag # fält validering för databasen. validerar: namn, närvaro: true validates: email, presence: true, length: in: 5 ... 255 validerar: adress, närvaro: true validates: message, presence: true validates:

Att fixa modellen räcker inte för att få vår app att fungera som vi vill. Kontrollern förväntar sig fortfarande att spara det mottagna dataobjektet i databasen i skapa metod. @ feedback.save kommer inte att fungera eftersom vi inte har någon databas tillbaka för att spara den nya feedbacken längre.

Vi kan åtgärda problemet genom att ändra @ feedback.save in i @ feedback.valid? eftersom vi bara utför valideringarna i våra modeller nu och baserat på denna framgångshändelse kan du utföra en önskad uppgift inom det här kvarteret, det vill säga skicka meddelanden, skicka e-post eller logga händelser, etc.

klass 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

Steg 2: Testning

Låt oss göra om de tester vi utförde tidigare.

Hit på rutten http: // localhost: 3000 / kopplingar / new och skickaformuläret utan att fylla i några fält. Alla valideringar ska fungera som tidigare.

Bra. Nu kan vi försöka genom att skicka in formuläret med giltiga värden.

Och här går du - samma framgångsbudskap.

Nu är den sista sak som vi behöver kontrollera databasen. 

För det, öppna upp din Terminal, gå till din projektkatalog och skriv kommandona nedan.

  • skenor db för att starta databasklienten i din konsol.
  • SQLite> .tables att lista alla tabeller i din databas (DB är vald som standard).
  • SQLite> .huvud på för att visa Kolumnnamn i dina resultat.
  • SQLite> välj * från feedback för att se all feedback i databasen.

Och den här gången, eftersom vår modell inte stöds med någon databastabell, hittar du inte de nyligen inlämnade värdena i tabellen.

Om du kontrollerar dina konsolloggar ser vi inte FÖRA IN fråga längre.

Slutsats

Så med detta är vi färdiga med ActiveModel, och vi såg hur lätt det är att skapa en tabelllös modell. ActiveModel har stora förbättringar, så du kan förvänta dig några förändringar i kommande versioner av Rails. 

Vi har just använt valideringarna och attributtilldelningarna i den här handledningen för att hålla sakerna enkla och tydliga. Men ta en titt i katalogen som innehåller koden för ActiveModel på GitHub.

Vi kan se från listan att ActiveModel också innehåller klasser för attributmetoder, serialisering, återuppringningar och smutsig spårning bland annat. På så sätt kan du hålla koll på kommande funktioner och bli bekant med andra.