Ruby on Railsアプリケーションに刺激を追加する方法

前書き

Ruby on Railsプロジェクトを使用している場合、要件には、https://guides.rubyonrails.org/v5.2/action_view_overview.htmlによって生成されたHTMLとの対話性が含まれる場合があります。 [テンプレートを表示]。 その場合、この対話機能を実装する方法についていくつかの選択肢があります。

たとえば、https://reactjs.org/ [React]やhttps://emberjs.comのようなhttps://www.digitalocean.com/community/tags/javascript?type=tutorials[JavaScript]フレームワークを実装できます。 / [Ember]。 要件にクライアント側の処理状態が含まれている場合、またはサーバーへの頻繁なクエリに関連するパフォーマンスの問題が懸念される場合は、これらのフレームワークのいずれかを選択するのが理にかなっています。 多くのシングルページアプリケーション(SPA)がこのアプローチを採用しています。

ただし、クライアント側で状態と頻繁な更新を管理するフレームワークを実装する場合、留意すべきいくつかの考慮事項があります。

  1. JavaScriptの解析、JSONの取得とHTMLへの変換など、読み込みと変換の要件がパフォーマンスを制限する可能性があります。

  2. フレームワークへのコミットには、特に小規模なJavaScript拡張機能を探している場合、特定のユースケースが必要とするよりも多くのコードを記述することが含まれます。

  3. クライアント側とサーバー側の両方で管理されている状態は、作業の重複につながる可能性があり、エラーの表面積が増加します。

別の方法として、https://basecamp.com/ [Basecamp](Railsを書いたのと同じチーム)のチームがhttps://stimulusjs.org [Stimulus.js]を作成しました。刺激は、サーバー側で生成されたHTMLを操作することにより、最新のRailsアプリケーションを強化することを目的としています。 状態はhttps://www.digitalocean.com/community/tutorial_series/understanding-the-dom-document-object-model [ドキュメントオブジェクトモデル(DOM)]にあり、フレームワークは要素やイベントとやり取りする標準的な方法を提供しますDOMで。 Turbolinks(デフォルトではRails 5以降に含まれています)と並行して動作し、明確に定義された目的に限定されスコープされたコードでパフォーマンスとロード時間を改善します。

このチュートリアルでは、Stimulusをインストールして使用し、読者にサメに関する情報を提供する既存のRailsアプリケーションを構築します。 アプリケーションには既にサメのデータを処理するモデルがありますが、個々のサメに関する投稿用のネストされたリソースを追加して、ユーザーがサメについての考えや意見を蓄積できるようにします。 この作品は、https://www.digitalocean.com/community/tutorials/how-to-create-nested-resources-for-a-ruby-on-rails-application [Rubyのネストされたリソースを作成する方法]とほぼ並行して実行されます。 on Rails Application]。ただし、JavaScriptを使用してページ上の投稿の位置と外観を操作します。 また、ポストモデル自体を構築するために少し異なるアプローチを取ります。

前提条件

このチュートリアルを実行するには、次のものが必要です。

  • Ubuntu 18.04を実行しているローカルマシンまたは開発サーバー。 開発マシンには、管理権限を持つ非ルートユーザーと、「+ ufw +」で設定されたファイアウォールが必要です。 これを設定する方法については、https://www.digitalocean.com/community/tutorials/initial-server-setup-with-ubuntu-18-04 [Ubuntu 18.04での初期サーバー設定]チュートリアルを参照してください。

  • ローカルマシンまたは開発サーバーにインストールされているhttps://nodejs.org [Node.js]およびhttps://www.npmjs.com/[npm]。 このチュートリアルでは、Node.jsバージョンとnpmバージョンを使用します。 Node.jsおよびnpmをUbuntu 18.04にインストールするためのガイダンスについては、https://www.digitalocean.com/community/tutorials/how-to-install-node-の*「PPAを使用してインストールする」セクションの手順に従ってください。 js-on-ubuntu-18-04#installing-using-a-ppa [Ubuntu 18.04にNode.jsをインストールする方法]。

  • Ruby、https://github.com/rbenv/rbenv [rbenv]、およびローカルマシンまたは開発サーバーにインストールされているRails(https://www.digitalocean.com/community/tutorials/の*ステップ1-4 *に従って) how-to-install-ruby-on-rails-with-rbenv-on-ubuntu-18-04 [Ubuntu 18.04にrbenvでRuby on Railsをインストールする方法]。 このチュートリアルでは、Ruby、rbenv、およびRailsを使用します。

  • Rubyのビルド方法の指示に従って、SQLiteがインストールされ、基本的なサメ情報アプリケーションが作成されました。 on Railsアプリケーション]。

手順1-入れ子モデルの作成

最初のステップは、ネストされた + Post + modelを作成することです。これを既存の `+ Shark +`モデルに関連付けます。 これを行うには、モデル間でActive Record associationsを作成します。投稿は特定のサメに属し、各サメは複数の投稿を持つことができます。

開始するには、前提条件でRailsプロジェクト用に作成した `+ sharkapp +`ディレクトリに移動します。

cd sharkapp

+ Post +`モデルを作成するには、 `+ model +`ジェネレーターでhttps://guides.rubyonrails.org/command_line.html#rails-generate[+rails generate + `]コマンドを使用します。 次のコマンドを入力して、モデルを作成します。

rails generate model Post body:text shark:references

`+ body:text `を使用すると、 ` posts `データベーステーブル( ` Post `モデルにマッピングされるテーブル)に ` body `フィールドを含めるようにRailsに指示します。 また、 `:references `キーワードも含めています。これは、 ` Shark `モデルと ` Post `モデルの間の関連付けを設定します。 具体的には、これにより、 ` sharks `データベースの各サメエントリを表すhttps://en.wikipedia.org/wiki/Foreign_key[foreign key]が ` posts +`データベースに追加されます。

コマンドを実行すると、アプリケーション用にRailsが生成したリソースを確認する出力が表示されます。 先に進む前に、データベース移行ファイルを確認して、モデルとデータベーステーブルの間に存在する関係を確認できます。 次のコマンドを使用してファイルの内容を確認し、ここに表示されている内容を独自の移行ファイルのタイムスタンプに置き換えてください。

cat db/migrate/_create_posts.rb

次の出力が表示されます。

Outputclass CreatePosts < ActiveRecord::Migration[5.2]
 def change
   create_table :posts do |t|
     t.text :body


     t.timestamps
   end
 end
end

ご覧のとおり、表にはサメの外部キーの列が含まれています。 このキーは「+ _id 」の形式をとります-この例では「 _id +」です。

Railsは他の場所でもモデル間の関係を確立しています。 次のコマンドを使用して、新しく生成された `+ Post +`モデルを見てください。

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

`+ belongs_to +`アソシエーションは、宣言モデルの単一インスタンスが名前付きモデルの単一インスタンスに属するモデル間の関係を設定します。 このアプリケーションの場合、これは単一の投稿が単一のサメに属することを意味します。

Railsはすでに「+ Post 」モデルで「 belongs_to 」関連付けを設定していますが、その関係を適切に機能させるには、「 Shark 」モデルでも「 has_many +」関連付けを指定する必要があります。

`+ has_many `アソシエーションを ` Shark `モデルに追加するには、 ` nano `またはお気に入りのエディターを使用して ` app / models / shark.rb +`を開きます。

nano app/models/shark.rb

次の行をファイルに追加して、サメと投稿の関係を確立します。

〜/ sharkapp / app / models / shark.rb

class Shark < ApplicationRecord

 validates :name, presence: true, uniqueness: true
 validates :facts, presence: true
end

ここで考える価値のあることの1つは、特定のサメが削除されると投稿に何が起こるかです。 削除されたサメに関連する投稿がデータベースに保持されることは望ましくありません。 特定のサメに関連付けられている投稿がそのサメが削除されたときに確実に削除されるようにするには、関連付けに `+ dependent +`オプションを含めることができます。

次のコードをファイルに追加して、特定のサメでの `+ destroy +`アクションが関連する投稿を削除するようにします:

〜/ sharkapp / app / models / shark.rb

class Shark < ApplicationRecord
 has_many :posts
 validates :name, presence: true, uniqueness: true
 validates :facts, presence: true
end

これらの変更が完了したら、ファイルを保存して閉じます。 + nano +`で作業している場合は、 `+ CTRL + X ++ Y +、次に `+ ENTER +`を押してこれを行います。

これで投稿用のモデルが生成されましたが、データベース内のデータと生成されてユーザーに表示されるHTMLの間で調整するためにhttps://guides.rubyonrails.org/action_controller_overview.html[controller]も必要になります。

手順2-入れ子になったリソースのコントローラーの作成

投稿コントローラーを作成するには、アプリケーションのメインルーティングファイルにネストされたリソースルートを設定し、コントローラーファイル自体を作成して、特定のアクションに関連付けるメソッドを指定します。

まず、 `+ config / routes.rb +`ファイルを開いて、リソースフルルート間の関係を確立します。

nano config/routes.rb

現在、ファイルは次のようになっています。

〜/ sharkapp / config / routes.rb

Rails.application.routes.draw do
 resources :sharks

 root 'sharks#index'
 # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

サメと投稿リソースの間にhttps://guides.rubyonrails.org/routing.html#nested-resources [依存関係]関係を作成します。 これを行うには、ルート宣言を更新して、 `:sharks +`を `:posts +`の親にします。 ファイル内のコードを次のように更新します。

〜/ sharkapp / config / routes.rb

Rails.application.routes.draw do
 resources :sharks


 root 'sharks#index'
 # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

編集が終了したら、ファイルを保存して閉じます。

次に、コントローラー用に「+ app / controllers / posts_controller.rb +」という新しいファイルを作成します。

nano app/controllers/posts_controller.rb

このファイルでは、個々の投稿を作成および破棄するために使用するメソッドを定義します。 ただし、これはネストされたモデルであるため、特定の投稿を特定のサメに関連付けるために使用できるローカルインスタンス変数「+ @ shark +」も作成する必要があります。

最初に、2つの + private +`メソッドと共に、 `+ PostsController +`クラス自体を作成できます。特定のサメを参照できるようにする `+ get_shark +`と、ユーザーへのアクセスを提供する `+ post_params + params method経由で送信された情報。

ファイルに次のコードを追加します。

〜/ sharkapp / app / controllers / posts_controller.rb

class PostsController < ApplicationController
 before_action :get_shark

 private

 def get_shark
   @shark = Shark.find(params[:shark_id])
 end

 def post_params
   params.require(:post).permit(:body, :shark_id)
 end
end

`+:shark_id +`キーと、ユーザーが投稿を作成するために入力しているデータを使用して、投稿に関連付けられる特定のサメのインスタンスを取得するメソッドが用意されました。 これらのオブジェクトは両方とも、投稿の作成と破棄を処理するために定義するメソッドで使用できます。

次に、 `+ private `メソッドの上で、ファイルに次のコードを追加して、 ` create `および ` destroy +`メソッドを定義します。

〜/ sharkapp / app / controllers / posts_controller.rb

. . .
 def create
   @post = @shark.posts.create(post_params)
 end

 def destroy
   @post = @shark.posts.find(params[:id])
   @post.destroy
 end
. . .

これらのメソッドは、 `+ @ post `インスタンスを特定の ` @ shark `インスタンスに関連付け、https://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many [collection methods]を使用しますサメと投稿の間に ` has_many `アソシエーションを作成したときに利用可能になりました。 ` find `や ` create +`などのメソッドを使用すると、特定のサメに関連付けられた投稿のコレクションをターゲットにすることができます。

完成したファイルは次のようになります。

〜/ sharkapp / app / controllers / posts_controller.rb

class PostsController < ApplicationController
 before_action :get_shark

 def create
   @post = @shark.posts.create(post_params)
 end

 def destroy
   @post = @shark.posts.find(params[:id])
   @post.destroy
 end

 private

 def get_shark
   @shark = Shark.find(params[:shark_id])
 end

 def post_params
   params.require(:post).permit(:body, :shark_id)
 end
end

編集が終了したら、ファイルを保存して閉じます。

コントローラーとモデルを配置したら、ビューテンプレートと、アプリケーションで生成されたHTMLをどのように整理するかについて考え始めることができます。

ステップ3-パーシャルを使用したビューの再編成

`+ Post +`モデルとコントローラーを作成したので、Railsの観点から考える最後のことは、ユーザーがサメに関する情報を表示して入力できるようにするビューです。 ビューは、スティミュラスとの対話性を構築する機会もあります。

このステップでは、Stimulusを使用した作業の開始点となるビューとパーシャルをマップします。

投稿および投稿に関連付けられたすべてのパーシャルのベースとして機能するビューは、 `+ sharks / show +`ビューです。

ファイルを開きます。

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

現在、ファイルは次のようになっています。

〜/ sharkapp / app / views / sharks / show.html.erb

<p id="notice"><%= notice %></p>

<p>
 <strong>Name:</strong>
 <%= @shark.name %>
</p>

<p>
 <strong>Facts:</strong>
 <%= @shark.facts %>
</p>

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

`+ Post `モデルを作成したとき、 ` sharks / show +`ビューで処理するため、投稿のビューを生成しないことを選択しました。 そのため、このビューで最初に対処するのは、新しい投稿に対するユーザー入力をどのように受け入れるか、およびユーザーに投稿をどのように提示するかです。

すべての機能をこのビューに組み込む代わりに、パーシャルを使用します-特定の機能を提供する再利用可能なテンプレート。 新しい投稿用にパーシャルを作成し、ユーザーへの投稿の表示方法を制御する別のパーシャルを作成します。 目標はJavaScriptで投稿の表示を制御することであるため、Stimulusを使用してページ上の投稿の外観を操作する方法と場所を検討します。

まず、サメの事実の下に、投稿用の `+ <h2> `ヘッダーと、 ` sharks / posts +`というパーシャルをレンダリングする行を追加します。

〜/ sharkapp / app / views / sharks / show.html.erb

. . .
<p>
 <strong>Facts:</strong>
 <%= @shark.facts %>
</p>



. . .

これにより、新しい投稿オブジェクトのフォームビルダーでパーシャルがレンダリングされます。

次に、「+ Edit 」および「 Back 」リンクの下に、ページ上の古い投稿の表示を制御するセクションを追加します。 ファイルに次の行を追加して、 ` sharks / all +`という名前のパーシャルをレンダリングします。

〜/ sharkapp / app / views / sharks / show.html.erb

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

`+ <div> +`要素は、Stimulusをこのファイルに統合し始めるときに役立ちます。

これらの編集が完了したら、ファイルを保存して閉じます。 Rails側で行った変更により、Stimulusをインストールしてアプリケーションに統合することができます。

ステップ4-Stimulusのインストール

Stimulusを使用する最初のステップは、Stimulusを使用するようにアプリケーションをインストールおよび構成することです。 これには、https://yarnpkg.com [Yarn]パッケージマネージャーやhttps://github.com/rails/webpacker[Webpacker]など、適切な依存関係があることを確認することが含まれます。 JavaScriptプリプロセッサーとバンドラーhttps://webpack.js.org/[webpack]。 これらの依存関係が整ったら、Stimulusをインストールし、JavaScriptを使用してDOMのイベントと要素を操作できるようになります。

Yarnをインストールすることから始めましょう。 まず、パッケージリストを更新します。

sudo apt update

次に、Debian YarnリポジトリのGPGキーを追加します。

curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -

リポジトリをAPTソースに追加します。

echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list

新しく追加されたYarnパッケージでパッケージデータベースを更新します。

sudo apt update

最後に、Yarnをインストールします。

sudo apt install yarn

+ yarn +`をインストールしたら、プロジェクトに `+ webpacker + gemを追加することに進みます。

プロジェクトのGemfileを開きます。このファイルには、プロジェクトのgemの依存関係がリストされています。

nano Gemfile

ファイル内では、ターボリンクがデフォルトで有効になっています:

〜/ sharkapp / Gemfile

. . .
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5'
. . .

Turbolinksは、ページの読み込みを最適化することでパフォーマンスを改善するように設計されています。リンククリックで新しいページに移動する代わりに、Turbolinksはこれらのクリックイベントをインターセプトし、https://en.wikipedia.org/wiki/Ajax_(programming)[非同期JavaScriptおよびHTML(AJAX)]。 次に、現在のページの本文を置き換え、 `+ <head> `セクションのコンテンツをマージします。JavaScriptの ` window `および ` document `オブジェクトと ` <html> +`要素はレンダリング間で保持されます。 これにより、ページの読み込み時間が遅くなる主な原因の1つである、CSSおよびJavaScriptリソースのリロードが解決されます。

GemfileではTurbolinksがデフォルトで取得されますが、Stimulusをインストールして使用できるように、 + webpacker + gemを追加する必要があります。 + turbolinks + gemの下に、 `+ webpacker +`を追加します。

〜/ sharkapp / Gemfile

. . .
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5'

. . .

完了したら、ファイルを保存して閉じます。

次に、 `+ bundle +`コマンドを使用して、gemをプロジェクトのバンドルに追加します。

bundle

これにより、新しい `+ Gemfile.lock +`ファイルが生成されます。これは、プロジェクトの宝石とバージョンの決定的な記録です。

次に、次の `+ bundle exec +`コマンドを使用して、gemをバンドルのコンテキストにインストールします。

bundle exec rails webpacker:install

インストールが完了したら、アプリケーションのコンテンツセキュリティファイルを少し調整する必要があります。 これは、https://guides.rubyonrails.org/security.html#content-security-policy [コンテンツセキュリティポリシー(CSP)]の制限された環境であるRails 5.2+で作業しているという事実によるものです。アプリケーションで許可されるスクリプトは、信頼できるソースからのものでなければなりません。

Railsがアプリケーション全体のセキュリティポリシーを定義するために提供するデフォルトのファイルである `+ config / initializers / content_security_policy.rb +`を開きます。

nano config/initializers/content_security_policy.rb

ファイルの最後に次の行を追加して、許可されたオリジンとして、アプリケーションのWebパックバンドルを提供するサーバーである `+ webpack-dev-server`を許可します。

〜/ sharkapp / config / initializers / content_security_policy.rb

. . .
Rails.application.config.content_security_policy do |policy|
 policy.connect_src :self, :https, 'http://localhost:3035', 'ws://localhost:3035' if Rails.env.development?
end

これにより、 `+ webpacker-dev-server +`が信頼できるアセットソースとして認識されるようになります。

この変更が完了したら、ファイルを保存して閉じます。

`+ webpacker `をインストールすることで、プロジェクトの ` app `ディレクトリ(メインアプリケーションコードがあるディレクトリ)に2つの新しいディレクトリを作成しました。 新しい親ディレクトリ ` app / javascript`は、プロジェクトのJavaScriptコードが存在する場所であり、次の構造になります。

Output├── javascript
│   ├── controllers
│   │   ├── hello_controller.js
│   │   └── index.js
│   └── packs
│       └── application.js

+ app / javascript +`ディレクトリには2つの子ディレクトリが含まれます: `+ app / javascript / packs +(webpackエントリポイントがあります)、および + app / javascript / controllers +(Stimulus https:/を定義する場所) /stimulusjs.org/reference/controllers[controllers]。 使用したばかりの `+ bundle exec `コマンドは、 ` app / javascript / packs `ディレクトリを作成しますが、 ` app / javascript / controllers +`ディレクトリを自動生成するにはStimulusをインストールする必要があります。

`+ webpacker +`がインストールされたら、次のコマンドでStimulusをインストールできます。

bundle exec rails webpacker:install:stimulus

次のような出力が表示され、インストールが成功したことが示されます。

Output. . .
success Saved lockfile.
success Saved 5 new dependencies.
info Direct dependencies
└─ [email protected]
info All dependencies
├─ @stimulus/[email protected]
├─ @stimulus/[email protected]
├─ @stimulus/[email protected]
├─ @stimulus/[email protected]
└─ [email protected]
Done in 8.30s.
Webpacker now supports Stimulus.js 🎉

これでStimulusがインストールされ、適切な場所で作業するために必要なメインディレクトリがインストールされました。 コードの記述に進む前に、インストールプロセスを完了するために、アプリケーションレベルの調整をいくつか行う必要があります。

まず、JavaScriptコードが利用可能であり、メインの `+ webpacker `エントリポイントで定義されたコードである ` app / javascript / packs / application.js + `、ページがロードされるたびに実行されます。

そのファイルを開きます:

nano app/views/layouts/application.html.erb

次の `+ javascript_include_tag `タグを ` javascript__tag `に変更して、 ` app / javascript / packs / application.js +`をロードします。

〜/ sharkapp / app / views / layouts / application.html.erb

. . .
   <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
   <%= javascript__tag 'application', 'data-turbolinks-track': 'reload' %>
. . .

この変更を行ったら、ファイルを保存して閉じます。

次に、 `+ app / javascript / packs / application.js +`を開きます。

nano app/javascript/packs/application.js

最初、ファイルは次のようになります。

〜/ sharkapp / app / javascript / packs / application.js

. . .
console.log('Hello World from Webpacker')

import "controllers"

そこにある定型コードを削除し、次のコードを追加してStimulusコントローラーファイルをロードし、アプリケーションインスタンスを起動します。

〜/ sharkapp / app / javascript / packs / application.js

. . .
import { Application } from "stimulus"
import { definitionsFromContext } from "stimulus/webpack-helpers"

const application = Application.start()
const context = require.context("../controllers", true, /\.js$/)
application.load(definitionsFromContext(context))

このコードはwebpackヘルパーメソッドを使用して、 `+ app / javascript / controllers +`ディレクトリ内のコントローラーを必要とし、アプリケーションで使用するためにこのコンテキストをロードします。

編集が終了したら、ファイルを保存して閉じます。

これで、Stimulusがインストールされ、アプリケーションで使用する準備が整いました。 次に、Stimulus controllers _、 targets_、および_actions_を使用して、サメの + show +`ビューで参照したパーシャル-+ sharks / posts `および ` sharks / all +`-を構築します。

ステップ5-Railsパーシャルで刺激を使用する

+ sharks / posts +`パーシャルはhttps://api.rubyonrails.org/v5.2.3/classes/ActionView/Helpers/FormHelper.html [+ form_with +`フォームヘルパー]を使用して新しい投稿オブジェクトを作成します。 また、Stimulusの3つのコアコンセプトであるコントローラー、ターゲット、アクションも利用します。 これらの概念は次のように機能します。

  • コントローラは、JavaScriptモジュールで定義され、モジュールのデフォルトオブジェクトとしてエクスポートされるJavaScriptクラスです。 コントローラを介して、特定のHTML要素と、 `+ app / javascript / packs / application.js +`で定義されているStimulus Applicationインスタンスにアクセスできます。

  • ターゲットを使用すると、特定のHTML要素を名前で参照でき、特定のコントローラーに関連付けられます。

  • アクションは、コントローラーによるDOMイベントの処理方法を制御し、特定のコントローラーにも関連付けられます。 これらは、コントローラーに関連付けられたHTML要素、コントローラーで定義されたメソッド、およびDOMイベントリスナー間の接続を作成します。

パーシャルでは、通常Railsを使用するのと同じように、まずフォームを作成します。 次に、Simulusコントローラー、アクション、およびターゲットをフォームに追加して、JavaScriptを使用して新しい投稿をページに追加する方法を制御します。

まず、パーシャル用の新しいファイルを作成します。

nano app/views/sharks/_posts.html.erb

ファイル内に、次のコードを追加して、 `+ form_with +`ヘルパーを使用して新しい投稿オブジェクトを作成します。

〜/ sharkapp / app / views / sharks / _posts.html.erb

       <%= form_with model: [@shark, @shark.posts.build] do |form| %>
               <%= form.text_area :body, placeholder: "Your post here" %>
               <br>
               <%= form.submit %>
       <% end %>

これまでのところ、このフォームは典型的なRailsフォームのように動作し、 `+ form_with `ヘルパーを使用して、 ` Post `モデル用に定義されたフィールドでpostオブジェクトを構築します。 したがって、フォームには投稿「:body 」のフィールドがあり、そこに投稿の入力を促す「 placeholder +」を追加しました。

さらに、フォームは、 `+ Shark `モデルと ` Post +`モデルの間の関連付けに伴うコレクションメソッドを利用するようにスコープされています。 この場合、ユーザーが送信したデータから作成された新しい投稿オブジェクトは、現在表示しているサメに関連付けられた投稿のコレクションに属します。

ここでの目標は、刺激データコントローラー、イベント、およびアクションを追加して、投稿データをページに表示する方法を制御することです。 ユーザーは最終的に投稿データを送信し、Stimulusアクションのおかげでページに投稿されたデータを確認します。

まず、 `+ <div> `要素の `+`というフォームにコントローラーを追加します。

〜/ sharkapp / app / views / sharks / _posts.html.erb

       <%= form_with model: [@shark, @shark.posts.build] do |form| %>
                <%= form.text_area :body, placeholder: "Your post here" %>
                <br>
                <%= form.submit %>
       <% end %>

*コントローラーを適切にスコープするために、終了の `+ <div> +`タグを追加してください。

次に、フォーム送信イベントによってトリガーされるアクションをフォームに添付します。 このアクションは、ユーザー入力がページに表示される方法を制御します。 posts Stimulusコントローラーで定義する `+ addPost +`メソッドを参照します:

〜/ sharkapp / app / views / sharks / _posts.html.erb

<div data-controller="posts">
       <%= form_with model: [@shark, @shark.posts.build] do |form| %>
       . . .
                <%= form.submit %>
       <% end %>
</div>

刺激アクションを追加のHTMLデータ属性として送信するには、 + form_with`で +:data`オプションを使用します。 アクション自体には、以下で構成される_action descriptor_と呼ばれる値があります。

  • リッスンするDOMイベント。 ここでは、フォーム要素であるsubmitに関連付けられているデフォルトのイベントを使用しているため、記述子自体でイベントを指定する必要はありません。 一般的な要素/イベントペアの詳細については、https://stimulusjs.org/reference/actions#event-shorthand [Stimulus documentation]を参照してください。

  • コントローラ識別子、この場合は「+ posts +」。

  • イベントが呼び出す必要のあるメソッド。 私たちの場合、これはコントローラーで定義する `+ addBody +`メソッドです。

次に、 +:body + `+ <textarea> `要素で定義されたユーザー入力にデータターゲットをアタッチします。これは、この入力値を ` addBody +`メソッドで使用するためです。

次の +:data`オプションを :body`の ` <textarea> +`要素に追加します:

〜/ sharkapp / app / views / sharks / _posts.html.erb

<div data-controller="posts">
       <%= form_with model: [@shark, @shark.posts.build], data: { action: "posts#addBody" } do |form| %>
               <%= form.text_area :body, placeholder: "Your post here" %>
. . .

アクション記述子と同様に、刺激ターゲットには_ターゲット記述子_があり、これにはコントローラー識別子とターゲット名が含まれます。 この場合、「+ posts 」がコントローラーであり、「 body +」がターゲット自体です。

最後のステップとして、入力された「+ body +」値のデータターゲットを追加して、投稿が送信されるとすぐにユーザーが投稿を表示できるようにします。

フォームの下と閉じている `+ <div> `の上に ` add `ターゲットを持つ次の ` <ul> +`要素を追加します。

〜/ sharkapp / app / views / sharks / _posts.html.erb

. . .
       <% end %>



</div>

「+ body 」ターゲットの場合と同様に、ターゲット記述子にはコントローラーの名前とターゲットの両方が含まれます。この場合は「 add +」です。

完成したパーシャルは次のようになります。

〜/ sharkapp / app / views / sharks / _posts.html.erb

<div data-controller="posts">
       <%= form_with model: [@shark, @shark.posts.build], data: { action: "posts#addBody"} do |form| %>
               <%= form.text_area :body, placeholder: "Your post here", data: { target: "posts.body" } %>
               <br>
               <%= form.submit %>
       <% end %>
 <ul data-target="posts.add">
 </ul>

</div>

これらの変更を行ったら、ファイルを保存して閉じることができます。

これで、 `+ sharks / show s`ビューテンプレートに追加した2つのパーシャルの1つを作成しました。 次に、2番目の「+ sharks / all +」を作成します。これは、データベースからの古い投稿をすべて表示します。

`+ app / views / sharks / `ディレクトリに ` _all.html.erb +`という名前の新しいファイルを作成します:

nano app/views/sharks/_all.html.erb

次のコードをファイルに追加して、選択したサメに関連付けられている投稿のコレクションを反復処理します。

〜/ sharkapp / app / views / sharks / _all.html.erb

<% for post in @shark.posts  %>
   <ul>

       <li class="post">
           <%= post.body %>
       </li>

   </ul>
   <% end %>

このコードはforループを使用して、特定のサメに関連付けられた投稿オブジェクトのコレクション内の各投稿インスタンスを反復処理します。

このパーシャルにいくつかの刺激アクションを追加して、ページ上の投稿の外観を制御できます。 具体的には、アップ投票を制御するアクションと、ページに投稿が表示されるかどうかを追加します

ただし、その前に、gemsをプロジェクトに追加して、https://fontawesome.com/ [Font Awesome]アイコンを操作できるようにする必要があります。このアイコンを使用して、投票を登録します。 2番目のターミナルウィンドウを開き、 `+ sharkapp +`プロジェクトディレクトリに移動します。

Gemfileを開きます。

nano Gemfile

+ webpacker + gemの下に、次の行を追加して、https://github.com/bokmann/font-awesome-rails [+ font-awesome-rails + gem]をプロジェクトに含めます。

〜/ sharkapp / Gemfile

. . .
gem 'webpacker', '~> 4.x'

. . .

ファイルを保存して閉じます。

次に、gemをインストールします。

bundle install

最後に、アプリケーションのメインスタイルシート「+ app / assets / stylesheets / application.css」を開きます。

nano app/assets/stylesheets/application.css

Font Awesomeのスタイルをプロジェクトに含めるには、次の行を追加します。

〜/ sharkapp / app / assets / stylesheets / application.css

. . .
*
*= require_tree .
*= require_self

*/

ファイルを保存して閉じます。 これで、2番目のターミナルウィンドウを閉じることができます。

+ app / views / sharks / _all.html.erb +`パーシャルに戻り、2つのhttps://api.rubyonrails.org/v5.2.3/classes/ActionView/Helpers/FormTagHelper.html#method-を追加できるようになりましたi-button_tag [+ button_tags +`]に関連付けられたStimulusアクション。クリックイベントでトリガーされます。 1つのボタンはユーザーに投稿に投票するオプションを提供し、もう1つのボタンはページビューから削除するオプションを提供します。

次のコードを `+ app / views / sharks / _all.html.erb +`に追加します。

〜/ sharkapp / app / views / sharks / _all.html.erb

<% for post in @shark.posts  %>
   <ul>

       <li class="post">
           <%= post.body %>


       </li>

   </ul>
   <% end %>

ボタンタグには「:data +」オプションも使用されるため、投稿スティミュラスコントローラーと2つのアクション「 remove 」と「 upvote 」を追加しました。 繰り返しますが、アクション記述子では、コントローラーとメソッドを定義するだけです。ボタン要素に関連付けられているデフォルトのイベントはクリックであるためです。 これらの各ボタンをクリックすると、コントローラーで定義されたそれぞれの ` remove `および ` upvote +`メソッドがトリガーされます。

編集が終了したら、ファイルを保存して閉じます。

コントローラーの定義に進む前に行う最後の変更は、データターゲットとアクションを設定して、「+ sharks / all +」パーシャルの表示方法とタイミングを制御することです。

現在、 `+ sharks / all `をレンダリングするための最初の呼び出しが定義されている ` show +`テンプレートを開きます。

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

ファイルの下部には、現在次のような `+ <div> +`要素があります:

〜/ sharkapp / app / views / sharks / show.html.erb

. . .
<div>
 <%= render 'sharks/all' %>
</div>

最初に、この `+ <div> +`要素にコントローラーを追加して、アクションとターゲットをスコープします:

〜/ sharkapp / app / views / sharks / show.html.erb

. . .
<div >
 <%= render 'sharks/all' %>
</div>

次に、ページ上のパーシャルの外観を制御するボタンを追加します。 このボタンは、投稿コントローラーで `+ showAll +`メソッドをトリガーします。

`+ <div> `要素の下と ` render +`ステートメントの上にボタンを追加します:

〜/ sharkapp / app / views / sharks / show.html.erb

. . .
<div data-controller="posts">



 <%= render 'sharks/all' %>

繰り返しますが、ここでは `+ posts `コントローラーと ` showAll +`メソッドを識別するだけで済みます。アクションはクリックイベントによってトリガーされます。

次に、データターゲットを追加します。 このターゲットを設定する目的は、ページ上のパーシャルの外観を制御することです。 最終的に、ユーザーが「古い投稿を表示」ボタンをクリックして、そうすることを選択した場合にのみ、古い投稿を表示するようにします。

そのため、「+ show 」というデータターゲットを「 sharks / all 」パーシャルにアタッチし、デフォルトスタイルをhttps://developer.mozilla.org/en-US/docs/Web/CSS/visibilityに設定します[ ` visibility:hidden +`]。 ユーザーがボタンをクリックして表示することを選択しない限り、これによりパーシャルが非表示になります。

次の `+ <div> `要素を ` show `ターゲットと ` style +`定義とともにボタンの下と部分的なrenderステートメントの上に追加します:

〜/ sharkapp / app / views / sharks / show.html.erb

. . .
<div data-controller="posts">

<button data-action="posts#showAll">Show Older Posts</button>


 <%= render 'sharks/all' %>

終了の `+ </ div> +`タグを必ず追加してください。

完成した `+ show +`テンプレートは次のようになります。

〜/ sharkapp / app / views / sharks / show.html.erb

<p id="notice"><%= notice %></p>

<p>
 <strong>Name:</strong>
 <%= @shark.name %>
</p>

<p>
 <strong>Facts:</strong>
 <%= @shark.facts %>
</p>

<h2>Posts</h2>

<%= render 'sharks/posts' %>

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

<div data-controller="posts">

<button data-action="posts#showAll">Show Older Posts</button>

<div data-target="posts.show" style="visibility:hidden">
 <%= render 'sharks/all' %>
</div>
</div>

編集が終了したら、ファイルを保存して閉じます。

このテンプレートとそれに関連するパーシャルが完成したら、これらのファイルで参照したメソッドを使用してコントローラーを作成することができます。

ステップ6-刺激コントローラーの作成

Stimulusをインストールすると、 `+ app / javascript / controllers +`ディレクトリが作成されます。これはwebpackがアプリケーションコンテキストをロードする場所であるため、このディレクトリに投稿コントローラを作成します。 このコントローラーには、前のステップで参照した各メソッドが含まれます。

  • + addBody()+、新しい投稿を追加します。

  • + showAll()+、古い投稿を表示します。

  • 現在のビューから投稿を削除するには、 + remove()+

  • + upvote()+、投稿にアップ投票アイコンを添付します。

+ app / javascript / controllers or`ディレクトリに + posts controller.js`というファイルを作成します:

nano app/javascript/controllers/posts_controller.js

まず、ファイルの先頭で、Stimulus組み込みの `+ Controller`クラスを拡張します。

〜/ sharkapp / app / javascript / controllers / posts_controller.js

import { Controller } from "stimulus"

export default class extends Controller {
}

次に、次のターゲット定義をファイルに追加します。

〜/ sharkapp / app / javascript / controllers / posts_controller.js

. . .
export default class extends Controller {

}

この方法でターゲットを定義すると、メソッドで `+ this.Target `プロパティを使用してそれらにアクセスできるようになり、最初に一致するターゲット要素が提供されます。 したがって、たとえば、targets配列で定義された ` body `データターゲットに一致させるには、 ` this.Target +`を使用します。 このプロパティを使用すると、入力値やCSSスタイルなどを操作できます。

次に、ページ上の新しい投稿の外観を制御する `+ addBody +`メソッドを定義できます。 このメソッドを定義するには、ターゲット定義の下に次のコードを追加します。

〜/ sharkapp / app / javascript / controllers / posts_controller.js

. . .
export default class extends Controller {
   static targets = [ "body", "add", "show"]





}

このメソッドはhttps://www.digitalocean.com/community/tutorials/understanding-variables-scope-hoisting-in-javascript#difference-between-var,-let,-and-constで + content +`変数を定義します[+ let `キーワード]と、ユーザーが投稿フォームに入力した投稿入力文字列と同じに設定します。 これは、フォームの ` <textarea> `要素に接続した ` body `データターゲットによって行われます。 ` this.bodyTarget `を使用してこの要素に一致させると、それに関連付けられているhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLTextAreaElement [` value ` property]を使用できます投稿入力ユーザーが入力したとおりに「 content +」の値を設定する要素。

次に、メソッドは、この投稿入力を、フォームビルダーの下の + <ul> +`要素に追加した `+ add +`ターゲットに、 `+ sharks / posts +`パーシャルで追加します。 https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML [+ Element.insertAdjacentHTML()` method]を使用してこれを行い、新しい投稿のコンテンツを挿入します、 ` add `ターゲット要素の前に、 ` content `変数で設定します。 また、新しい投稿が箇条書きリスト項目として表示されるように、新しい投稿を ` <li> +`要素で囲みました。

次に、 `+ addBody `メソッドの下に、ページ上の古い投稿の外観を制御する ` showAll +`メソッドを追加できます。

〜/ sharkapp / app / javascript / controllers / posts_controller.js

. . .
export default class extends Controller {
. . .
   addBody() {
       let content = this.bodyTarget.value;
       this.addTarget.insertAdjacentHTML('beforebegin', "<li>" + content + "</li>");
   }





}

ここで、 `+ shark。/ all `パーシャルで ` <div> `要素にアタッチされている ` show `ターゲットと一致するように、 ` this.Target `プロパティを再び使用します。 デフォルトのスタイル、 `" visibility:hidden "`を指定したため、このメソッドでは、スタイルを単に `" visible "+`に変更します。 これにより、古い投稿の表示を選択したユーザーにパーシャルが表示されます。

`+ showAll `の下に、 ` upvote `メソッドを追加して、ユーザーがhttps://fontawesome.com/icons?d=gallery&m=free[free]を添付してページに投稿を「アップロード」できるようにします。 Font Awesomeの特定の投稿への ` check-circle +`アイコン。

次のコードを追加して、このメソッドを定義します。

〜/ sharkapp / app / javascript / controllers / posts_controller.js

. . .
export default class extends Controller {
. . .

   showAll() {
       this.showTarget.style.visibility = "visible";
   }






}

ここでは、クラス `+ post `の最も近い ` <li> `要素(ループ内の各 ` <li> `要素にアタッチしたクラス)をターゲットとする ` post `変数を作成しています。 ` sharks / all `での繰り返し。 これは、最も近い投稿をターゲットにし、最後の子の後に、「 <li> 」要素のすぐ内側に「 check-circle」アイコンを追加します。

次に、同様の方法を使用して、ページ上の投稿を非表示にします。 `+ upvote `メソッドの下に次のコードを追加して、 ` remove +`メソッドを定義します。

〜/ sharkapp / app / javascript / controllers / posts_controller.js

. . .
export default class extends Controller {
. . .

   upvote() {
       let post = event.target.closest(".post");
       post.insertAdjacentHTML('beforeend', '<i class="fa fa-check-circle"></i>');
   }





}

繰り返しますが、 + post`変数はクラス + post`を持つ最も近い `+ <li> `要素をターゲットにします。 次に、visibilityプロパティを `" hidden "+`に設定して、ページ上の投稿を非表示にします。

完成したコントローラーファイルは次のようになります。

〜/ sharkapp / app / javascript / controllers / posts_controller.js

import { Controller } from "stimulus"

export default class extends Controller {

   static targets = ["body", "add", "show"]

   addBody() {
       let content = this.bodyTarget.value;
       this.addTarget.insertAdjacentHTML('beforebegin', "<li>" + content + "</li>");
   }

   showAll() {
       this.showTarget.style.visibility = "visible";
   }

   upvote() {
       let post = event.target.closest(".post");
       post.insertAdjacentHTML('beforeend', '<i class="fa fa-check-circle"></i>');
   }

   remove() {
       let post = event.target.closest(".post");
       post.style.visibility = "hidden";
   }
}

編集が終了したら、ファイルを保存して閉じます。

Stimulusコントローラーを適切に配置したら、「+ index +」ビューに最終的な変更を加えて、アプリケーションをテストすることができます。

手順7-インデックスビューの変更とアプリケーションのテスト

サメの `+ index `ビューに最後の変更を加えると、アプリケーションをテストする準備が整います。 ` index +`ビューはアプリケーションのルートであり、https://www.digitalocean.com/community/tutorials/how-to-build-a-ruby-on-rails-application#step-4で設定します-%E2%80%94-creating-the-application-root-view-and-testing-functionality [Step 4] of https://www.digitalocean.com/community/tutorials/how-to-build-a- ruby-on-rails-application [Ruby on Railsアプリケーションの構築方法]。

ファイルを開きます。

nano app/views/sharks/index.html.erb

サメを表示および破壊するために自動生成された「+ link_to 」ヘルパーの代わりに、「 button_to 」ヘルパーを使用します。 これは、デフォルトのRails JavaScriptアセットの代わりに生成されたHTMLコードを使用するのに役立ちます。これは、ステップ1で ` javascript_include_tag `を ` javascript_pack_tag `に ` app / views / layouts / application.html.erb + `。

ファイル内の既存の `+ link_to `ヘルパーを次の ` button_to +`ヘルパーに置き換えます。

〜/ sharkapp / app / views / sharks / index.html.erb

. . .
 <tbody>
   <% @sharks.each do |shark| %>
     <tr>
       <td><%= shark.name %></td>
       <td><%= shark.facts %></td>
       <td></td>
       <td></td>
       <td></td>
     </tr>
   <% end %>
 </tbody>
. . .

これらのヘルパーは、対応する `+ link_to `とほぼ同じことを達成しますが、 ` Destroy +`ヘルパーはRailsのデフォルトJavaScriptではなく、生成されたHTMLに依存するようになりました。

編集が終了したら、ファイルを保存して閉じます。

これで、アプリケーションをテストする準備ができました。

まず、データベースの移行を実行します。

rails db:migrate

次に、サーバーを起動します。 ローカルで作業している場合は、次のコマンドでこれを行うことができます。

rails s

開発サーバーで作業している場合は、次を使用してアプリケーションを開始できます。

rails s --binding=

ブラウザでアプリケーションのランディングページに移動します。 ローカルで作業している場合、これは「+ localhost:3000+」、またはサーバーで作業している場合は「+ http://:3000+」になります。

次のランディングページが表示されます。

image:https://assets.digitalocean.com/articles/stimulus/stimulus_landing.png [アプリケーションのランディングページ]

  • Show *をクリックすると、このサメの `+ show +`ビューに移動します。 ここに投稿を記入するフォームが表示されます:

image:https://assets.digitalocean.com/articles/stimulus/stimulus_empty_post.png [シャークショーページ]

投稿フォームで、「これらのサメは怖い!」と入力します。

image:https://assets.digitalocean.com/articles/stimulus/stimulus_fill_post.png [記入済みの投稿]

[投稿の作成]をクリックします。 ページに新しい投稿が表示されます。

image:https://assets.digitalocean.com/articles/stimulus/stimulus_show_post.png%20.png [ページに追加された新しい投稿]

必要に応じて、別の新しい投稿を追加できます。 今回は、「これらのサメは映画でしばしば不正確に表示される」と入力し、[投稿を作成]をクリックします。

image:https://assets.digitalocean.com/articles/stimulus/stimulus_two_posts.png [ページに追加された2番目の投稿]

*以前の投稿を表示*機能の機能をテストするには、現在追加した投稿より古い投稿がグレートホワイトにないため、このページを終了する必要があります。

*戻る*をクリックしてメインページに移動し、*表示*をクリックしてグレートホワイトランディングページに戻ります。

image:https://assets.digitalocean.com/articles/stimulus/stimulus_empty_post.png [シャークショーページ]

[古い投稿を表示]をクリックすると、作成した投稿が表示されます。

image:https://assets.digitalocean.com/articles/stimulus/stimulus_show_older.png [古い投稿を表示]

[投稿に投票]ボタンをクリックして、投稿に投票できます。

image:https://assets.digitalocean.com/articles/stimulus/stimulus_upvote.png [投稿に投票]

同様に、[投稿を削除]をクリックすると、投稿が非表示になります。

image:https://assets.digitalocean.com/articles/stimulus/stimulus_remove.png [投稿を削除]

これで、Stimulusを使用して、個々のサメのページにネストされた投稿リソースを表示する方法を制御する実用的なRailsアプリケーションがあることを確認できました。 これは、Stimulusの将来の開発および実験の出発点として使用できます。

結論

刺激は、https://github.com/rails/rails/tree/master/actionview/app/assets/javascripts [rails-ujs]、https://jquery.com/ [JQuery]を使用する代わりに考えられる代替手段です。 ReactやVueなどのフレームワーク。

はじめに説明したように、Stimulusは、サーバーによって生成されたHTMLを直接操作する必要がある場合に最も意味があります。 軽量で、コード(特にHTML)を可能な限り自明なものにすることを目的としています。 クライアント側で状態を管理する必要がない場合は、Stimulusが適している可能性があります。

Stimulus統合なしでネストされたリソースを作成する方法に興味がある場合は、https://www.digitalocean.com/community/tutorials/how-to-create-nested-resources-for-a-ruby-on-を参照してください。 rails-application [Ruby on Railsアプリケーションのネストされたリソースを作成する方法]。

ReactをRailsアプリケーションと統合する方法の詳細については、https://www.digitalocean.com/community/tutorials/how-to-set-up-a-ruby-on-rails-project-with-aを参照してください-react-frontend [ReactフロントエンドでRuby on Railsプロジェクトをセットアップする方法]。