[Ruby on Rails] Hinzufügen und Löschen von Tags und Anzeigen von (Erfolgs- / Fehler-) Meldungen mit Ajax.

Umgebung

Ruby 2.5.7 Rails 5.2.4

Bibliothek

jQuery 1.12.4

Annahme

Dieses Mal werde ich anhand der Tag-Tabelle erklären.

Bitte bestätigen Sie zunächst im Voraus, dass Sie Tags hinzufügen und entfernen können, ohne Ajax zu verwenden.

Ich werde nicht auf die japanische Lokalisierung von Fehlermeldungen und Assoziationen eingehen. Wenn Sie sie benötigen, tun Sie dies bitte selbst.

Turbolinks ist deaktiviert. (Wir haben den Vorgang nicht bestätigt, wenn er aktiviert ist.)

Verfahren

Wie der Titel schon sagt, werden wir in den folgenden Schritten Ajax verwenden, um Tags hinzuzufügen / zu löschen und Fehlermeldungen anzuzeigen.

  1. Validierungseinstellungen in tag.rb
  2. Vorbereitung von Teilvorlagen (views / layouts / _error_messages.html.erb, views / layouts / _flash_messages.html.erb, views / tags / _tag.html.erb)
  3. Erstellen Sie einen Tag-Listenbildschirm und ein neues Formular (views / tags / index.html.erb).
  4. Bereiten Sie js.erb für jede Aktion vor (views / tags / create.js.erb, views / tags / destroy.js.erb)
  5. Vorbereitung von tags_controller.rb (: index ,: create ,: destroy)

Wenn Sie als Bild auf die Schaltfläche "Senden" klicken, wird die Erstellungsaktion des Controllers ausgeführt. Die Methode, die create.js.erb aufruft, wird in der Aktion create ausgeführt In create.js.erb geschriebenes JavaScript (jQuery) wird ausgelöst Die DOM-Manipulation überschreibt das Fehlermeldungenelement und das Taglistenelement (jQuery .html () Methode) Gleiches gilt für die Zerstörungsaktion beim Löschen.

Als Ablauf des ausgefüllten Formulars

  1. Geben Sie einen Wert in das Formular auf dem Indexbildschirm ein. 1-1. Speichern Sie ein neues Tag, falls es nicht vorhanden ist (Erfolgsmeldung). 1-2. Wenn das Tag vorhanden ist, speichern Sie den Fehler (Validierungsfehlermeldung). 1-3. Wenn leer, Speichern fehlgeschlagen (Validierungsfehlermeldung)

  2. Löschen Sie einzelne Tags 1-1. Erfolgsmeldung anzeigen

Da alle Ajax sind, wird nicht die gesamte Seite aktualisiert.

1. Validierungseinstellungen in tag.rb

tag.rb


class Tag < ApplicationRecord

  ...

  #Verbietet Leerzeichen und gewährt Eindeutigkeit (doppeltes NG).
  validates :name, presence: true, uniqueness: true

end

2. Vorbereitung von Teilvorlagen (layouts / _error_messages.html.erb, layouts / _flash_messages.html.erb, _tag.html.erb)

Die drei hier erstellten Teilvorlagen werden entsprechend der Aktion durch DOM-Operationen überschrieben. Wenn Sie in jQuery schreiben, ist dies redundant, da Sie DOM-Operationen zeilenweise ausführen. Verwenden Sie daher Teilvorlagen, damit die später beschriebene jQuery mit <% = render ...%> 1 Zeile ausgeführt werden kann Es ist geworden.

Teilvorlage für Validierungsfehlermeldung Wenn Sie bereits eine haben, können Sie diese verwenden.

erb:layouts/_error_messages.html.erb


<% if model.errors.any? %>
  <div id="validation-errors">
    <p><%= model.errors.count %>Es gibt einige Fehler.</p>
    <ul class="error-messages">
      <% model.errors.full_messages.each do |message| %>
        <li class="error-message"><%= message %></li>
      <% end %>
    </ul>
  </div>
<% end %>

Wenn beim Überschreiben durch die DOM-Manipulation von jQuery ein Validierungsfehler auftritt, wird eine Fehlermeldung angezeigt. Ersetzen Sie die lokale Variable model durch @ tag (Tag.new) in index.html.erb, was später beschrieben wird.

Als nächstes eine Teilvorlage für Erfolgsmeldungen (Flash-Nachrichten) Wenn Sie dies bereits haben, verwenden Sie es bitte.

erb:layouts/_flash_messages.html.erb


<% flash.each do |key, value| %>
  <p class="alert alert-<%= key %>">
    <%= value %>
  </p>
<% end %>

Es soll mit jedem aus dem Array kommen, aber dies dient nicht dazu, mehrere Flash-Nachrichten zu erhalten, aber jeder Schlüssel (flash [key]) kann mit diesem einen Satz erneut angezeigt werden Ich werde. Diesmal werden zwei Arten von Schlüsseln verwendet: "[: Erfolg]" und "[: Warnung]". (Diese beiden Typen sind übrigens auch im Bootstrap verfügbar, daher habe ich mich diesmal entschieden.) Wenn Sie diese beiden verwenden, können Sie die Teilvorlage wie folgt umschreiben.

erb:layouts/_flash_messages.html.erb


<% case flash.keys[0] %>
  <% when "success" %>
  <p class="alert alert-<%= flash.keys[0] %>">
    <%= flash[:success] %>
  </p>
  <% when "warning" %>
  <p class="alert alert-<%= flash.keys[0] %>">
    <%= flash[:warning] %>
  </p>
<% end %>

Die in Flash gespeicherten Schlüssel sind Arrays, daher müssen sie "Schlüssel [0]" sein. Ändern Sie die anzuzeigende Flash-Nachricht gemäß dem Schlüsselmuster in der case-Anweisung. Der Grund für die Verwendung von "keys [0]" in der Klasse des p-Elements besteht darin, das Design von css abhängig vom Schlüssel zu ändern (Erfolg oder Warnung in diesem Fall).

Dies macht es jedoch überflüssig, da die Anzahl der Zeilen jedes Mal erhöht werden muss, wenn die Anzahl der Schlüsseltypen (Schlüsselnamen können beliebig angegeben werden) zunimmt.

Daher wird dieses Mal durch die Verwendung jeder Anweisung der Fehler beseitigt. Indem Sie es zu einer Teilvorlage machen, können Sie es auch in anderen Ansichten sowie in der Validierungsfehlermeldung wiederverwenden.

Teilvorlage zur Anzeige der nächsten Tag-Liste

erb:tags/_tag.html.erb


<div class="tags-index__tags--tag">
  <%= tag.name %>(<%= tag.menu_tag_ids.count %>)
  <%= link_to 'X', tag_path(tag), method: :delete, remote: true %>
</div>

Wenn Sie keine Teilvorlage verwenden, müssen Sie 4 Zeilen mit jQuery schreiben, was später beschrieben wird. Ich möchte DOM-Vorgänge mit jQuery so einfach wie möglich verwalten, also habe ich es zu einer Teilvorlage gemacht. Die lokale Variable "tag" wird automatisch als einzelne lokale Variable "tag" in der Teilvorlage ersetzt, indem die Instanzvariable "@ tags" (Tag.all) in index.html.erb angegeben wird. (Ich werde in index.html.erb ausführlich erklären.) (<% = tag.menu_tag_ids.count%>) zeigt die Anzahl der Menüs an, für die das Tag neben dem Tag-Namen verwendet wird. (Menütabelle (weggelassen) 1: Multi-Menü-Tag-Tabelle (Zwischentabelle) (weggelassen) Multi: 1-Tag-Tabelle (diesmal)) Für <% = link_to'X ', tag_path (tag), method :: delete, remote: true%> wird durch Drücken von X die Zerstörungsaktion ausgelöst. Durch Setzen von "remote: true" wird angegeben, dass es sich um eine Ajax-Kommunikation handelt.

Wie "remote: true" funktioniert Bei einer normalen Anforderung (Link) wird HTML erfasst, bei einer Anforderung mit dem Attribut "remote: true" (Attribut "data-remote =" true ") nach der HTML-Konvertierung wird jedoch nur die JS-Datei erfasst. ..
Im Fall von Rails gibt es ein Tag, das js im Tag von layouts / application.html.erb liest. Wenn also HTML erfasst wird, wird js normalerweise auch automatisch neu geladen. Dies gilt nicht, wenn Sie Turbolinks verwenden.

3. Erstellen Sie einen Tag-Listenbildschirm und ein neues Formular (views / tags / index.html.erb).

Wir werden auch einen Tag-Listenbildschirm und ein neues Eingabeformular darin erstellen.

erb:views/tags/index.html.erb


<div class="contents tags-index">
  <div class="tags-index--messages"><!--Anzeigebereich für Nachrichten--></div>
  <h2>Tag-Liste</h2>
  <div class="tags-index__list" id="tags-index--tag-list">
    <%= render @tags %>
  </div>
  <div class="tags-index__form">
    <%= form_with model: @tag, url: tags_path(@tag) do |f| %>
      <%= f.text_field :name %>
      <%= f.submit %>
    <% end %>
  </div>
</div>

Das neu hinzugefügte Formular wird am Ende der Tag-Liste angehängt.

Das neue Registrierungsformular verwendet form_with. form_with ist optional, da der Standard das Attribut remote: true hat. (Wenn Sie form_for verwenden, müssen Sie das Attribut remote: true angeben.) Wenn Sie ajax in form_with nicht verwenden, müssen Sie das Attribut local: true angeben. Der Formular-Helfer teilt der Aktion nur JS mit, wenn "remote: true" und HTML, wenn "local: true". Da die Standard-HTTP-Methode des Formular-Helfers auch POST ist, ist method :: post auch __optional __.

Die Instanzvariable @ tags von <% = render @ tags%> erhält auf der später beschriebenen ControllerseiteTag.all. Es ist eine ungewohnte Art, eine Teilvorlage zu schreiben, aber in dieser Abkürzung Teilvorlage wird "_variable name.html.erb", die dem Variablennamen entspricht, und die lokale Variable ("in der Teilvorlage in diesem Fall" in dieser Teilvorlage aufgerufen. Es kann als Tag verwendet werden`). Wenn Sie es diesmal als Array wie "@ tags" erhalten, wird es in der Teilvorlage so oft wie die Nummer des Arrays wiederholt angezeigt. Dies kann wie folgt umgeschrieben werden.

erb:views/tags/index.html.erb


<%= render partial: 'tag', locals: {tags: @tags} %>

erb:views/tags/_tag.html.erb


<% tags.each do |tag| %>
  <div class="tags-index__tags--tag">
    <%= tag.name %>(<%= tag.menu_tag_ids.count %>)
    <%= link_to 'X', tag_path(tag), method: :delete, remote: true %>
  </div>
<% end %>

Die diesmalige Beschreibungsmethode ist eine Abkürzung davon. [Rails Guide-Layout und Rendering](https://railsguides.jp/layouts_and_rendering.html#%E3%83%91%E3%83%BC%E3%82%B7%E3%83%A3%E3%83% AB% E3% 82% 92% E4% BD% BF% E7% 94% A8% E3% 81% 99% E3% 82% 8B)

4. Bereiten Sie js.erb für jede Aktion vor (views / tags / create.js.erb, views / tags / destroy.js.erb)

Erstellen Sie js (.erb), um vom Controller aus aufzurufen. Durch die Beschreibung von js hier wird die DOM-Operation von jQuery ausgeführt, die beim Erstellen bzw. Zerstören ausgelöst wird und vom Controller aufgerufen wird. Die hier verwendete .html () wird hinzugefügt, wenn dort kein Element vorhanden ist, und wird neu geschrieben, wenn bereits ein anderes Element vorhanden ist.

js (.erb) zum Zeitpunkt der Erstellung der Aktion

erb:views/tags/create.js.erb


<% if @tag.errors.any? %>
  $(".tags-index--messages").html("<p><%= j(render partial: 'layouts/error_messages', locals: {model: @tag}) %></p>")
<% else %>
  $(".tags-index--messages").html("<p><%= j(render partial: 'layouts/flash_messages', locals: {model: @tag}) %></p>")
  $("#tags-index--tag-list").html("<%= j(render @tags) %>")
  $("#tag_name").val('')
<% end %>

<% if @ tag.errors.any?%> Überprüft, ob beim Drücken der Senden-Schaltfläche ein Fehler in @ tag vorliegt.

Unterschied zwischen "object.errors.any?" und "object.invalid?" In diesem Fall befindet sich js.erb in einem Zustand, in dem festgestellt werden kann, ob in "@ tag" bereits ein Fehler aufgetreten ist, da create.js.erb aufgerufen wird, nachdem "@ tag.save" auf der Controllerseite versucht wurde. Ich komme vorbei. Andererseits validiert die Methode "ungültig?" Das nicht gespeicherte Objekt manuell. Wenn ein Objekt gespeichert werden soll (wenn ".save" versucht wird), wird normalerweise automatisch eine Validierungsprüfung ausgeführt, und diesmal wird die Aktion nach Erfolg oder Misserfolg von ".save" aufgeteilt, also manuell "ungültig?" Anstatt dies zu tun, ist es besser zu überprüfen, ob zum Zeitpunkt von ".save" (".errors.any?") Bereits ein Fehler aufgetreten ist.

Wenn ein Fehler auftritt (Leerzeichen oder doppelte Tag-Namen)

  • Fügen Sie Validierungsfehlermeldungen (error_messages.html.erb) zu $ (". Tags-index - messages ") hinzu oder schreiben Sie sie neu

Wenn kein Fehler aufgetreten ist (Speichern war erfolgreich)

  • Fügen Sie Flash-Nachrichten (flash_message.html.erb) zu $ (". Tags-index - messages ") hinzu oder schreiben Sie sie neu
  • Schreiben Sie die Tag-Liste neu ($ (" # tags-index - tag-list ")) -Löschen Sie den im Formular eingegebenen Tag-Namen ($ (" # tag_name "). Val (''))

Wird durchgeführt.

js (.erb) während der Zerstörungsaktion

erb:views/tags/destroy.js.erb


$(".tags-index--messages").html("<p><%= j(render partial: 'layouts/flash_messages', locals: {model: @tag}) %></p>")
$("#tags-index--tag-list").html("<%= j(render @tags) %>")

Gleich wie beim Erstellen.

  • Fügen Sie eine Flash-Nachricht hinzu oder schreiben Sie sie neu, wenn das Tag gelöscht wird ・ Umschreiben der Tag-Liste

Wird durchgeführt.

"Notwendigkeit eines Teils:" Wenn Sie Optionen mithilfe von render (in diesem Fall `local: {tag: @tag}`) hinzufügen müssen, geben Sie den Dateinamen (Pfad) an. Sie müssen `partiell:` vorher angeben. [Rails Guide-Layout und Rendering](https://railsguides.jp/layouts_and_rendering.html#%E3%83%91%E3%83%BC%E3%82%B7%E3%83%A3%E3%83% AB% E3% 82% 92% E4% BD% BF% E7% 94% A8% E3% 81% 99% E3% 82% 8B)

5. Vorbereitung von tags_controller.rb (: index ,: create ,: destroy)

Ich werde die notwendigen Aktionen dieses Mal auf dem Controller beschreiben

tags_controller.rb


class TagsController < ApplicationController

  def index
    @tags = Tag.all
    @tag = Tag.new
  end

  def create
    @tags = Tag.all
    @tag = Tag.new(tag_params)

    respond_to do |format|
      if @tag.save
        format.js { flash.now[:success] = "Ich habe es gespeichert." }
      else
        format.js
      end
    end
  end

  def destroy
    @tags = Tag.all
    @tag = Tag.new
    Tag.find(params[:id]).destroy
    flash.now[:warning] = "Es wurde gelöscht."
  end

  private
  def tag_params
    params.require(:tag).permit(:name)
  end

end

Dieses Mal geben form_with von create und link_to von destroy jeweils "remote: true" an (im Fall von form_with wird es weggelassen, da dies die Standardeinstellung ist), sodass beide nur JS anfordern.

tags_controller.rb


def create

  ...

  respond_to do |format|
    if @tag.save
      format.js { flash.now[:success] = "Ich habe es gespeichert." }
    else
      format.js
    end
  end
end

respond_to do |format|Ist ein Blockparameter, der die Verarbeitung nach dem Anforderungsformat unterteilt. Dieses Mal gehen wir nicht davon aus, dass eine Anfrage in HTML (local: true) zum Hinzufügen / Löschen von Tags eingeht, daher wird nur format.js {Processing} beschrieben. Wenn Sie die Verarbeitung trennen möchten, wenn eine Anforderung in HTML eingeht, können Sie format.html {Verarbeitung} schreiben und die Verarbeitung gemäß der Anforderungsmethode aufteilen. Wenn if @ tag.save erfolgreich ist, geben Sie die Nachricht" Gespeichert "ein. Geben Sie in die Taste flash [: success] ein und übergeben Sie sie an create.js.erb. Wenn dies fehlschlägt, wird nur die Validierungsfehlermeldung angezeigt, sodass keine Flash-Nachricht verwendet wird. Daher wird nach format.js` keine Verarbeitung geschrieben, sondern nur die Anzeige. Wie oben erwähnt, wird das "@ -Tag", an dem der Validierungsfehler zu diesem Zeitpunkt aufgetreten ist, an create.js.erb übergeben, und die Fehlerverarbeitung (Anzeige der Validierungsfehlermeldung) wird dort durchgeführt.

Die Zerstörungsaktion setzt die Nachricht "gelöscht". "Auf die Taste" flash [: warning] "und übergibt sie an destroy.js.erb.

Beim Schreiben von "format.js" und beim Nichtschreiben von Normalerweise hat der Controller einen Aktionsnamen mit demselben Namen, der der Ansichtsdatei entspricht. (index.html.erb für `def index end`)
Sofern im Inhalt des Aktionsnamens nichts anderes angegeben ist, z. B.` render` oder` redirect_to`, wird `render: action name` am Ende der Aktion weggelassen. Es läuft (implizit). (Aus diesem Grund wird die Ansicht gerendert, ohne den Inhalt zu schreiben, z. B. "def index end".) Dieses Mal möchte ich in der Aktion "Erstellen" abhängig von der Bedingung eine Flash-Nachricht übergeben. Daher habe ich "format.js" explizit beschrieben und die Verarbeitung darin aufgeteilt. In der Aktion "Zerstören" ist es jedoch nicht erforderlich, die Verarbeitung bisher zu trennen. , `Respond_to`,` format.js`, `render: destroy` werden nicht beschrieben. Das `render: destroy` wird bereits implizit erwähnt, sodass Sie es nicht schreiben müssen. Wie ich zu Beginn geschrieben habe, wird der `render: action name` implizit nur ausgelöst, wenn es keinen anderen` render: einen anderen Aktionsnamen` oder` redirect_to` in der Aktion gibt, also andererseits die create-Aktion Wenn Sie format.js explizit schreiben und ausführen, wird das implizite "render: create" am Ende der Aktion nicht ausgeführt. (Dies ist der Grund, warum kein Double-Rendering-Fehler auftritt.)

[Rails Guide-Übersicht über Action Controller](https://railsguides.jp/action_controller_overview.html#%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%81 % A8% E3% 82% A2% E3% 82% AF% E3% 82% B7% E3% 83% A7% E3% 83% B3) Pikawaka - resoond_to [Qiita- [Rails] Detaillierte Methode und Erklärung zum Anzeigen einfacher Nachrichten mithilfe von Flash-Nachrichten](https://qiita.com/dice9494/items/2a0e92aba58a516e42e9#flash%E3%81%A8flashnow%E3%81%AE] % E4% BD% BF% E3% 81% 84% E5% 88% 86% E3% 81% 91% E6% 96% B9% E3% 81% AF)

Zusammenfassung

Wenn Sie Fragen haben, unterschiedliche Interpretationen haben oder wenn Sie der Meinung sind, dass etwas mit der Beschreibungsmethode nicht stimmt, würden wir uns freuen, wenn Sie in den Kommentaren darauf hinweisen könnten.

Vielen Dank für das Lesen bis zum Ende.

Referenzseite

[Rails Guide-Layout und Rendering](https://railsguides.jp/layouts_and_rendering.html#%E3%83%91%E3%83%BC%E3%82%B7%E3%83%A3%E3%83% AB% E3% 82% 92% E4% BD% BF% E7% 94% A8% E3% 81% 99% E3% 82% 8B) [Rails Guide-Übersicht über Action Controller](https://railsguides.jp/action_controller_overview.html#%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%81 % A8% E3% 82% A2% E3% 82% AF% E3% 82% B7% E3% 83% A7% E3% 83% B3) Pikawaka - resoond_to [Qiita- [Rails] Detaillierte Methode und Erklärung zum Anzeigen einfacher Nachrichten mithilfe von Flash-Nachrichten](https://qiita.com/dice9494/items/2a0e92aba58a516e42e9#flash%E3%81%A8flashnow%E3%81%AE] % E4% BD% BF% E3% 81% 84% E5% 88% 86% E3% 81% 91% E6% 96% B9% E3% 81% AF)

Recommended Posts