序章

Ruby on Rails プロジェクトで作業している場合、要件には、ビューテンプレートによって生成されたHTMLとの対話性が含まれる場合があります。 その場合、この対話性を実装する方法についていくつかの選択肢があります。

たとえば、ReactEmberのようなJavaScriptフレームワークを実装できます。 要件にクライアント側での状態の処理が含まれている場合、またはサーバーへの頻繁なクエリに関連するパフォーマンスの問題が懸念される場合は、これらのフレームワークのいずれかを選択するのが理にかなっている場合があります。 多くのシングルページアプリケーション(SPA)は、このアプローチを採用しています。

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

  1. JavaScriptの解析、JSONのフェッチとHTMLへの変換などの読み込みと変換の要件により、パフォーマンスが制限される可能性があります。
  2. フレームワークへのコミットメントには、特に小規模なJavaScriptの拡張機能を探している場合に、特定のユースケースで必要とされるよりも多くのコードを記述することが含まれる場合があります。
  3. クライアント側とサーバー側の両方で状態管理を行うと、作業が重複し、エラーの表面積が増える可能性があります。

別の方法として、 Basecamp のチーム(Railsを作成したのと同じチーム)が Stimulus.js を作成しました。これは、「既存のHTML用の控えめなJavaScriptフレームワーク」と説明されています。 」 Stimulusは、サーバー側で生成されたHTMLを操作することにより、最新のRailsアプリケーションを強化することを目的としています。 状態はDocumentObject Model(DOM)に存在し、フレームワークはDOM内の要素やイベントと対話するための標準的な方法を提供します。 Turbolinks (デフォルトではRails 5+に含まれています)と連携して動作し、明確に定義された目的に限定され、スコープが設定されたコードでパフォーマンスとロード時間を改善します。

このチュートリアルでは、Stimulusをインストールして使用し、サメに関する情報を読者に提供する既存のRailsアプリケーションを構築します。 このアプリケーションにはすでにサメのデータを処理するためのモデルがありますが、個々のサメに関する投稿用のネストされたリソースを追加して、ユーザーがサメに関する一連の考えや意見を構築できるようにします。 この部分は、JavaScriptを使用してページ上の投稿の位置と外観を操作することを除いて、 RubyonRailsアプリケーションのネストされたリソースを作成する方法とほぼ並行して実行されます。 また、ポストモデル自体を構築するために少し異なるアプローチを取ります。

前提条件

このチュートリアルに従うには、次のものが必要です。

  • Ubuntu18.04を実行しているローカルマシンまたは開発サーバー。 開発マシンには、管理者権限を持つroot以外のユーザーと、で構成されたファイアウォールが必要です。 ufw. これを設定する方法については、 Ubuntu18.04を使用した初期サーバー設定のチュートリアルを参照してください。
  • Node.jsおよびnpmがローカルマシンまたは開発サーバーにインストールされています。 このチュートリアルでは、Node.jsバージョン10.16.3とnpmバージョン6.9.0を使用します。 Ubuntu 18.04にNode.jsとnpmをインストールする手順については、 Ubuntu18.04にNode.jsをインストールする方法の「PPAを使用したインストール」セクションの手順に従ってください。
  • Ubuntu18.04でrbenvを使用してRubyonRailsをインストールする方法の手順1〜4 に従って、ローカルマシンまたは開発サーバーにインストールされたRuby、 rbenv 、およびRails 。 このチュートリアルでは、Ruby 2.5.1 、rbenv 1.1.2 、およびRails 5.2.3を使用します。
  • Ruby on Railsアプリケーションの構築方法の指示に従って、SQLiteをインストールし、基本的なサメ情報アプリケーションを作成しました。

ステップ1—ネストされたモデルの作成

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

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

  1. cd sharkapp

私たちを作成するには Post モデルでは、 railsgenerateコマンドを model 発生器。 次のコマンドを入力して、モデルを作成します。

  1. rails generate model Post body:text shark:references

body:text、Railsに含めるように指示しています body のフィールド posts データベーステーブル—にマップするテーブル Post モデル。 また、 :references キーワード。 SharkPost モデル。 具体的には、これにより、外部キーsharks データベースがに追加されます posts データベース。

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

  1. cat db/migrate/20190805132506_create_posts.rb

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

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

ご覧のとおり、テーブルにはサメの外部キーの列が含まれています。 このキーは次の形式になります model_name_id – 私たちの場合には、 shark_id.

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

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

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

Railsはすでに設定していますが belongs_to 私たちの協会 Post モデル、指定する必要があります has_many 私たちの協会 Shark その関係が適切に機能するためにもモデルを作成します。

追加するには has_many への関連付け Shark モデル、オープン app/models/shark.rb を使用して nano またはお気に入りの編集者:

  1. nano app/models/shark.rb

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

〜/ sharkapp / app / models / shark.rb
class Shark < ApplicationRecord
  has_many :posts
  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, dependent: :destroy
  validates :name, presence: true, uniqueness: true
  validates :facts, presence: true
end

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

これで投稿用にモデルが生成されましたが、データベース内のデータと生成されてユーザーに表示されるHTMLを調整するためのコントローラーも必要になります。

ステップ2—ネストされたリソースのコントローラーを作成する

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

開始するには、 config/routes.rb 機知に富んだルート間の関係を確立するためのファイル:

  1. 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

サメと投稿リソースの間に依存関係関係を作成したいと思います。 これを行うには、ルート宣言を更新して作成します :sharks の親 :posts. ファイル内のコードを次のように更新します。

〜/sharkapp/config/routes.rb
Rails.application.routes.draw do
  resources :sharks do
    resources :posts
  end
  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 コントローラの場合:

  1. nano app/controllers/posts_controller.rb

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

まず、作成することができます PostsController クラス自体、および2つ private メソッド: get_shark、特定のサメを参照できるようになり、 post_paramsparamsメソッドを介してユーザーが送信した情報にアクセスできます。

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

〜/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 メソッドについては、次のコードをファイルに追加して、 createdestroy メソッド:

〜/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 インスタンスを作成し、作成時に使用可能になったコレクションメソッドを使用します。 has_many サメとポストの間の関連付け。 などの方法 findcreate 特定のサメに関連する投稿のコレクションをターゲットにできます。

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

〜/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との双方向性を構築する機会もあります。

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

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

ファイルを開きます。

  1. 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 見る。 したがって、このビューでは、最初に対処するのは、新しい投稿に対するユーザー入力を受け入れる方法と、ユーザーに投稿を提示する方法です。

注:このアプローチの代替方法については、 RubyonRailsアプリケーションのネストされたリソースを作成する方法を参照してください。投稿コントローラーで定義されているRead、Update、Delete (CRUD)メソッド。 これらの方法とその仕組みについては、 RubyonRailsアプリケーションステップ3を参照してください。

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

まず、サメの事実の下に、 <h2> 投稿のヘッダーと、呼び出された部分をレンダリングする行 sharks/posts:

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

<h2>Posts</h2>
<%= render 'sharks/posts' %>
. . . 

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

次に、以下 EditBack リンクには、ページ上の古い投稿の表示を制御するセクションを追加します。 次の行をファイルに追加して、呼び出された部分をレンダリングします sharks/all:

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

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

The <div> このファイルへのStimulusの統合を開始するときに、elementが役立ちます。

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

ステップ4—刺激をインストールする

Stimulusを使用する最初のステップは、アプリケーションをインストールして構成し、それを使用するようにすることです。 これには、YarnパッケージマネージャーやWebpacker、JavaScriptプリプロセッサーおよびバンドラーとの連携を可能にするgemなど、正しい依存関係があることの確認が含まれます。 webpack。 これらの依存関係を設定すると、Stimulusをインストールし、JavaScriptを使用してDOM内のイベントと要素を操作できるようになります。

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

  1. sudo apt update

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

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

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

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

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

  1. sudo apt update

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

  1. sudo apt install yarn

yarn インストールすると、追加に進むことができます webpacker あなたのプロジェクトへの宝石。

プロジェクトのGemfileを開きます。これには、プロジェクトのgem依存関係が一覧表示されています。

  1. nano Gemfile

ファイル内には、デフォルトで有効になっているターボリンクが表示されます。

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

Turbolinksは、ページの読み込みを最適化することでパフォーマンスを向上させるように設計されています。リンククリックで新しいページに移動する代わりに、Turbolinksはこれらのクリックイベントをインターセプトし、非同期JavaScriptおよびHTML(AJAX)を使用してページリクエストを行います。 次に、現在のページの本文を置き換え、コンテンツをマージします <head> セクション、JavaScript windowdocument オブジェクトと <html> 要素はレンダリング間で持続します。 これは、ページの読み込み時間が遅くなる主な原因の1つであるCSSおよびJavaScriptリソースの再読み込みに対処します。

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

〜/ sharkapp / Gemfile
. . . 
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5'
gem 'webpacker', '~> 4.x'
. . . 

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

次に、gemをプロジェクトのバンドルに追加します。 bundle 指図:

  1. bundle

これにより、新しい Gemfile.lock file —プロジェクトのgemとバージョンの決定的な記録。

次に、次のバンドルのコンテキストでgemをインストールします bundle exec 指図:

  1. bundle exec rails webpacker:install

インストールが完了したら、アプリケーションのコンテンツセキュリティファイルを少し調整する必要があります。 これは、コンテンツセキュリティポリシー(CSP)制限付き環境であるRails 5.2+を使用しているためです。つまり、アプリケーションで許可されるスクリプトは、信頼できるソースからのもののみである必要があります。

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

  1. nano config/initializers/content_security_policy.rb

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

〜/ 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、プロジェクトに2つの新しいディレクトリを作成しました app ディレクトリ、メインアプリケーションコードが配置されているディレクトリ。 新しい親ディレクトリ、 app/javascriptは、プロジェクトのJavaScriptコードが存在する場所であり、次の構造になります。

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

The app/javascript ディレクトリには、2つの子ディレクトリが含まれます。 app/javascript/packs、webpackのエントリポイントがあり、 app/javascript/controllers、ここで刺激コントローラーを定義します。 The bundle exec 使用したコマンドで、 app/javascript/packs ディレクトリですが、Stimulusをインストールする必要があります app/javascript/controllers 自動生成されるディレクトリ。

webpacker インストールすると、次のコマンドでStimulusをインストールできるようになります。

  1. 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がインストールされ、Stimulusを操作するために必要なメインディレクトリが配置されました。 コードの記述に進む前に、インストールプロセスを完了するために、アプリケーションレベルでいくつかの調整を行う必要があります。

まず、調整する必要があります app/views/layouts/application.html.erb JavaScriptコードが利用可能であり、メインで定義されているコードを確認するため webpacker エントリーポイント、 app/javascript/packs/application.js、ページが読み込まれるたびに実行されます。

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

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

以下を変更します javascript_include_tag タグを付ける javascript_pack_tag ロードする app/javascript/packs/application.js:

〜/ sharkapp / app / views / layouts / application.html.erb
. . .
    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
. . . 

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

次に、開く app/javascript/packs/application.js:

  1. 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がインストールされ、アプリケーションで使用できるようになりました。 次に、サメで参照したパーシャルを作成します show 見る – sharks/postssharks/all —刺激コントローラーターゲット、およびアクションを使用します。

ステップ5—RailsPartialsでの刺激の使用

私たちの sharks/posts パーシャルは、 form_with formhelperを使用して新しい投稿オブジェクトを作成します。 また、Stimulusの3つのコアコンセプトであるコントローラー、ターゲット、およびアクションを利用します。 これらの概念は次のように機能します。

  • コントローラは、JavaScriptモジュールで定義され、モジュールのデフォルトオブジェクトとしてエクスポートされるJavaScriptクラスです。 コントローラを介して、特定のHTML要素とで定義されたStimulusApplicationインスタンスにアクセスできます。 app/javascript/packs/application.js.
  • ターゲットを使用すると、特定のHTML要素を名前で参照でき、特定のコントローラーに関連付けられます。
  • アクションは、DOMイベントがコントローラーによって処理される方法を制御し、特定のコントローラーにも関連付けられます。 これらは、コントローラーに関連付けられたHTML要素、コントローラーで定義されたメソッド、およびDOMイベントリスナーの間に接続を作成します。

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

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

  1. 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 モデル。 したがって、フォームには投稿用のフィールドがあります :body、に追加しました placeholder 投稿を入力するためのプロンプトが表示されます。

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

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

まず、コントローラーをというフォームに追加します posts<div> エレメント:

〜/ sharkapp / app / views / sharks / _posts.html.erb
<div data-controller="posts">
        <%= form_with model: [@shark, @shark.posts.build] do |form| %>
                 <%= form.text_area :body, placeholder: "Your post here" %>
                 <br>
                 <%= form.submit %>
        <% end %>
</div>

必ずクロージングを追加してください

鬼ごっこコントローラを適切にスコープします。

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

〜/ 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.submit %>
        <% end %>
</div>

を使用します :data オプション付き form_with 追加のHTMLデータ属性としてStimulusアクションを送信します。 アクション自体には、アクション記述子と呼ばれる値があり、次の要素で構成されています。

  • リッスンするDOMイベント。 ここでは、フォーム要素に関連付けられたデフォルトのイベントsubmitを使用しているため、記述子自体でイベントを指定する必要はありません。 一般的な要素/イベントのペアの詳細については、刺激に関するドキュメントを参照してください。
  • コントローラー識別子、この場合 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", data: { target: "posts.body" } %>
. . .

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

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

以下を追加します <ul> 要素と add フォームの下とクロージングの上をターゲット <div>:

〜/ sharkapp / app / views / sharks / _posts.html.erb
. . .
        <% end %>
  <ul data-target="posts.add">
  </ul>

</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>

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

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

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

  1. 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ループを使用して、特定のサメに関連付けられた投稿オブジェクトのコレクション内の各投稿インスタンスを反復処理します。

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

ただし、その前に、プロジェクトにgemを追加して、賛成票の登録に使用する FontAwesomeアイコンを操作できるようにする必要があります。 2番目のターミナルウィンドウを開き、 sharkapp プロジェクトディレクトリ。

Gemfileを開きます。

  1. nano Gemfile

あなたの下に webpacker gemの場合、次の行を追加して、 font-awesome-railsgemをプロジェクトに含めます。

〜/ sharkapp / Gemfile
. . . 
gem 'webpacker', '~> 4.x'
gem 'font-awesome-rails', '~>4.x'
. . . 

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

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

  1. bundle install

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

  1. nano app/assets/stylesheets/application.css

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

〜/ sharkapp / app / Assets / stylesheets / application.css
. . . 
*
 *= require_tree .
 *= require_self
 *= require font-awesome
 */

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

あなたに戻って app/views/sharks/_all.html.erb 部分的に、クリックイベントでトリガーされる刺激アクションが関連付けられた2つのbutton_tagsを追加できるようになりました。 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 %>
            <%= button_tag "Remove Post", data: { controller: "posts", action: "posts#remove" } %>
            <%= button_tag "Upvote Post", data: { controller: "posts", action: "posts#upvote" } %>
        </li>

    </ul>
    <% end %>

ボタンタグも必要です :data オプションなので、投稿Stimulusコントローラーと2つのアクションを追加しました。 removeupvote. 繰り返しになりますが、アクション記述子では、ボタン要素に関連付けられたデフォルトのイベントがクリックであるため、コントローラーとメソッドを定義するだけで済みます。 これらの各ボタンをクリックすると、それぞれがトリガーされます removeupvote コントローラで定義されたメソッド。

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

コントローラの定義に進む前に行う最後の変更は、データターゲットとアクションを設定して、いつどのように sharks/all 部分的に表示されます。

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

  1. 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 data-controller="posts">
  <%= render 'sharks/all' %>
</div>

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

下にボタンを追加します <div> 要素以上 render 声明:

〜/ sharkapp / app / views / sharks / show.html.erb
. . . 
<div data-controller="posts">

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

  <%= render 'sharks/all' %>

繰り返しますが、私たちは私たちを識別する必要があるだけです posts コントローラーと showAll ここでの方法—アクションはクリックイベントによってトリガーされます。

次に、データターゲットを追加します。 このターゲットを設定する目的は、ページ上のパーシャルの外観を制御することです。 最終的には、ユーザーが[ Show Older Posts ボタン。

したがって、というデータターゲットを添付します showsharks/all 部分的で、デフォルトのスタイルを visible:hiddenに設定します。 これにより、ユーザーがボタンをクリックして表示することを選択しない限り、パーシャルが非表示になります。

以下を追加します <div> 要素と show ターゲットと style ボタンの下および部分的なレンダリングステートメントの上にある定義:

〜/ sharkapp / app / views / sharks / show.html.erb
. . . 
<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> 鬼ごっこ。

完成した 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()、投稿に賛成アイコンを添付します。

というファイルを作成します posts_controller.js の中に app/javascript/controllers ディレクトリ:

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 {
    static targets = ["body", "add", "show"]
}

このようにターゲットを定義すると、メソッドでターゲットにアクセスできるようになります。 this.target-nameTarget プロパティ。これにより、最初に一致するターゲット要素が得られます。 したがって、たとえば、 body ターゲット配列で定義されたデータターゲット、 this.bodyTarget. このプロパティを使用すると、入力値やcssスタイルなどを操作できます。

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

〜/sharkapp/app/javascript/controllers/posts_controller.js
. . .
export default class extends Controller {
    static targets = [ "body", "add", "show"]

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

このメソッドは、 content letキーワードを使用して変数を設定し、ユーザーが投稿フォームに入力した投稿入力文字列と同じ値に設定します。 それはのおかげでこれを行います body 添付したデータターゲット <textarea> 私たちのフォームの要素。 使用する this.bodyTarget この要素に一致させるには、その要素に関連付けられているvalueプロパティを使用して次の値を設定できます。 content 投稿入力ユーザーが入力したとおり。

次に、メソッドはこの投稿入力をに追加します add 追加したターゲット <ul> フォームビルダーの下の要素 sharks/posts 部分的。 これは、 Element.insertAdjacentHTML()メソッドを使用して行われます。これにより、で設定された新しい投稿のコンテンツが挿入されます。 content 変数、前 add ターゲット要素。 また、新しい投稿を <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>");
    }

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

}

ここでも、 this.target-nameTarget 私たちに一致するプロパティ show に接続されているターゲット <div> 要素と sharks/all 部分的。 デフォルトのスタイルを設定しました。 "visibility:hidden"したがって、このメソッドでは、スタイルを次のように変更するだけです。 "visible". これにより、古い投稿を表示することを選択したユーザーに部分的に表示されます。

showAll、次に追加します upvote free Font Awesomeを添付して、ユーザーがページ上の投稿に「賛成」できるようにする方法 check-circle 特定の投稿へのアイコン。

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

〜/sharkapp/app/javascript/controllers/posts_controller.js
. . . 
export default class extends Controller {
. . . 

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

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

}

ここでは、 post 最も近いものをターゲットにする変数 <li> クラスを持つ要素 post —それぞれに付けたクラス <li> のループ反復の要素 sharks/all. これにより、最も近い投稿がターゲットになり、 check-circle すぐ内側のアイコン <li> 要素、最後の子の後。

次に、同様の方法を使用してページ上の投稿を非表示にします。 以下のコードを追加します 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>');
    }

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

もう一度、私たちの post 変数は最も近いものをターゲットにします <li> クラスを持つ要素 post. 次に、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—インデックスビューの変更とアプリケーションのテスト

サメへの最後の変更が1つあります index アプリケーションをテストする準備ができていることを確認してください。 The index viewは、 How To Build Ruby on RailsApplicationステップ4で設定したアプリケーションのルートです。

ファイルを開きます。

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

の代わりに link_to サメを表示して破壊するために自動生成されたヘルパーを使用します button_to ヘルパー。 これにより、変更時に手順1で使用しなくなると指定したデフォルトのRails JavaScriptアセットの代わりに、生成されたHTMLコードを操作できるようになります。 javascript_include_tagjavascript_pack_tagapp/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><%= button_to 'Show', shark_path(:id => shark.id), :method => :get %></td>
        <td><%= button_to 'Edit', edit_shark_path(:id => shark.id), :method => :get %></td>
        <td><%= button_to 'Destroy', shark_path(:id => shark.id), :method => :delete %></td>
      </tr>
    <% end %>
  </tbody>
. . . 

これらのヘルパーは、彼らとほとんど同じことを達成します link_to カウンターパート、しかし Destroy ヘルパーは、RailsのデフォルトのJavaScriptではなく、生成されたHTMLに依存するようになりました。

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

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

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

  1. rails db:migrate

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

  1. rails s

開発サーバーで作業している場合は、次のコマンドでアプリケーションを起動できます。

  1. rails s --binding=your_server_ip

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

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

表示をクリックすると、 show このサメのビュー。 ここに、投稿に記入するためのフォームが表示されます。

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

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

![ページに新しい投稿が追加されました]( https://assets.digitalocean.com/articles/stimulus/stimulus_show_post.png .png)

必要に応じて、別の新しい投稿を追加できます。 今回は、「これらのサメは映画で誤って表現されることが多い」と入力し、投稿の作成をクリックします。

古い投稿を表示機能の機能をテストするには、このページを離れる必要があります。これは、現在、グレートホワイトには、追加したばかりの投稿よりも古い投稿がないためです。

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

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

[Upvote Post] ボタンをクリックして、投稿に賛成票を投じることができます。

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

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

結論

Stimulusは、 rails-ujs JQuery 、およびReactやVueなどのフレームワークを操作するための可能な代替手段を表しています。

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

Stimulusを統合せずにネストされたリソースを作成する方法に興味がある場合は、 RubyonRailsアプリケーションのネストされたリソースを作成する方法を参照してください。

ReactをRailsアプリケーションと統合する方法の詳細については、ReactFrontendを使用してRubyonRailsプロジェクトをセットアップする方法を参照してください。