[Ruby on Rails] 1 Modell CRUD (Routing Main)

Die Gelegenheit, diesen Artikel zu schreiben

Vor kurzem habe ich bei tetatail angefangen, Fragen zu beantworten, um mein Verständnis von Schienen zu vertiefen. Wenn ich mir die dortigen Fragen ansehe, habe ich manchmal das Gefühl, dass einigen Leuten Grundkenntnisse bei der Implementierung von CRUD fehlen, und es scheint, als hätte ich mich vor etwa einem Jahr selbst angeschaut, also hoffe ich, dass es hilft. Ich habe diesen Artikel geschrieben. Was ist CRUD Wenn man diese eine CRUD versteht, fühlt es sich an, als würde man sich auf der Grundlage dieses Grundwissens bewerben, selbst wenn die Anzahl der Modelle auf zwei oder drei steigt. Ich denke, es ist gut, zuerst die CRUD eines Modells genau kennenzulernen. ..

Zielgruppe

Überblick

Es beschreibt die CRUD-Funktion eines Modells (Modellname: Beitrag, Spalte: Titel, Inhalt) so detailliert wie möglich. Die Beschreibung des Modells wird in diesem Artikel selten erwähnt. Das Routing und der Controller werden die Hauptrolle spielen. Das Routing erscheint übrigens dauerhaft. Bitte verzeihen Sie diesen Punkt auch, da der Code auch so beschrieben wird, wie er ist, wo er normalerweise zusammengefasst wird.

Ablauf dieses Artikels

  1. Erstellen Sie ein neues Projekt
  2. Erstellen eines Post-Modells
  3. Routing-Einstellungen
  4. Erstellen Sie den Posts Controller
  5. Definition der Indexaktion (keine Beschreibung des Inhalts)
  6. Neue Aktionsdefinition, Erstellung eines neuen Registrierungsformulars
  7. Aktionsdefinition erstellen
  8. Beschreibung des Inhalts der Indexaktion
  9. Aktionsdefinition anzeigen, Detailseitenerstellung
  10. Aktionsdefinition bearbeiten, Formularerstellung bearbeiten
  11. Aktualisieren Sie die Aktionsdefinition
  12. Aktionsdefinition zerstören Ich werde in der Reihenfolge von erklären.

Umgebung

% ruby -v
ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-darwin19]

% rails -v
Rails 6.0.3.2

% postgres --version
postgres (PostgreSQL) 9.6.18

1. Erstellen Sie ein neues Projekt

Erstellen Sie eine App mit dem Befehl Rails New. Diesmal lautet der App-Name "one_model_crud".

rails new [App Name](one_model_crud) -d postgresql

Bearbeiten Sie database.yml

database.yml


default: &default
  adapter: postgresql
  encoding: unicode
  username: <%= ENV['PG_USERNAME'] %> #Benutzername in postgresql gesetzt
  password: <%= ENV['PG_PASSWORD'] %> #Passwort in postgresql gesetzt
  # For details on connection pooling, see Rails configuration guide
  # https://guides.rubyonrails.org/configuring.html#database-pooling
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
% rails db:create
Created database 'one_model_crud_development'
Created database 'one_model_crud_test'

% rails s

Gehen Sie zu http: // localhost: 3000 /. スクリーンショット 2020-08-15 9.46.35.png

Obwohl es vom Hauptthema abweicht, verwendet diese Zeitansicht Slim, Bootstrap für das Styling und Pry-Rails als Debugging-Tool.

schlanke Konvertierung

Einführung von Bootstrap

Jetzt bist du bereit.

2. Erstellen eines Post-Modells

Schienen g Modell Erstellen Sie ein Modell mit dem Modellnamen (Einzelformular).

% rails g model post

Fügen Sie einen Titel und Inhaltsspalten hinzu.

XXXX_create_posts.rb


class CreatePosts < ActiveRecord::Migration[6.0]
  def change
    create_table :posts do |t|
      t.string :title
      t.text   :content

      t.timestamps
    end
  end
end

Reflektieren Sie die erstellten Datenbankinformationen.

% rails db:migrate
== 20200815005104 CreatePosts: migrating ======================================
-- create_table(:posts)
   -> 0.0271s
== 20200815005104 CreatePosts: migrated (0.0272s) =============================

Lassen Sie es uns auf der Konsole überprüfen.

% rails c
irb(main):001:0> Post.new
=> #<Post id: nil, title: nil, content: nil, created_at: nil, updated_at: nil>
irb(main):002:0> Post.new(title: 'Titel 1', content: 'Inhalt 1').save
   (0.3ms)  BEGIN
  Post Create (7.9ms)  INSERT INTO "posts" ("title", "content", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id"  [["title", "Titel 1"], ["content", "Inhalt 1"], ["created_at", "2020-08-15 01:03:24.246072"], ["updated_at", "2020-08-15 01:03:24.246072"]]
   (6.8ms)  COMMIT
=> true

Sie haben ein Post-Modell erstellt. Lassen Sie uns dies jetzt im Browser tun.

3. Routing-Einstellungen

Stellen Sie das Routing so ein, dass beim Zugriff auf http: // localhost: 3000 / auf "posts # index" zugegriffen wird.

routes.rb


Rails.application.routes.draw do
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
  root to: "posts#index"
  resources :posts
end

resources: model (plural) generiert das Routing für die sieben grundlegenden Aktionen für dieses Modell: index, new, create, show, edit, update, destroy.

Sie können Aktionen auch einschränken, indem Sie "Ressourcen: Modell (Plural), nur :: Index" oder "Ressourcen: Modell (Plural), nur:% i [Index]" schreiben.

Werfen wir einen Blick auf das generierte Routing auf der Konsole.

% rails routes
     Prefix Verb       URI Pattern               Controller#Action
       root  GET      /                           posts#index
       posts GET      /posts(.:format)            posts#index
             POST     /posts(.:format)            posts#create
    new_post GET      /posts/new(.:format)        posts#new
   edit_post GET      /posts/:id/edit(.:format)   posts#edit
        post GET      /posts/:id(.:format)        posts#show
             PATCH    /posts/:id(.:format)        posts#update
             PUT      /posts/:id(.:format)        posts#update
             DELETE   /posts/:id(.:format)        posts#destroy

Ein Routing wie oben wurde erstellt.

--Prefix wird später erklärt. --Verb ist eine HTTP-Methode. --URI Pattern zeigt auf eine URL nach http: // localhost: 3000.

Schauen wir uns vor diesem Hintergrund http: // localhost: 3000 / an.

Dies bedeutet, dass Sie beim Besuch von http: // localhost: 3000 / die Indexaktion auf dem Posts-Controller ausführen.

4. Erstellen Sie den Posts Controller

Erstellen Sie eine Steuerung mit dem Reglermodell "Schienen g (Plural)".

% rails g controller posts
Running via Spring preloader in process 31151
      create  app/controllers/posts_controller.rb
      invoke  erb
      create    app/views/posts
      invoke  test_unit
      create    test/controllers/posts_controller_test.rb
      invoke  helper
      create    app/helpers/posts_helper.rb
      invoke    test_unit
      invoke  assets
      invoke    scss
      create      app/assets/stylesheets/posts.scss

Es werden nur "app / controller / posts_controller.rb" und "app / views / posts" verwendet, sodass Sie sie löschen können.

5. Definition der Indexaktion (keine Beschreibung des Inhalts)

PostsController.rb


class PostsController < ApplicationController
  def index
  end
end

Der Inhalt wird festgelegt, nachdem der Beitrag erstellt werden kann.

Erstellen Sie index.slim in app / views / posts / und schreiben Sie Folgendes

index.slim


h1 Posts#index

Jetzt bist du bereit. Greifen Sie jetzt tatsächlich auf http: // localhost: 3000 / zu

% rails s

Fluss beim Zugriff

  1. Führen Sie die PostsController-Indexaktion aus
  2. Ansichten / posts / index.slim anzeigen Es wird sein.

Wenn Sie tatsächlich darauf zugreifen, wird der folgende Bildschirm angezeigt.

スクリーンショット 2020-08-15 11.12.19.png

6. Neue Aktionsdefinition, Erstellung eines neuen Registrierungsformulars

Als Implementierungsablauf

  1. Installieren Sie die Installation
  2. Neue Aktion von PostsController
  3. Übergang zu new.slim
  4. PostsController Aktion erstellen Es sieht aus wie.

1. Installieren Sie die Installation

Erstellen Sie zunächst einen Link, um auf den neuen Registrierungsbildschirm zuzugreifen. Was Sie hier brauchen, ist ** Präfix **. Der Link kann durch Schreiben des folgenden Formulars erstellt werden. = link_to'character to display ', Prefix_path Wenn Sie so schreiben, können Sie einen Link generieren, um auf das URI-Muster von Prefix_path zuzugreifen. Ich werde es tatsächlich beschreiben.

index.slim


h1 Posts#index
= link_to 'Anmelden', new_post_path

Dieser Link ist ein Link, bei dem Prefix zu URI Pattertn von ** new_post ** übergeht. Werfen wir einen Blick auf das Routing der neuen Aktion.

Prefix Verb       URI Pattern               Controller#Action
new_post GET      /posts/new(.:format)        posts#new

Sie haben jetzt einen Link erstellt, um auf den neuen Registrierungsbildschirm zuzugreifen. スクリーンショット 2020-08-15 11.42.12.png

Durch Klicken auf den neuen Registrierungslink wird die URL in / posts / new geändert. (* Ich erhalte eine Fehlermeldung, weil ich noch keine neue Aktion definiert habe.)

スクリーンショット 2020-08-15 11.43.12.png

2. Neue Aktion von PostsController

PostsController.rb


def new
  @post = Post.new
end

Post.new erstellt eine Instanz des Post-Modells und weist diese Instanz @post zu.

3. Übergang zu new.slim

new.slim


.container
  h1.mt-4 Neue Registrierung
  = form_with url: posts_path, model: @post do |form|
    .form-group
      = form.label :title, 'Titel'
      = form.text_field :title, class: 'form-control'
    .form-group
      = form.label :content, 'Inhalt'
      = form.text_area :content, class: 'form-control'
    = form.submit 'Anmeldung', class: 'btn btn-primary'

Klicken Sie hier für form_with => Verwendung von form_with

Um es kurz zu erklären = Sie können das Übergangsziel festlegen, wenn Sie mit form_with posts_path auf Submit klicken.

Ich würde gerne das Routing der Erstellungsaktion hier sehen.

Prefix Verb       URI Pattern               Controller#Action
posts GET      /posts(.:format)            posts#index
      POST     /posts(.:format)            posts#create

Wenn im Präfix nichts beschrieben ist, ist es das Präfix, das am Anfang vorhanden ist, indem Sie den obigen Anweisungen folgen. In diesem Fall ist Präfix Beiträge. Daher gibt es zwei Arten von posts_path: posts # index und posts # create. Verb (** HTTP-Methode **) ist, wie diese beiden beurteilt werden. Für form_with ist die Standard-HTTP-Methode auf POST festgelegt. Dies bedeutet, dass ** posts_path **, geschrieben in new.slim, "die Erstellungsaktion von PostsController ausführen" bedeutet.

4. PostsController Aktion erstellen

Überprüfen Sie zunächst, welche Art von Parametern gesendet werden.

PostsController.rb


def create
  binding.pry
end

Lassen Sie uns in der Konsole sehen, wie die Daten durch Schreiben gesendet werden.

 9: def create
 => 10:   binding.pry
    11: end

[1] pry(#<PostsController>)> params
=> <ActionController::Parameters {"authenticity_token"=>"d9j/87bg84JqMg5cPr7HwMKi8PIbw8gmEhMj4EvgIblmRKqdmGAdmk1THcW9095M2cBdQxGigM/PZ+VYl9ZGYA==", "post"=>{"title"=>"Titel 2", "content"=>"Inhalt 2"}, "commit"=>"Anmeldung", "controller"=>"posts", "action"=>"create"} permitted: false>
[2] pry(#<PostsController>)> params[:post][:title]
=> "Titel 1"
[3] pry(#<PostsController>)> params[:post][:content]
=> "Inhalt 2"

Durch dieses Schreiben konnte ich den Inhalt bestätigen. Dann speichern Sie diese.

PostsController.rb


def create
  @post = Post.new(title: params[:post][:title], content: params[:post][:content])
  @post.save
end

Dann können Sie es speichern. Dieses Mal werden wir es jedoch mithilfe eines Mechanismus speichern, der als starke Parameter bezeichnet wird und ungültige Parameter verhindert.

PostsController.rb


def create
  @post = Post.new
  @post.save(post_params)
  redirect_to posts_path
end

private

def post_params
  params.require(:post).permit(:title, :content)
end

Der geänderte Code sieht folgendermaßen aus. Diesmal können Titel und Inhalt gespeichert werden, auch wenn sie leer sind, sodass der bedingte Verzweigungscode nicht in die if-Anweisung geschrieben wird. Die endgültige Beschreibung der Erstellungsaktion "redirect_to posts_path" bewirkt, dass die URL zu "/" übergeht, dh die Indexaktion von PostsController ausführt.

6. Beschreibung des Inhalts der Indexaktion

Nachdem die Daten durch die Aktion "Erstellen" generiert wurden, besteht der nächste Schritt darin, die Daten zu erfassen und anzuzeigen.

PostsController.rb


def index
 @posts = Post.all
end

Sie können alle Daten des Modells mit model .all abrufen und die erhaltenen Daten @posts zuweisen. @posts ist Plural, da erwartet wird, dass mehrere Daten eingegeben werden. Die Daten sind übrigens im folgenden Formular enthalten.

[#<Post:0x00007f94bc4d83b8 id: 1, title: "Titel 1", content: "Inhalt 1", created_at: Sat, 15 Aug 2020 05:19:09 UTC +00:00, updated_at: Sat, 15 Aug 2020 05:19:09 UTC +00:00>,
 #<Post:0x00007f94bc4ae838 id: 2, title: "Titel 2", content: "Inhalt 2", created_at: Sat, 15 Aug 2020 05:19:22 UTC +00:00, updated_at: Sat, 15 Aug 2020 05:19:22 UTC +00:00>]

Lassen Sie uns diese anzeigen.

index.slim


.container
  h1.mt-4 Posts#index
  = link_to 'Anmelden', new_post_path

  //Nachtrag
  - @posts.each do |post|
    .card.my-4
      .card-header
        = post.title
      .card-body
        p.card-text
          = post.content

@posts wird in der Indexaktion definiert. Es wird mit jeder Methode einzeln abgerufen, und die abgerufenen Daten werden in den Beitrag gestellt. = post.title, = post.content bezieht sich auf die Titelspalte und die Inhaltsspalte der Postdaten. Der Bildschirm sieht wie folgt aus. スクリーンショット 2020-08-15 14.28.14.png

7. Aktionsdefinition anzeigen, Detailseitenerstellung

Richten Sie zunächst eine Schaltfläche ein, um zum Detailbildschirm unter den einzelnen Daten zu gelangen.

index.slim


.container
  h1.mt-4 Posts#index
  = link_to 'Anmelden', new_post_path

  - @posts.each do |post|
    .card.my-4
      .card-header
        = post.title
      .card-body
        p.card-text
          = post.content
        //Nachtrag
        = link_to 'Einzelheiten', post_path(post), class: 'btn btn-success mr-2'

Beachten Sie, dass post als ** Argument von post_path ** verwendet wird. Werfen wir einen Blick auf das Routing der Show-Aktion.

Prefix Verb       URI Pattern               Controller#Action
    post GET      /posts/:id(.:format)        posts#show

Das URI-Muster hat eine: id und dieser Wert ändert sich dynamisch. (Beispiel: / posts / 1, / posts / 7) Wenn nur post_path verwendet wird, ist die ID unbekannt. Nehmen Sie also ein Argument. (Diesmal nach) Auf diese Weise können Sie die ID des Beitrags abrufen und zu / posts /: id übergehen. Nun wollen wir sehen, welche Parameter an die Show-Aktion gesendet werden.

PostsController.rb


def show
  binding.pry
end

Stoppen Sie bei binding.pry und überprüfen Sie die Konsole

pry(#<PostsController>)> params
=> <ActionController::Parameters {"controller"=>"posts", "action"=>"show", "id"=>"1"} permitted: false>
[2] pry(#<PostsController>)> params[:id]
=> "1"

Sie können die ID erhalten, indem Sie params [: id] wie folgt schreiben. Verwenden Sie diese ID, um Daten aus den Post-Modelldaten abzurufen.

PostsController.rb


def show
  @post = Post.find(params[:id])
end

Durch Festlegen als Modell .find (ID-Nummer) werden Daten erfasst, die mit der ID und der ID-Nummer des Modells übereinstimmen. Als nächstes kommt show.slim.

show.slim


.container
  .card.my-4
    .card-header
      = @post.title
    .card-body
      p.card-text
        = @post.content

Ein solcher Bildschirm wird angezeigt, wenn der Übergang erfolgt. スクリーンショット 2020-08-15 16.39.02.png

8. Aktionsdefinition bearbeiten, Formularerstellung bearbeiten

Richten Sie zunächst die Schaltfläche Bearbeiten auf die gleiche Weise wie die Schaltfläche Detail ein.

index.slim


.container
  h1.mt-4 Posts#index
  = link_to 'Anmelden', new_post_path

  - @posts.each do |post|
    .card.my-4
      .card-header
        = post.title
      .card-body
        p.card-text
          = post.content
        = link_to 'Einzelheiten', post_path(post), class: 'btn btn-success mr-2'
        //Nachtrag
        = link_to 'Bearbeiten', edit_post_path(post), class: 'btn btn-primary mr-2'

Werfen wir einen Blick auf das Routing der Bearbeitungsaktion.

Prefix Verb       URI Pattern               Controller#Action
edit_post GET      /posts/:id/edit(.:format)   posts#edit

Definieren Sie dann die Bearbeitungsaktion.

PostsController.rb


def edit
  @post = Post.find(params[:id])
end

Die Beschreibung entspricht der Show-Aktion. Dann schreibe edit.slim.

edit.slim


.container
  h1.mt-4 Bearbeiten
  = form_with url: post_path(@post), model: @post do |form|
    .form-group
      = form.label :title, 'Titel'
      = form.text_field :title, class: 'form-control'
    .form-group
      = form.label :content, 'Inhalt'
      = form.text_area :content, class: 'form-control'
    = form.submit 'aktualisieren', class: 'btn btn-primary'

Der Inhalt ist fast der gleiche wie bei new.slim, daher wird die Erklärung weggelassen. post_path (@post) ist dasselbe wie in new.slim definiert, und diese HTTP-Methode ist PATCH. Ich werde mir vorerst auch das Routing ansehen.

Prefix Verb       URI Pattern               Controller#Action
   post GET      /posts/:id(.:format)        posts#show
        PATCH    /posts/:id(.:format)        posts#update
        PUT      /posts/:id(.:format)        posts#update

Da die HTTP-Methode PATCH ist, ist die Aktion, die ausgeführt werden soll, wenn die Aktualisierungsschaltfläche dieses Mal gedrückt wird, die "PostsController-Aktualisierungsaktion".

9. Aktualisieren Sie die Aktionsdefinition

Definieren Sie die Aktualisierungsaktion.

PostsController.rb


def update
  @post = Post.find(params[:id])
  @post.update(post_params)
  redirect_to posts_path
end

Dies entspricht fast der Erstellungsaktion. Der Unterschied zur Erstellungsaktion besteht darin, ob das Modell neu ist oder gefunden wird.

10. Aktionsdefinition zerstören

Löschen Sie abschließend die Daten. Richten Sie eine Löschschaltfläche sowie eine Bearbeitungsschaltfläche ein. Werfen wir einen Blick auf das Routing der Zerstörungsaktion.

Prefix Verb       URI Pattern               Controller#Action
 post GET      /posts/:id(.:format)        posts#show
       DELETE   /posts/:id(.:format)        posts#destroy

Da es sich um denselben post_path handelt, werden sie durch die HTTP-Methode unterschieden. Durch Setzen von method :: HTTP method wird die Aktion der angegebenen HTTP-Methode im angegebenen Pfad ausgeführt. Ich werde es tatsächlich beschreiben.

index.slim


.container
  h1.mt-4 Posts#index
  = link_to 'Anmelden', new_post_path

  - @posts.each do |post|
    .card.my-4
      .card-header
        = post.title
      .card-body
        p.card-text
          = post.content
        = link_to 'Einzelheiten', post_path(post), class: 'btn btn-success mr-2'
        = link_to 'Bearbeiten', edit_post_path(post), class: 'btn btn-primary mr-2'
        //Nachtrag
        = link_to 'Löschen', post_path(post), method: :delete, class: 'btn btn-danger'

Definieren Sie dann die Zerstörungsaktion.

PostsController.rb


def destroy
  @post = Post.find(params[:id])
  @post.destroy
  redirect_to posts_path
end

Sie haben jetzt ein CRUD-Modell implementiert.

Code abgeschlossen

Der fertige Code ist vorerst unten aufgeführt.

Postscontroller.rb


class PostsController < ApplicationController
  def index
    @posts = Post.all
  end

  def new
    @post = Post.new
  end

  def create
    @post = Post.new(post_params)
    @post.save
    redirect_to posts_path
  end

  def show
    @post = Post.find(params[:id])
  end

  def edit
    @post = Post.find(params[:id])
  end

  def update
    @post = Post.find(params[:id])
    @post.update(post_params)
    redirect_to posts_path
  end

  def destroy
    @post = Post.find(params[:id])
    @post.destroy
    redirect_to posts_path
  end

  private

  def post_params
    params.require(:post).permit(:title, :content)
  end
end

abschließend

Vorerst konnte ich alle Inhalte schreiben, die ich mir vor einem Jahr zeigen wollte.

Recommended Posts

[Ruby on Rails] 1 Modell CRUD (Routing Main)
Ruby On Rails entwickelt Routing-Konflikte
Modell [Ruby on Rails], Befehl für Controller-Terminal
Befehl zum Erstellen / Löschen von Ruby on Rails-Modellen
[Ruby on Rails] Modelltest mit RSpec
Ruby on Rails Elementary
Ruby on Rails Grundlagen
Ruby On Rails Association
Ruby on Rails Lernrekord -2020.10.03
Portfolioerstellung Ruby on Rails
Ruby on Rails Lernrekord -2020.10.04
[Ruby on Rails] Debuck (bindend.pry)
Ruby on Rails Lernrekord -2020.10.05
Ruby on Rails Lernrekord -2020.10.09
Ruby on Rails lernen Rekord-2020.10.07 ②
Ruby on Rails lernen Rekord-2020.10.07 ①
Brechen Sie die Ruby on Rails-Migration ab
Ruby on Rails Lernrekord -2020.10.06
Zusammenfassung der Ruby on Rails-Validierung
[Ruby on Rails] Suchfunktion (Modell, Methodenauswahlformel)
Ruby on Rails Grundlegendes Memorandum
[Ruby on Rails] Eliminierung von Fat Controller-First, Logik zum Modell-
[Ruby on Rails] Leseversuch (: [],: Schlüssel)
Ruby on Rails-Variablen, konstante Zusammenfassung
Installation von Ruby + Rails unter Ubuntu 18.04 (rbenv)
Grundkenntnisse in Ruby on Rails
Progate Ruby on Rails5 Rückblick
Verwendung von Ruby on Rails
Ruby on Rails Japanisch-Englisch kompatibler i18n
(Ruby on Rails6) Gepostete Inhalte "löschen"
[Ruby on Rails] CSV-Ausgabefunktion
Ruby on Rails 6.0-Umgebungskonstruktionsnotiz
[Ruby on Rails] Erstellung der Bestätigungsseite
[Ruby on Rails] Implementierung der Kommentarfunktion
[Ruby on Rails] DM, Chat-Funktion
[Ruby on Rails] Praktische Hilfsmethode
[Ruby on Rails] Stoppen Sie "Looping bis ..."
[Ruby on Rails] Einführung der Anfangsdaten
[Ruby on Rails] Suchfunktion (nicht ausgewählt)
[Rails] Hinzufügen der Ruby On Rails-Kommentarfunktion
[Ruby on Rails] Erstellen eines Anfrageformulars
Ruby on Rails6 Praktischer Leitfaden cp13 ~ cp15 [Memo]
[Ruby on Rails] Test mit RSpec anzeigen
[Ruby on Rails] Codeprüfung mit Rubocop-Airbnb
Ruby on Rails-Installationsmethode [Mac Edition]
Ruby on Rails6 Praktischer Leitfaden cp7 ~ cp9 [Memo]
Ruby on Rails in Visual Studio-Codespaces
[Ruby on Rails] Folgen Sie der Funktionsimplementierung: Bidirektional
Hinweise zur Verwendung von FCM mit Ruby on Rails
[Ruby on Rails] Controller-Test mit RSpec