[RUBY] Erstellen Sie ein Eltern-Kind-Beziehungsformular mit form_object (ich habe auch einen Test geschrieben)

Hintergrund

Es gibt Tabellen mit verschiedenen untergeordneten Elementen wie "@ comment" und "@ employee", die mit "@ shop" verknüpft sind. Zum Zeitpunkt der erstmaligen Registrierung der Informationen konnte ich alle untergeordneten Elemente zusammen mit dem übergeordneten Element wie "@ shop", "@ comment", "@ employee" speichern.

Obwohl ich diese mit accept_nested_attributes_for in Form des folgenden Artikels realisiert habe,

▼ Es wurde so realisiert Erstellen Sie untergeordnete Tabellendaten sofort mit fields_for (ich schreibe auch einen Test) [Rails] [Rspec]

Von diesen wurden Bearbeitungsformulare nur für "@ shop" und Veröffentlichungs- / Bearbeitungsformulare wie "@ comment" und "@ employee" erforderlich, sodass das "Modell" allmählich mit verschiedenen Beschreibungen aufgebläht wurde.

Was ist form_object?

↑ In der obigen Situation kann form_object die Beschreibung des Modells vereinfachen, indem Validierungen und Standardwerteinstellungen für ein bestimmtes Formular an einer Stelle gesammelt werden. Persönlich bin ich auf die Einführung gestoßen, also werde ich einen Artikel schreiben und ein Protokoll führen.

Die Ausführungsumgebung ist wie folgt.

Einführungsmethode

Die grundlegende Methode zum Schreiben von "form_object", "controller" und "view" ist wie folgt. Dieses Mal möchte ich ein Beispiel für ein Formular nehmen, mit dem Sie einen "@ Kommentar" registrieren können, wenn Sie "@ shop" zum ersten Mal registrieren.

Dieser Artikel war für die Implementierung am hilfreichsten.

Speichern Sie mehrere untergeordnete Datensätze ohne accept_nested_attributes_for

DB-Struktur

shops
name string
category integer

↑ Kategorie ist der Shop-Typ. Die Spalte "Aufzählung".

comments
content text
shop_id integer

Erstellte Datei

form_object

/forms/shop_entry_form.rb


class ShopEntryForm
  include ActiveModel::Model

  # @Beschreibung über Shop-----------------------------
  concerning :ShopBuilder do
    def initialize(params = {})
      super(params)
      @category = params[:category]
    end

    def facility
      @shop ||= Shop.new
    end
  end

  attr_accessor :name, :category
  validates :name, presence: true
  validates :category, presence: true

  # @Beschreibung zum Kommentar-----------------------------
  concerning :CommentBuilder do
    attr_reader :comments_attributes

    def comments
      @comments_attributes ||= Comment.new
    end

    def comments_attributes=(attributes)
      @comments_attributes = Comment.new(attributes)
    end
  end

  attr_accessor :content
 
  #Implementierungslogik------------------------------------
  def save
    #Wenn ein Validierungsfehler vorliegt, wird false zurückgegeben und die folgende Verarbeitung wird nicht ausgeführt.
    return false if invalid?

    shop.assign_attributes(shop_params)
    build_asscociation

    shop.save ? true : false
  end
  
  private

  def shop_params
    {
      name: name,
      category: @category,
    }
  end

  def build_asscociations
    #Fügen Sie dem untergeordneten Element des Shops einen Kommentar hinzu. Wenn der Inhalt jedoch leer ist, wird er nicht hinzugefügt.
    shop.comments << comments if comments[:content].present?
  end

  
end

Allein damit gab es viele Stolpersteine. .. .. .. Erstens hat der Teil "Betrifft: ShopBuilder do ... end" die folgende Bedeutung.

#Diese Beschreibung ist...
concern :ShopBuilder do
  ...
end

#Gleich wie unten
module ShopBuilder
  extend ActiveSupport::Concern
  ...
end

Weitere Informationen finden Sie unter Dieser Artikel, auf den ich bei der Implementierung verwiesen habe.

Als nächstes hat der Teil von "initialize (params = {}) ... end" die folgende Bedeutung.

def initialize(params = {})
  # @Shop-Parameter zugänglich machen
  super(params)
  
  #Beschreibung für Spalten, für die Standardwerte in DB festgelegt sind
  @category = params[:category]
end

Zuallererst in Bezug auf "super (params)" gemäß dem folgenden Artikel, der auch ein sehr hilfreicher Artikel für die Implementierung war.

Formularklasse verwenden

Eine Beschreibung, die Parameter mit "super (params)" speichert und dieselbe Bedeutung wie die folgende Beschreibung hat.

@attributes = self.class._default_attributes.deep_dup
assign_attributes(params)

Darüber hinaus können Spalten, für die auf der Datenbankseite Standardwerte festgelegt sind, nur dann auf Parameter zugreifen, wenn Sie wie unten gezeigt explizit auf Zugriffsparameter schreiben. Selbst wenn Sie einen ** -Wert eingeben, ist dies der Standardwert von DB. Es ist geworden ... ** **.

@category = params[:category]

Dieses Rätsel kann nicht gelöst werden. Ich möchte es zu einer zukünftigen Ausgabe machen. .. .. Der Grund, warum der Standardwert auf der Datenbankseite für Spalten mit enum erforderlich ist, ist [dieser Artikel](https://framgia.com/journal/rails%E3%81%AEenum-%E8%AB%B8%E5% Siehe 88% 83% E3% 81% AE% E5% 89% A3% EF% BC% 88% EF% BC% 91% EF% BC% 89-% E3% 80% 80from-viblo /).

Und der Teil von def comment_attributes = (Attribute) ... end,

def comments_attributes=(attributes)
  @comments_attributes = Comment.new(attributes)
end

Dies ist eine Methode zum Schreiben der Setter-Methode, die Sie selten sehen, wenn Sie nur Rails ausführen, und Sie können das Element mit dem Argument @ by ** in Form einer Methode (Argument) ändern, die mit `= endet Ich werde. Persönlich denke ich, dass es dem Bild nahe kommt, so etwas zu tun.

def comments_attributes=(attributes) # ...Folgendes wird weggelassen

#Ein solches Bild
comments_attributes = attributes

#Sie können es also so nennen
self.comments_attributes
# =>Inhalt von Attributen

Das liegt daran, dass ich Ruby Getter und Setter nicht richtig verstanden habe. .. .. .. Tohoho. .. .. Ich werde mein Bestes geben. .. .. Die Methode, die mit `= endet, finden Sie unter " Einführung in Ruby für Profis, von Sprachspezifikationen bis zu testgetriebenen Entwicklungs- / Debugging-Techniken " Ich habe "p215" von /) ungefähr 15 Mal gelesen.

controller

Das Folgende ist eine Beschreibung der Steuerung. Der Controller sieht so aus.

app/controllers/shops_controller.rb


class ShopsController < ApplicationController
  
  def new
    @shop = ShopEntryForm.new
  end

  def create
    @shop = ShopEntryForm.new(shop_entry_params)
    if @shop.save
      #Was tun, wenn es gelingt?
    else
      #Was tun, wenn es fehlschlägt?
    end
  end

  private

  def shop_entry_params
    params.require(:shop_entry_form).permit(:caregory,
                                            :name,
                                            comments_attributes: [:content])
  end
end

Ich habe den Eindruck, dass die Beschreibung nicht unerwartet abgenommen hat. Zuerst hatte ich erwartet, dass "shop_entry_params" vom Controller reduziert wird, aber ich konnte es doch nicht vom Controller löschen. Nur die Methode, die die Zuordnung erstellt, konnte vom Controller entfernt werden.

Was das Modell betrifft, wurden ** Validierungs- und Standardwerteinstellungsmethoden, Zuordnungen usw. gelöscht! ** Keine zusätzliche Beschreibung! !! Immerhin ist form_object eine bequeme Möglichkeit, ein schlankes Modell zu schreiben! !!

View Schließlich sieht die Ansicht so aus.

haml:app/views/shops/new.html.haml


= form_with model: @shop, url: shops_path, local: true do |f|
    = f.text_field :name

    = f.fields_for :shop_comments, local: true do |comment_form|
      = comment_form.text_field

    = f.submit "Senden"

Die Verwendung von fields_for entspricht der Implementierung von accept_nested_attributes_for ^^

Prüfung

Der Test war auch sehr einfach!

spec/forms/shop_entry_form_spec.rb


require 'rails_helper'

RSpec.describe ShopEntryForm, type: :model do
  before do
    @shop_form = ShopEntryForm.new(category: "category1", name: "Testgeschäft")
  end

  describe "Validierungstest" do
    it "Bestehen Sie die Validierung, wenn Sie einen Namen und eine Kategorie haben" do
      @shop_form.valid?
      expect(@shop_form).to be_valid
    end
    
    #Folgendes wird weggelassen
  end
end

Ich musste nur auf den Speicherort der Datei, den Teil "RSpec.describe ShopEntryForm ..." und die Beschreibung beim Erstellen der Testinstanz achten ^^

Dies ist ein wenig alt, aber ich habe es mit Bezug auf diesen Artikel erstellt.

Schreiben Sie einen Test eines Formularobjekts mit RSpec

Impressionen, Referenzmaterialien usw.

Die Implementierung hat sehr lange gedauert. Die eigentliche Form hatte drei Arten von verschachtelten untergeordneten Elementen, und die Form war ziemlich kompliziert, aber vor allem glaube ich, dass ich es nicht gewohnt war, einfaches Ruby zu schreiben. .. .. Wenn ich mich beruhige, möchte ich Ruby noch einmal überprüfen.

Dies ist eine Zusammenfassung der Artikel und Materialien, auf die ich mich dieses Mal bezog.

▼ Gesamtschreiben Speichern Sie mehrere untergeordnete Datensätze ohne accept_nested_attributes_for

▼ So greifen Sie auf Parameter zu Formularklasse verwenden "Einführung in Ruby für Profis, von Sprachspezifikationen bis hin zu testgetriebenen Entwicklungs- und Debugging-Techniken" (S.215)

▼ Über Bedenken Bite-sized separation of concerns

▼ Wie schreibe ich einen Test? Schreiben Sie einen Test eines Formularobjekts mit RSpec

Danach bleiben auch die Bearbeitungs- und Aktualisierungsformulare erhalten, daher möchte ich als nächstes daran arbeiten ^^

Recommended Posts

Erstellen Sie ein Eltern-Kind-Beziehungsformular mit form_object (ich habe auch einen Test geschrieben)
Ich habe jetzt einen Test mit Spring Boot + JUnit 5 geschrieben
Ich habe einen CRUD-Test mit SpringBoot + MyBatis + DBUnit geschrieben (Teil 1)
Ich habe ein Programm zur Beurteilung von Primzahlen in Java geschrieben
[RSpec] Ich habe einen Test zum Hochladen eines Profilbilds geschrieben.
Ich habe versucht, mit Chocolatey eine Java8-Entwicklungsumgebung zu erstellen
[Rails] Ich habe versucht, eine Mini-App mit FullCalendar zu erstellen
Ich möchte ein Formular erstellen, um die Kategorie [Schienen] auszuwählen
Ich habe versucht, mit Docker eine Padrino-Entwicklungsumgebung zu erstellen
Erstellen Sie einen Spielplatz mit Xcode 12
Ich habe versucht, ein Formular mit Spring MVC und Jasper Reports 1/3 (Jasper Reports-Einstellungen) zu drucken.
Benötige ich einen Test, wenn ich DDD in einer Sprache mit einem Typ mache?
Ich habe versucht, ein Formular mit Spring MVC und Jasper Reports 3/3 (Spring MVC-Steuerung) zu drucken.
Ich kann in IntelliJ keine Java-Klasse mit einem bestimmten Namen erstellen
Ich habe ein einfaches Suchformular mit Spring Boot + GitHub Search API erstellt.
Erstellen Sie mit Docker eine Vue3-Umgebung!
Ich habe mit Swing eine GUI erstellt
Erstellen Sie Ausnahmen mit einer Fluid-Schnittstelle
Erstellen Sie ein Maven-Projekt mit Befehlen
Ich habe versucht, ein Formular mit Spring MVC und Jasper Reports 2/3 (Formularvorlagenerstellung) zu drucken.
Ich möchte mit Jakarta EE 8 mit Java 11 ein dunkles Web-SNS erstellen
Ich habe eine Lambda-Funktion in Java geschrieben und mit SAM bereitgestellt