Wie man verschachtelte Ressourcen für eine Ruby-on-Rails-Anwendung erstellt

Einführung

Ruby on Rails ist ein Webanwendungs-Framework, das in Ruby geschrieben wurde und Entwicklern einen meinungsbasierten Ansatz für die Anwendungsentwicklung bietet. Die Arbeit mit Rails bietet Entwicklern:

  • Konventionen für die Handhabung von Dingen wie Routing, zustandsbehafteten Daten und Asset-Verwaltung.
  • A firm grounding in the model-view-controller (MCV) architectural pattern, which separates an application’s logic, located in models, from the presentation and routing of application information.

Wenn Sie Komplexität zu Ihren Rails-Anwendungen hinzufügen, werden Sie wahrscheinlich mit mehreren Modellen arbeiten, die die Geschäftslogik Ihrer Anwendung darstellen und mit Ihrer Datenbank interagieren. Das Hinzufügen von verwandten Modellen bedeutet, sinnvolle Beziehungen zwischen ihnen herzustellen, die dann beeinflussen, wie Informationen durch die Controller Ihrer Anwendung übermittelt werden und wie sie von Benutzern durch Ansichten erfasst und präsentiert werden.

In diesem Tutorial werden Sie auf einer bestehenden Rails-Anwendung aufbauen, die Benutzern Fakten über Haie bietet. Diese Anwendung hat bereits ein Modell zur Verarbeitung von Haifischdaten, aber Sie werden eine verschachtelte Ressource für Beiträge über einzelne Haie hinzufügen. Dadurch können Benutzer einen breiteren Gedankenschatz und Meinungen zu einzelnen Haien entwickeln.

Voraussetzungen

Um diesem Tutorial folgen zu können, benötigen Sie:

  • A local machine or development server running Ubuntu 18.04. Your development machine should have a non-root user with administrative privileges and a firewall configured with ufw. For instructions on how to set this up, see our Initial Server Setup with Ubuntu 18.04 tutorial.
  • Node.js und npm sind auf Ihrem lokalen Rechner oder Entwicklungsserver installiert. Dieses Tutorial verwendet Node.js Version 10.16.3 und npm Version 6.9.0. Für Anleitungen zur Installation von Node.js und npm unter Ubuntu 18.04 folgen Sie den Anweisungen im Abschnitt „Installation mithilfe eines PPA“ von So installieren Sie Node.js unter Ubuntu 18.04.
  • Ruby, rbenv und Rails sind auf Ihrem lokalen Rechner oder Entwicklungsserver installiert, indem Sie Schritte 1-4 in So installieren Sie Ruby on Rails mit rbenv unter Ubuntu 18.04 befolgen. Dieses Tutorial verwendet Ruby 2.5.1, rbenv 1.1.2 und Rails 5.2.3.
  • SQLite ist installiert, und eine grundlegende Anwendung für Haie ist erstellt, indem Sie den Anweisungen in So erstellen Sie eine Ruby on Rails-Anwendung folgen.

Schritt 1 — Das verschachtelte Modell scaffolden

Unsere Anwendung wird von den Assoziationen von Active Record profitieren, um eine Beziehung zwischen den Modellen Shark und Post aufzubauen: Posts werden bestimmten Haien gehören, und jeder Hai kann mehrere Posts haben. Unsere Modelle Shark und Post werden daher über die belongs_to– und has_many-Assoziationen miteinander verbunden sein.

Der erste Schritt, um die Anwendung auf diese Weise zu erstellen, wird sein, ein Post-Modell und zugehörige Ressourcen zu erstellen. Dazu können wir den Befehl rails generate scaffold verwenden, der uns ein Modell, eine Datenbankmigration zur Änderung des Datenbankschemas, einen Controller, einen vollständigen Satz von Ansichten zum Verwalten der Standard-Erstellen, Lesen, Aktualisieren und Löschen (CRUD)-Operationen sowie Vorlagen für Partials, Helfer und Tests gibt. Wir müssen diese Ressourcen anpassen, aber die Verwendung des Befehls scaffold wird uns etwas Zeit und Energie sparen, da er eine Struktur generiert, die wir als Ausgangspunkt verwenden können.

Zuerst stellen Sie sicher, dass Sie sich im Verzeichnis sharkapp für das Rails-Projekt befinden, das Sie in den Voraussetzungen erstellt haben:

  1. cd sharkapp

Erstellen Sie Ihre Post-Ressourcen mit folgendem Befehl:

rails generate scaffold Post body:text shark:references

Mit `body:text` sagen wir Rails, ein body-Feld in der posts-Datenbanktabelle einzuschließen – die Tabelle, die zum Post-Modell abbildet. Wir inkludieren auch das :references-Schlüsselwort, welches eine Verbindung zwischen den Shark– und Post-Modellen einrichtet. Speziell stellt dies sicher, dass ein Fremdschlüssel, der jeden Shark-Eintrag in der sharks-Datenbank darstellt, zur posts-Datenbank hinzugefügt wird.

Nachdem du den Befehl ausgeführt hast, wirst du eine Ausgabe sehen, die die Ressourcen bestätigt, die Rails für die Anwendung generiert hat. Bevor du fortfährst, kannst du deine Datenbank-Migrationsdatei überprüfen, um die Beziehung anzusehen, die jetzt zwischen deinen Modellen und Datenbanktabellen besteht. Verwende den folgenden Befehl, um den Inhalt der Datei anzusehen, und achte darauf, den Zeitstempel in deiner eigenen Migrationsdatei für das zu verwenden, was hier gezeigt wird:

  1. cat db/migrate/20190805132506_create_posts.rb

Du wirst die folgende Ausgabe sehen:

Output
class CreatePosts < ActiveRecord::Migration[5.2] def change create_table :posts do |t| t.text :body t.references :shark, foreign_key: true t.timestamps end end end

Wie du sehen kannst, enthält die Tabelle eine Spalte für einen Shark-Fremdschlüssel. Dieser Schlüssel wird in Form von model_name_id vorliegen – in unserem Fall shark_id.

Rails hat die Beziehung zwischen den Modellen auch anderswo hergestellt. Sieh dir das neu generierte Post-Modell mit dem folgenden Befehl an:

cat app/models/post.rb
Output
class Post < ApplicationRecord belongs_to :shark end

Die belongs_to-Assoziation richtet eine Beziehung zwischen Modellen ein, bei der eine einzelne Instanz des deklarierenden Modells zu einer einzelnen Instanz des benannten Modells gehört. In unserem Fall bedeutet dies, dass ein einzelner Beitrag zu einem einzigen Shark gehört.

Zusätzlich zur Festlegung dieser Beziehung hat der Befehl rails generate scaffold auch Routen und Ansichten für Beiträge erstellt, wie er es auch für unsere Haifisch-Ressourcen in Schritt 3 von Wie man eine Ruby on Rails-Anwendung erstellt getan hat.

Dies ist ein nützlicher Anfang, aber wir müssen einige zusätzliche Routen konfigurieren und die aktive Record-Verknüpfung für das Shark-Modell festigen, damit die Beziehung zwischen unseren Modellen und Routen wie gewünscht funktioniert.

Schritt 2 — Spezifizierung von Verschachtelten Routen und Verknüpfungen für das Elternmodell

Rails hat bereits die belongs_to-Verknüpfung in unserem Post-Modell festgelegt, dank des :references-Schlüsselworts im rails generate scaffold-Befehl, aber damit diese Beziehung ordnungsgemäß funktioniert, müssen wir auch eine has_many-Verknüpfung in unserem Shark-Modell angeben. Wir müssen auch Änderungen an den Standard-Routen vornehmen, die uns Rails gegeben hat, um Beitrag-Ressourcen zu den Kindern von Haifisch-Ressourcen zu machen.

Um die has_many-Assoziation zum Modell Shark hinzuzufügen, öffnen Sie app/models/shark.rb mit nano oder Ihrem bevorzugten Editor:

  1. nano app/models/shark.rb

Fügen Sie die folgende Zeile zur Datei hinzu, um die Beziehung zwischen Haien und Beiträgen herzustellen:

~/sharkapp/app/models/shark.rb
class Shark < ApplicationRecord
  has_many :posts
  validates :name, presence: true, uniqueness: true
  validates :facts, presence: true
end

Eine Sache, über die es sich hier nachzudenken lohnt, ist, was mit Beiträgen passiert, wenn ein bestimmter Hai gelöscht wird. Wahrscheinlich möchten wir nicht, dass die Beiträge, die mit einem gelöschten Hai verbunden sind, in der Datenbank bestehen bleiben. Um sicherzustellen, dass alle Beiträge, die mit einem bestimmten Hai verbunden sind, gelöscht werden, wenn dieser Hai gelöscht wird, können wir die dependent-Option mit der Assoziation einschließen.

Fügen Sie den folgenden Code zur Datei hinzu, um sicherzustellen, dass die destroy-Aktion bei einem bestimmten Hai alle zugehörigen Beiträge löscht:

~/sharkapp/app/models/shark.rb
class Shark < ApplicationRecord
  has_many :posts , dependent: :destroy
  validates :name, presence: true, uniqueness: true
  validates :facts, presence: true
end

Nachdem Sie diese Änderungen vorgenommen haben, speichern Sie die Datei und schließen Sie sie. Wenn Sie nano verwenden, können Sie dies tun, indem Sie STRG+X, Y, dann ENTER drücken.

Öffnen Sie als nächstes Ihre config/routes.rb-Datei, um die Beziehung zwischen Ihren ressourcenorientierten Routen zu ändern:

  1. nano config/routes.rb

Derzeit sieht die Datei so aus:

~/sharkapp/config/routes.rb
Rails.application.routes.draw do
  resources :posts 
  resources :sharks

  root 'sharks#index'
  # Weitere Informationen zur verfügbaren DSL in dieser Datei finden Sie unter http://guides.rubyonrails.org/routing.html
end

Der aktuelle Code etabliert eine unabhängige Beziehung zwischen unseren Routen, während wir gerne eine abhängige Beziehung zwischen Haien und ihren zugehörigen Beiträgen ausdrücken möchten.

Lassen Sie uns unsere Routendeklaration aktualisieren, um :sharks zum Elternteil von :posts zu machen. Aktualisieren Sie den Code in der Datei wie folgt:

~/sharkapp/config/routes.rb
Rails.application.routes.draw do
  resources :sharks do
    resources :posts
end
  root 'sharks#index'
  # Weitere Details zur verfügbaren DSL in dieser Datei finden Sie unter http://guides.rubyonrails.org/routing.html
end

Speichern und schließen Sie die Datei, wenn Sie mit der Bearbeitung fertig sind.

Mit diesen Änderungen können Sie damit fortfahren, Ihren posts-Controller zu aktualisieren.

Schritt 3 — Aktualisierung des Posts-Controllers

Die Verbindung zwischen unseren Modellen gibt uns Methoden, die wir verwenden können, um neue Post-Instanzen zu erstellen, die mit bestimmten Haien verbunden sind. Um diese Methoden zu verwenden, müssen wir sie unserem Posts-Controller hinzufügen.

Öffnen Sie die Datei des Posts-Controllers:

  1. nano app/controllers/posts_controller.rb

Aktuell sieht die Datei wie folgt aus:

~/sharkapp/controllers/posts_controller.rb
class PostsController < ApplicationController
  before_action :set_post, only: [:show, :edit, :update, :destroy]

  # GET /posts
  # GET /posts.json
  def index
    @posts = Post.all
  end

  # GET /posts/1
  # GET /posts/1.json
  def show
  end

  # GET /posts/new
  def new
    @post = Post.new
  end

  # GET /posts/1/edit
  def edit
  end

  # POST /posts
  # POST /posts.json
  def create
    @post = Post.new(post_params)

    respond_to do |format|
      if @post.save
        format.html { redirect_to @post, notice: 'Post was successfully created.' }
        format.json { render :show, status: :created, location: @post }
      else
        format.html { render :new }
        format.json { render json: @post.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /posts/1
  # PATCH/PUT /posts/1.json
  def update
    respond_to do |format|
      if @post.update(post_params)
        format.html { redirect_to @post, notice: 'Post was successfully updated.' }
        format.json { render :show, status: :ok, location: @post }
      else
        format.html { render :edit }
        format.json { render json: @post.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /posts/1
  # DELETE /posts/1.json
  def destroy
    @post.destroy
    respond_to do |format|
      format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_post
      @post = Post.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def post_params
      params.require(:post).permit(:body, :shark_id)
    end
end

Wie unser Controller für Haie arbeitet auch dieser Controller mit Instanzen der zugehörigen Post-Klasse. Zum Beispiel erstellt die Methode new eine neue Instanz der Klasse Post, die Methode index greift auf alle Instanzen der Klasse zu, und die Methode set_post verwendet find und params, um einen bestimmten Beitrag nach der id auszuwählen. Wenn wir jedoch möchten, dass unsere Beitragsexemplare mit bestimmten Hai-Exemplaren verbunden sind, müssen wir diesen Code ändern, da die Klasse Post derzeit als unabhängige Entität fungiert.

Unsere Änderungen werden zwei Dinge nutzen:

  • Die Methoden, die uns zur Verfügung stehen, wenn wir die belongs_to– und has_many-Verknüpfungen zu unseren Modellen hinzugefügt haben. Speziell haben wir jetzt Zugriff auf die build-Methode dank der von uns definierten has_many-Verknüpfung in unserem Shark-Modell. Diese Methode ermöglicht es uns, eine Sammlung von Beitrag-Objekten zu erstellen, die mit einem bestimmten Hai-Objekt verknüpft sind, indem wir den shark_id-Fremdschlüssel verwenden, der in unserer posts-Datenbank vorhanden ist.
  • Die Routen und Routenhelfer, die verfügbar wurden, als wir eine verschachtelte posts-Route erstellt haben. Für eine vollständige Liste von Beispielrouten, die verfügbar werden, wenn Sie verschachtelte Beziehungen zwischen Ressourcen erstellen, siehe die Rails-Dokumentation. Für jetzt wird es für uns ausreichen zu wissen, dass für jeden spezifischen Hai — sagen wir sharks/1 — es eine zugehörige Route für Beiträge gibt, die mit diesem Hai verbunden sind: sharks/1/posts. Es wird auch Routenhelfer wie shark_posts_path(@shark) und edit_sharks_posts_path(@shark) geben, die sich auf diese verschachtelten Routen beziehen.

In der Datei werden wir damit beginnen, eine Methode namens get_shark zu schreiben, die vor jeder Aktion im Controller ausgeführt wird. Diese Methode wird eine lokale @shark-Instanzvariable erstellen, indem sie eine Hai-Instanz nach shark_id findet. Mit dieser Variable, die uns in der Datei zur Verfügung steht, wird es möglich sein, Beiträge in den anderen Methoden mit einem bestimmten Hai in Beziehung zu setzen.

Über den anderen private Methoden am Ende der Datei fügen Sie die folgende Methode hinzu:

~/sharkapp/controllers/posts_controller.rb
. . . 
private
  def get_shark
@shark = Shark.find(params[:shark_id])
end
  # Verwenden Sie Rückrufe, um gemeinsame Einrichtung oder Einschränkungen zwischen Aktionen zu teilen.
. . . 

Als nächstes fügen Sie den entsprechenden Filter oben in die Datei ein, bevor der vorhandene Filter hinzugefügt wird:

~/sharkapp/controllers/posts_controller.rb
class PostsController < ApplicationController
  before_action :get_shark

Dies stellt sicher, dass get_shark vor jeder in der Datei definierten Aktion ausgeführt wird.

Als nächstes können Sie diese @shark-Instanz verwenden, um die index-Methode neu zu schreiben. Anstatt alle Instanzen der Klasse Post abzurufen, möchten wir, dass diese Methode alle Postinstanzen zurückgibt, die mit einer bestimmten Haiinstanz verknüpft sind.

Ändern Sie die index-Methode so:

~/sharkapp/controllers/posts_controller.rb
. . .
  def index
    @posts = @shark.posts
  end
. . .

Die new-Methode benötigt eine ähnliche Überarbeitung, da wir möchten, dass eine neue Postinstanz mit einem bestimmten Hai verknüpft wird. Um dies zu erreichen, können wir die build-Methode zusammen mit unserer lokalen @shark-Instanzvariable verwenden.

Ändern Sie die new-Methode wie folgt:

~/sharkapp/controllers/posts_controller.rb
. . . 
  def new
    @post = @shark.posts.build
  end
. . . 

Diese Methode erstellt ein Postobjekt, das mit der spezifischen Haiinstanz aus der get_shark-Methode verknüpft ist.

Als nächstes werden wir uns der Methode widmen, die am engsten mit new verbunden ist: create. Die create-Methode tut zwei Dinge: Sie erstellt eine neue Postinstanz mit den Parametern, die Benutzer in das new-Formular eingegeben haben, und wenn keine Fehler auftreten, speichert sie diese Instanz und verwendet einen Routenhelfer, um Benutzer dorthin umzuleiten, wo sie den neuen Beitrag sehen können. Im Falle von Fehlern rendert es das new-Template erneut.

Aktualisieren Sie die create-Methode, damit sie so aussieht:

~/sharkapp/controllers/posts_controller.rb
  def create
    @post = @shark.posts.build(post_params)

        respond_to do |format|
         if @post.save  
            format.html { redirect_to shark_posts_path(@shark), notice: 'Post was successfully created.' }
            format.json { render :show, status: :created, location: @post }
         else
            format.html { render :new }
            format.json { render json: @post.errors, status: :unprocessable_entity }
      end
    end
  end

Als nächstes werfen Sie einen Blick auf die update-Methode. Diese Methode verwendet eine @post-Instanzvariable, die nicht explizit in der Methode selbst festgelegt ist. Woher stammt diese Variable?

Schauen Sie sich die Filter oben in der Datei an. Der zweite, automatisch generierte before_action-Filter liefert eine Antwort:

~/sharkapp/controllers/posts_controller.rb
class PostsController < ApplicationController
  before_action :get_shark
  before_action :set_post, only: [:show, :edit, :update, :destroy]
  . . .

Die update-Methode (wie show, edit und destroy) nimmt eine @post-Variable aus der set_post-Methode. Diese Methode, aufgeführt unter der get_shark-Methode mit unseren anderen private-Methoden, sieht derzeit so aus:

~/sharkapp/controllers/posts_controller.rb
. . . 
private
. . . 
  def set_post
    @post = Post.find(params[:id])
  end
. . .

Im Einklang mit den Methoden, die wir anderswo in der Datei verwendet haben, müssen wir diese Methode ändern, damit @post auf eine bestimmte Instanz in der Sammlung von Posts verweist, die mit einem bestimmten Hai verbunden ist. Behalten Sie hier die build-Methode im Hinterkopf – dank der Beziehungen zwischen unseren Modellen und den Methoden (wie build), die uns durch diese Beziehungen zur Verfügung stehen, ist jede unserer Postinstanzen Teil einer Sammlung von Objekten, die mit einem bestimmten Hai verbunden ist. Es ergibt also Sinn, dass wir beim Abfragen eines bestimmten Posts die Sammlung von Posts abfragen, die mit einem bestimmten Hai verbunden ist.

Aktualisieren Sie set_post, damit es so aussieht:

~/sharkapp/controllers/posts_controller.rb
. . . 
private
. . . 
  def set_post
    @post = @shark.posts.find(params[:id])
  end
. . .

Anstatt eine bestimmte Instanz der gesamten Post-Klasse nach id zu suchen, suchen wir stattdessen nach einer übereinstimmenden id in der Sammlung von Posts, die mit einem bestimmten Hai verbunden ist.

Mit dieser aktualisierten Methode können wir uns die update und destroy Methoden ansehen.

Die update Methode verwendet die @post Instanzvariable von set_post und verwendet sie mit den post_params, die der Benutzer im edit Formular eingegeben hat. Im Erfolgsfall möchten wir, dass Rails den Benutzer zur index Ansicht der Beiträge eines bestimmten Hais zurücksendet. Im Fehlerfall rendert Rails erneut das edit Template.

In diesem Fall müssen wir nur die redirect_to Anweisung ändern, um erfolgreiche Updates zu behandeln. Aktualisieren Sie sie so, dass sie zu shark_post_path(@shark) umleitet, was zur index Ansicht der Beiträge des ausgewählten Hais umleitet:

~/sharkapp/controllers/posts_controller.rb
. . . 
  def update
    respond_to do |format|
      if @post.update(post_params)
        format.html { redirect_to shark_post_path(@shark), notice: 'Post was successfully updated.' }
        format.json { render :show, status: :ok, location: @post }
      else
        format.html { render :edit }
        format.json { render json: @post.errors, status: :unprocessable_entity }
      end
    end
  end
. . .

Als nächstes machen wir eine ähnliche Änderung an der destroy Methode. Aktualisieren Sie die redirect_to Methode, um Anfragen im Erfolgsfall an shark_posts_path(@shark) umzuleiten:

~/sharkapp/controllers/posts_controller.rb
. . . 
  def destroy
    @post.destroy
     respond_to do |format|
      format.html { redirect_to shark_posts_path(@shark), notice: 'Post was successfully destroyed.' }
      format.json { head :no_content }
    end
  end
. . .

Dies ist die letzte Änderung, die wir vornehmen werden. Sie haben jetzt eine Post-Controller-Datei, die folgendermaßen aussieht:

~/sharkapp/controllers/posts_controller.rb
class PostsController < ApplicationController
  before_action :get_shark
  before_action :set_post, only: [:show, :edit, :update, :destroy]

  # GET /posts
  # GET /posts.json
  def index
    @posts = @shark.posts
  end

  # GET /posts/1
  # GET /posts/1.json
  def show
  end

  # GET /posts/new
  def new
    @post = @shark.posts.build
  end

  # GET /posts/1/edit
  def edit
  end

  # POST /posts
  # POST /posts.json
  def create
    @post = @shark.posts.build(post_params)

        respond_to do |format|
         if @post.save  
            format.html { redirect_to shark_posts_path(@shark), notice: 'Post was successfully created.' }
            format.json { render :show, status: :created, location: @post }
         else
            format.html { render :new }
            format.json { render json: @post.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /posts/1
  # PATCH/PUT /posts/1.json
  def update
    respond_to do |format|
      if @post.update(post_params)
        format.html { redirect_to shark_post_path(@shark), notice: 'Post was successfully updated.' }
        format.json { render :show, status: :ok, location: @post }
      else
        format.html { render :edit }
        format.json { render json: @post.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /posts/1
  # DELETE /posts/1.json
  def destroy
    @post.destroy
    respond_to do |format|
      format.html { redirect_to shark_posts_path(@shark), notice: 'Post was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private

   def get_shark
     @shark = Shark.find(params[:shark_id])
   end
    # Use callbacks to share common setup or constraints between actions.
    def set_post
      @post = @shark.posts.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def post_params
      params.require(:post).permit(:body, :shark_id)
    end
end

Der Controller verwaltet, wie Informationen zwischen den Ansichtsvorlagen und der Datenbank übergeben werden und umgekehrt. Unser Controller spiegelt nun die Beziehung zwischen unseren Modellen Shark und Post wider, bei der Posts mit bestimmten Haien verbunden sind. Wir können nun damit fortfahren, die Ansichtsvorlagen selbst zu ändern, in denen Benutzer Postinformationen zu bestimmten Haien eingeben und ändern.

Schritt 4 — Ansichten anpassen

Unsere Überarbeitung der Ansichtsvorlagen beinhaltet die Änderung der Vorlagen, die sich auf Posts beziehen, und die Modifikation unserer Haiansicht show, da wir möchten, dass Benutzer die mit bestimmten Haien verbundenen Posts sehen.

Beginnen wir mit der grundlegenden Vorlage für unsere Posts: dem form-Partial, das in mehreren Post-Vorlagen wiederverwendet wird. Öffnen Sie dieses Formular jetzt:

  1. nano app/views/posts/_form.html.erb

Anstatt nur das post-Modell dem form_with-Formularhelfer zu übergeben, geben wir sowohl die Modelle shark als auch post weiter, wobei post als untergeordnete Ressource festgelegt ist.

Ändern Sie die erste Zeile der Datei so, dass sie wie folgt aussieht, um die Beziehung zwischen unseren Hai- und Post-Ressourcen widerzuspiegeln:

~/sharkapp/views/posts/_form.html.erb
<%= form_with(model: [@shark, post], local: true) do |form| %>
. . . 

Löschen Sie als Nächstes den Abschnitt, der die shark_id des zugehörigen Hais auflistet, da diese Information in der Ansicht nicht wesentlich ist.

Das fertige Formular, komplett mit unseren Bearbeitungen der ersten Zeile und ohne den gelöschten Abschnitt shark_id, wird wie folgt aussehen:

~/sharkapp/views/posts/_form.html.erb
<%= form_with(model: [@shark, post], local: true) do |form| %>
  <% if post.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(post.errors.count, "error") %> prohibited this post from being saved:</h2>

      <ul>
      <% post.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= form.label :body %>
    <%= form.text_area :body %>
  </div>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>

Speichern Sie die Datei und schließen Sie sie, wenn Sie mit der Bearbeitung fertig sind.

Öffnen Sie als Nächstes die Ansicht index, die die mit einem bestimmten Hai verbundenen Beiträge anzeigt:

  1. nano app/views/posts/index.html.erb

Dank des Befehls rails generate scaffold hat Rails den Großteil der Vorlage generiert, komplett mit einer Tabelle, die das Feld body jedes Beitrags und seinen zugehörigen shark anzeigt.

Wie bei dem anderen Code, den wir bereits geändert haben, behandelt diese Vorlage jedoch Beiträge als unabhängige Entitäten, während wir die Beziehungen zwischen unseren Modellen und die Sammlungen und Hilfsmethoden nutzen möchten, die uns diese Beziehungen geben.

Aktualisieren Sie im Tabellenkörper Folgendes:

Ersetzen Sie zunächst post.shark durch post.shark.name, damit die Tabelle das Namensfeld des zugehörigen Hais enthält, anstatt Informationen über das Hai-Objekt selbst zu identifizieren:

~/sharkapp/app/views/posts/index.html.erb
. . . 
  <tbody>
    <% @posts.each do |post| %>
      <tr>
        <td><%= post.body %></td>
        <td><%= post.shark.name %></td>
. . . 

Als nächstes ändern Sie die Umleitung von Show, um Benutzer zur show-Ansicht des zugehörigen Haies zu führen, da sie wahrscheinlich einen Weg zurück zum ursprünglichen Hai wünschen werden. Wir können die @shark-Instanzvariable nutzen, die wir hier im Controller gesetzt haben, da Rails Instanzvariablen, die im Controller erstellt wurden, allen Ansichten zur Verfügung stellt. Wir ändern auch den Text für den Link von Show auf Hai anzeigen, damit Benutzer seine Funktion besser verstehen.

Aktualisieren Sie diese Zeile wie folgt:

~/sharkapp/app/views/posts/index.html.erb
. . . 
  <tbody>
    <% @posts.each do |post| %>
      <tr>
        <td><%= post.body %></td>
        <td><%= post.shark.name %></td>
        <td><%= link_to 'Show Shark', [@shark] %></td>

In der nächsten Zeile möchten wir sicherstellen, dass Benutzer den richtigen verschachtelten Pfad geroutet bekommen, wenn sie einen Beitrag bearbeiten. Das bedeutet, dass Benutzer nicht zu posts/post_id/edit weitergeleitet werden, sondern zu sharks/shark_id/posts/post_id/edit. Dazu verwenden wir den Routing-Helfer shark_post_path und unsere Modelle, die Rails als URLs behandeln wird. Wir aktualisieren auch den Linktext, um seine Funktion klarer zu machen.

Aktualisieren Sie die Zeile Edit wie folgt:

~/sharkapp/app/views/posts/index.html.erb
. . . 
  <tbody>
    <% @posts.each do |post| %>
      <tr>
        <td><%= post.body %></td>
        <td><%= post.shark.name %></td>
        <td><%= link_to 'Show Shark', [@shark] %></td>
        <td><%= link_to 'Edit Post', edit_shark_post_path(@shark, post) %></td>

Als nächstes fügen wir eine ähnliche Änderung zum Löschen-Link hinzu, aktualisieren seine Funktion in der Zeichenkette und fügen unsere Ressourcen shark und post hinzu:

~/sharkapp/app/views/posts/index.html.erb
. . . 
  <tbody>
    <% @posts.each do |post| %>
      <tr>
        <td><%= post.body %></td>
        <td><%= post.shark.name %></td>
        <td><%= link_to 'Show Shark', [@shark] %></td>
        <td><%= link_to 'Edit Post', edit_shark_post_path(@shark, post) %></td>
        <td><%= link_to 'Destroy Post', [@shark, post], method: :delete, data: { confirm: 'Are you sure?' } %></td>

Zuletzt möchten wir am Ende des Formulars den Pfad Neuer Beitrag aktualisieren, um Benutzer zum entsprechenden verschachtelten Pfad zu führen, wenn sie einen neuen Beitrag erstellen möchten. Aktualisieren Sie die letzte Zeile der Datei, um den Routing-Helfer new_shark_post_path(@shark) zu verwenden:

~/sharkapp/app/views/posts/index.html.erb
. . . 
<%= link_to 'New Post', new_shark_post_path(@shark) %>

Die fertige Datei wird wie folgt aussehen:

~/sharkapp/app/views/posts/index.html.erb
<p id="notice"><%= notice %></p>

<h1>Posts</h1>

<table>
  <thead>
    <tr>
      <th>Body</th>
      <th>Shark</th>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @posts.each do |post| %>
      <tr>
        <td><%= post.body %></td>
        <td><%= post.shark.name %></td>
        <td><%= link_to 'Show Shark', [@shark] %></td>
        <td><%= link_to 'Edit Post', edit_shark_post_path(@shark, post) %></td>
        <td><%= link_to 'Destroy Post', [@shark, post], method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<br>

<%= link_to 'New Post', new_shark_post_path(@shark) %>

Speichern Sie die Datei und schließen Sie sie, wenn Sie mit der Bearbeitung fertig sind.

Die anderen Änderungen, die wir an den Beitragansichten vornehmen werden, werden nicht so zahlreich sein, da unsere anderen Ansichten das bereits bearbeitete form-Partial verwenden. Wir möchten jedoch die link_to-Verweise in den anderen Beitragstemplates aktualisieren, um die Änderungen, die wir an unserem form-Partial vorgenommen haben, widerzuspiegeln.

Öffnen Sie app/views/posts/new.html.erb:

  1. nano app/views/posts/new.html.erb

Aktualisieren Sie den link_to-Verweis am Ende der Datei, um den shark_posts_path(@shark)-Helfer zu verwenden:

~/sharkapp/app/views/posts/new.html.erb
. . . 
<%= link_to 'Back', shark_posts_path(@shark) %>

Speichern Sie die Datei und schließen Sie sie, wenn Sie diese Änderung abgeschlossen haben.

Öffnen Sie als nächstes das Bearbeiten-Template:

  1. nano app/views/posts/edit.html.erb

Neben dem Zurück-Pfad aktualisieren wir Anzeigen, um unsere verschachtelten Ressourcen widerzuspiegeln. Ändern Sie die letzten beiden Zeilen der Datei so:

~/sharkapp/app/views/posts/edit.html.erb
. . . 
<%= link_to 'Show', [@shark, @post] %> |
<%= link_to 'Back', shark_posts_path(@shark) %>

Speichern und schließen Sie die Datei.

Öffnen Sie als nächstes das Anzeigen-Template:

nano app/views/posts/show.html.erb

Führen Sie folgende Änderungen am Bearbeiten– und Zurück-Pfad am Ende der Datei durch:

~/sharkapp/app/views/posts/edit.html.erb
. . .
<%= link_to 'Edit', edit_shark_post_path(@shark, @post) %> |
<%= link_to 'Back', shark_posts_path(@shark) %>

Speichern Sie die Datei und schließen Sie sie, wenn Sie fertig sind.

Als letzten Schritt möchten wir die Anzeigen-Ansicht für unsere Haie aktualisieren, damit Beiträge für einzelne Haie sichtbar sind. Öffnen Sie jetzt diese Datei:

  1. nano app/views/sharks/show.html.erb

Unsere Änderungen hier umfassen das Hinzufügen eines Beiträge-Abschnitts zum Formular und einen Beitrag hinzufügen-Link am Ende der Datei.

Unterhalb der Facts für einen bestimmten Hai werden wir einen neuen Abschnitt hinzufügen, der durch jede Instanz in der Sammlung von Beiträgen dieses Haies iteriert und den body jedes Beitrags ausgibt.

Fügen Sie den folgenden Code unterhalb des Facts-Abschnitts des Formulars und über den Weiterleitungen am Ende der Datei hinzu:

~/sharkapp/app/views/sharks/show.html.erb
. . .
<p>
  <strong>Facts:</strong>
  <%= @shark.facts %>
</p>

<h2>Posts</h2>
<% for post in @shark.posts %>
    <ul>
      <li><%= post.body %></li>
  </ul>
<% end %>

<%= link_to 'Edit', edit_shark_path(@shark) %> |
. . . 

Fügen Sie als nächstes eine neue Weiterleitung hinzu, damit Benutzer einen neuen Beitrag für diesen bestimmten Hai hinzufügen können:

~/sharkapp/app/views/sharks/show.html.erb
. . .
<%= link_to 'Edit', edit_shark_path(@shark) %> |
<%= link_to 'Add Post', shark_posts_path(@shark) %> |
<%= link_to 'Back', sharks_path %>

Speichern und schließen Sie die Datei, wenn Sie mit der Bearbeitung fertig sind.

Sie haben nun Änderungen an den Modellen, Controllern und Ansichten Ihrer Anwendung vorgenommen, um sicherzustellen, dass Beiträge immer mit einem bestimmten Hai verknüpft sind. Als letzter Schritt können wir einige Validierungen zu unserem Post-Modell hinzufügen, um die Konsistenz der Daten zu gewährleisten, die in die Datenbank gespeichert werden.

Schritt 5 — Validierungen hinzufügen und die Anwendung testen

Im Schritt 5 von Wie man eine Ruby on Rails Anwendung erstellt, haben Sie Validierungen zu Ihrem Shark-Modell hinzugefügt, um Einheitlichkeit und Konsistenz in den Daten sicherzustellen, die in die sharks-Datenbank gespeichert werden. Nun werden wir einen ähnlichen Schritt unternehmen, um Garantien für die posts-Datenbank sicherzustellen.

Öffnen Sie die Datei, in der Ihr Post-Modell definiert ist:

  1. nano app/models/post.rb

Hier möchten wir sicherstellen, dass Beiträge nicht leer sind und dass sie keine doppelten Inhalte enthalten, die andere Benutzer möglicherweise gepostet haben. Um dies zu erreichen, fügen Sie die folgende Zeile zur Datei hinzu:

~/sharkapp/app/models/post.rb
class Post < ApplicationRecord
  belongs_to :shark
  validates :body, presence: true, uniqueness: true
end

Speichern Sie die Datei und schließen Sie sie, wenn Sie mit der Bearbeitung fertig sind.

Mit dieser letzten Änderung sind Sie bereit, Ihre Migrationen auszuführen und die Anwendung zu testen.

Führen Sie zuerst Ihre Migrationen aus:

  1. rails db:migrate

Starten Sie anschließend Ihren Server. Wenn Sie lokal arbeiten, können Sie dies tun, indem Sie folgendes ausführen:

  1. rails s

Wenn Sie auf einem Entwicklungsserver arbeiten, führen Sie stattdessen den folgenden Befehl aus:

  1. rails s --binding=your_server_ip

Navigieren Sie zu Ihrem Anwendungsstamm unter http://localhost:3000 oder http://Ihre_Server_IP:3000.

Das vorherige Rails-Projekt-Tutorial führte Sie durch das Hinzufügen und Bearbeiten eines Weißen Hais-Eintrags. Wenn Sie keine weiteren Haie hinzugefügt haben, wird die Startseite der Anwendung folgendermaßen aussehen:

Klicken Sie auf Anzeigen neben dem Namen des Great White. Dadurch gelangen Sie zur Anzeigen-Ansicht für diesen Hai. Sie sehen den Namen des Haies und seine Fakten sowie einen Beiträge-Header ohne Inhalt. Fügen wir einen Beitrag hinzu, um diesen Teil des Formulars auszufüllen.

Klicken Sie unter dem Beiträge-Header auf Beitrag hinzufügen. Dadurch gelangen Sie zur Beitrag Index-Ansicht, wo Sie die Möglichkeit haben, Neuer Beitrag auszuwählen:

Dank der Authentifizierungsmechanismen, die Sie in Schritt 6 von So erstellen Sie eine Ruby on Rails-Anwendung implementiert haben, kann es sein, dass Sie aufgefordert werden, sich mit dem Benutzernamen und dem Passwort, die Sie in diesem Schritt erstellt haben, zu authentifizieren, abhängig davon, ob Sie eine neue Sitzung erstellt haben oder nicht.

Klicken Sie auf Neuer Beitrag, um zu Ihrer Beitrag Neu-Vorlage zu gelangen:

Geben Sie im Inhalt-Feld „Diese Haie sind gruselig!“ ein.

Klicken Sie auf Beitrag erstellen. Sie werden zur Index-Ansicht für alle Beiträge, die zu diesem Hai gehören, weitergeleitet:

Mit unseren Beitrag-Ressourcen funktioniert, können wir jetzt unsere Datenvalidierungen testen, um sicherzustellen, dass nur gewünschte Daten in die Datenbank gespeichert werden.

Von der Index-Ansicht aus klicken Sie auf Neuer Beitrag. Geben Sie im Inhalt-Feld des neuen Formulars erneut „Diese Haie sind gruselig!“ ein:

Klicken Sie auf Beitrag erstellen. Sie werden den folgenden Fehler sehen:

Klicken Sie auf Zurück, um zur Hauptseite der Beiträge zurückzukehren.

Um unsere andere Validierung zu testen, klicken Sie erneut auf Neuer Beitrag. Lassen Sie den Beitrag leer und klicken Sie auf Beitrag erstellen. Sie werden den folgenden Fehler sehen:

Mit Ihren verschachtelten Ressourcen und Validierungen, die ordnungsgemäß funktionieren, haben Sie jetzt eine funktionierende Rails-Anwendung, die Sie als Ausgangspunkt für weitere Entwicklung verwenden können.

Abschluss

Mit Ihrer Rails-Anwendung können Sie jetzt an Dingen wie Styling und der Entwicklung anderer Frontend-Komponenten arbeiten. Wenn Sie mehr über Routing und verschachtelte Ressourcen erfahren möchten, ist die Rails-Dokumentation ein großartiger Ausgangspunkt.

Um mehr über die Integration von Frontend-Frameworks in Ihre Anwendung zu erfahren, werfen Sie einen Blick auf Wie man ein Ruby-on-Rails-Projekt mit einem React-Frontend einrichtet.

Source:
https://www.digitalocean.com/community/tutorials/how-to-create-nested-resources-for-a-ruby-on-rails-application