RubyonRailsアプリケーションに刺激を追加する方法
序章
Ruby on Rails プロジェクトで作業している場合、要件には、ビューテンプレートによって生成されたHTMLとの対話性が含まれる場合があります。 その場合、この対話性を実装する方法についていくつかの選択肢があります。
たとえば、ReactやEmberのようなJavaScriptフレームワークを実装できます。 要件にクライアント側での状態の処理が含まれている場合、またはサーバーへの頻繁なクエリに関連するパフォーマンスの問題が懸念される場合は、これらのフレームワークのいずれかを選択するのが理にかなっている場合があります。 多くのシングルページアプリケーション(SPA)は、このアプローチを採用しています。
ただし、クライアント側で状態と頻繁な更新を管理するフレームワークを実装する際に留意すべきいくつかの考慮事項があります。
- JavaScriptの解析、JSONのフェッチとHTMLへの変換などの読み込みと変換の要件により、パフォーマンスが制限される可能性があります。
- フレームワークへのコミットメントには、特に小規模なJavaScriptの拡張機能を探している場合に、特定のユースケースで必要とされるよりも多くのコードを記述することが含まれる場合があります。
- クライアント側とサーバー側の両方で状態管理を行うと、作業が重複し、エラーの表面積が増える可能性があります。
別の方法として、 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アソシエーションを作成します。投稿は特定のサメに属し、各サメは複数の投稿を持つことができます。
開始するには、前提条件でRailsプロジェクト用に作成したsharkapp
ディレクトリに移動します。
cd sharkapp
Post
モデルを作成するには、 railsgenerateコマンドとmodel
ジェネレーターを使用します。 次のコマンドを入力して、モデルを作成します。
rails generate model Post body:text shark:references
body:text
を使用して、Railsにbody
フィールドをposts
データベーステーブル(Post
モデルにマップするテーブル)に含めるように指示しています。 :references
キーワードも含まれています。これはShark
モデルとPost
モデル間の関連付けを設定します。 具体的には、これにより、sharks
データベースの各サメエントリを表す外部キーがposts
データベースに追加されます。
コマンドを実行すると、Railsがアプリケーション用に生成したリソースを確認する出力が表示されます。 先に進む前に、データベース移行ファイルをチェックして、モデルとデータベーステーブルの間に現在存在する関係を確認できます。 次のコマンドを使用してファイルの内容を確認し、ここに表示されているものを自分の移行ファイルのタイムスタンプに置き換えてください。
cat db/migrate/20190805132506_create_posts.rb
次の出力が表示されます。
Outputclass 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
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 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
ファイルを開いて、リソースの豊富なルート間の関係を確立します。
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
という名前の新しいファイルを作成します。
nano app/controllers/posts_controller.rb
このファイルでは、個々の投稿を作成および破棄するために使用するメソッドを定義します。 ただし、これはネストされたモデルであるため、特定の投稿を特定のサメに関連付けるために使用できるローカルインスタンス変数@shark
も作成する必要があります。
まず、PostsController
クラス自体を、特定のサメを参照できるget_shark
とpost_params
の2つのprivate
メソッドとともに作成できます。 、paramsメソッドを介してユーザーが送信した情報にアクセスできます。
次のコードをファイルに追加します。
〜/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
キーを使用して、投稿が関連付けられる特定のsharkインスタンスと、ユーザーが投稿を作成するために入力するデータを取得するメソッドができました。 これらのオブジェクトは両方とも、投稿の作成と破棄を処理するために定義するメソッドで使用できるようになります。
次に、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
インスタンスに関連付け、サメと投稿。 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との双方向性を構築する機会もあります。
このステップでは、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
ビューで処理するため、生成しないことを選択しました。 したがって、このビューでは、最初に対処するのは、新しい投稿に対するユーザー入力を受け入れる方法と、ユーザーに投稿を提示する方法です。
注:このアプローチの代替方法については、 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' %> . . .
これにより、新しい投稿オブジェクトのフォームビルダーでパーシャルがレンダリングされます。
次に、Edit
リンクとBack
リンクの下に、ページ上の古い投稿の表示を制御するセクションを追加します。 次の行をファイルに追加して、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>
<div>
要素は、Stimulusをこのファイルに統合し始めるときに役立ちます。
これらの編集が終了したら、ファイルを保存して閉じます。 Rails側で行った変更により、Stimulusのインストールとアプリケーションへの統合に進むことができます。
ステップ4—刺激をインストールする
Stimulusを使用する最初のステップは、アプリケーションをインストールして構成し、それを使用するようにすることです。 これには、YarnパッケージマネージャーやWebpacker、JavaScriptプリプロセッサーおよびバンドラーとの連携を可能にするgemなど、正しい依存関係があることの確認が含まれます。 webpack。 これらの依存関係を設定すると、Stimulusをインストールし、JavaScriptを使用してDOM内のイベントと要素を操作できるようになります。
Yarnをインストールすることから始めましょう。 まず、パッケージリストを更新します。
sudo apt update
次に、DebianYarnリポジトリの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はこれらのクリックイベントをインターセプトし、非同期JavaScriptおよびHTML(AJAX)を使用してページリクエストを行います。 次に、現在のページの本文を置き換え、<head>
セクションのコンテンツをマージしますが、JavaScriptwindow
およびdocument
オブジェクトと<html>
要素は保持されますレンダリング間。 これは、ページの読み込み時間が遅くなる主な原因の1つであるCSSおよびJavaScriptリソースの再読み込みに対処します。
デフォルトではGemfileにTurbolinksがありますが、Stimulusをインストールして使用できるように、webpacker
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' . . .
終了したら、ファイルを保存して閉じます。
次に、bundle
コマンドを使用して、gemをプロジェクトのバンドルに追加します。
bundle
これにより、新しいGemfile.lock
ファイルが生成されます。これは、プロジェクトのgemとバージョンの最も信頼のおけるレコードです。
次に、次のbundle exec
コマンドを使用して、バンドルのコンテキストにgemをインストールします。
bundle exec rails webpacker:install
インストールが完了したら、アプリケーションのコンテンツセキュリティファイルを少し調整する必要があります。 これは、コンテンツセキュリティポリシー(CSP)制限付き環境であるRails 5.2+を使用しているためです。つまり、アプリケーションで許可されるスクリプトは、信頼できるソースからのもののみである必要があります。
Railsがアプリケーション全体のセキュリティポリシーを定義するために提供するデフォルトのファイルであるconfig/initializers/content_security_policy.rb
を開きます。
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
をインストールすることにより、プロジェクトのapp
ディレクトリ(メインアプリケーションコードが配置されているディレクトリ)に2つの新しいディレクトリを作成しました。 新しい親ディレクトリapp/javascript
は、プロジェクトのJavaScriptコードが存在する場所であり、次の構造になります。
Output├── javascript │ ├── controllers │ │ ├── hello_controller.js │ │ └── index.js │ └── packs │ └── application.js
app/javascript
ディレクトリには、2つの子ディレクトリが含まれます。Webpackエントリポイントを持つapp/javascript/packs
と、Stimulusコントローラーを定義するapp/javascript/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がインストールされ、Stimulusを操作するために必要なメインディレクトリが配置されました。 コードの記述に進む前に、インストールプロセスを完了するために、アプリケーションレベルでいくつかの調整を行う必要があります。
まず、app/views/layouts/application.html.erb
を調整して、JavaScriptコードが使用可能であり、メインのwebpacker
エントリポイントであるapp/javascript/packs/application.js
で定義されたコードが実行されるようにする必要があります。ページが読み込まれるたび。
そのファイルを開きます。
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
を開きます。
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 、を使用して、サメshow
ビュー(sharks/posts
およびsharks/all
)で参照したパーシャルを構築します。ターゲット、およびアクション。
ステップ5—RailsPartialsでの刺激の使用
sharks/posts
パーシャルは、 form_with formhelperを使用して新しい投稿オブジェクトを作成します。 また、Stimulusの3つのコアコンセプトであるコントローラー、ターゲット、およびアクションを利用します。 これらの概念は次のように機能します。
- コントローラは、JavaScriptモジュールで定義され、モジュールのデフォルトオブジェクトとしてエクスポートされるJavaScriptクラスです。 コントローラを介して、
app/javascript/packs/application.js
で定義されている特定のHTML要素とStimulusApplicationインスタンスにアクセスできます。 - ターゲットを使用すると、特定のHTML要素を名前で参照でき、特定のコントローラーに関連付けられます。
- アクションは、DOMイベントがコントローラーによって処理される方法を制御し、特定のコントローラーにも関連付けられます。 これらは、コントローラーに関連付けられたHTML要素、コントローラーで定義されたメソッド、およびDOMイベントリスナーの間に接続を作成します。
パーシャルでは、最初にRailsを使用する場合と同じようにフォームを作成します。 次に、JavaScriptを使用して新しい投稿をページに追加する方法を制御するために、Stimulusコントローラー、アクション、およびターゲットをフォームに追加します。
まず、パーシャルの新しいファイルを作成します。
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
と投稿の入力を求めるプロンプトが追加されています。
さらに、フォームは、Shark
モデルとPost
モデル間の関連付けに付属する収集メソッドを利用するようにスコープが設定されています。 この場合、ユーザーが送信したデータから作成された新しい投稿オブジェクトは、現在表示しているサメに関連付けられた投稿のコレクションに属します。
ここでの目標は、いくつかのStimulusコントローラー、イベント、およびアクションを追加して、投稿データがページに表示される方法を制御することです。 ユーザーは最終的に投稿データを送信し、Stimulusアクションのおかげでページに投稿されたことがわかります。
まず、<div>
要素のposts
というフォームにコントローラーを追加します。
〜/ 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>
必ずクロージングを追加してください
鬼ごっこコントローラを適切にスコープします。
次に、フォーム送信イベントによってトリガーされるアクションをフォームに添付します。 このアクションは、ユーザー入力がページにどのように表示されるかを制御します。 これは、postsStimulusコントローラーで定義するaddPost
メソッドを参照します。
〜/ 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>
これらの変更を行ったら、ファイルを保存して閉じることができます。
これで、sharks/show
ビューテンプレートに追加した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ループを使用して、特定のサメに関連付けられた投稿オブジェクトのコレクション内の各投稿インスタンスを反復処理します。
これで、このパーシャルにいくつかの刺激アクションを追加して、ページ上の投稿の外観を制御できます。 具体的には、賛成票と投稿がページに表示されるかどうかを制御するアクションを追加します
ただし、その前に、プロジェクトにgemを追加して、賛成票の登録に使用する FontAwesomeアイコンを操作できるようにする必要があります。 2番目のターミナルウィンドウを開き、sharkapp
プロジェクトディレクトリに移動します。
Gemfileを開きます。
nano Gemfile
webpacker
gemの下に、次の行を追加して、プロジェクトに font-awesome-railsgemを含めます。
〜/ sharkapp / Gemfile
. . . gem 'webpacker', '~> 4.x' gem 'font-awesome-rails', '~>4.x' . . .
ファイルを保存して閉じます。
次に、gemをインストールします。
bundle install
最後に、アプリケーションのメインスタイルシートapp/assets/stylesheets/application.css
を開きます。
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
オプションを使用するため、投稿の刺激コントローラーと2つのアクションremove
とupvote
を追加しました。 繰り返しになりますが、アクション記述子では、ボタン要素に関連付けられたデフォルトのイベントがクリックであるため、コントローラーとメソッドを定義するだけで済みます。 これらの各ボタンをクリックすると、コントローラーで定義されているそれぞれのremove
およびupvote
メソッドがトリガーされます。
編集が終了したら、ファイルを保存して閉じます。
コントローラの定義に進む前に行う最後の変更は、sharks/all
パーシャルを表示する方法とタイミングを制御するためのデータターゲットとアクションを設定することです。
show
テンプレートを再度開きます。ここで、sharks/all
をレンダリングするための最初の呼び出しが現在定義されています。
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
ボタンをクリックして古い投稿を表示することを選択した場合にのみ、ユーザーに古い投稿を表示してもらいたいと考えています。
したがって、show
というデータターゲットをsharks/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がアプリケーションコンテキストをロードします。このディレクトリにpostsコントローラーを作成します。 このコントローラーには、前のステップで参照した各メソッドが含まれます。
addBody()
、新しい投稿を追加します。showAll()
、古い投稿を表示します。remove()
、現在のビューから投稿を削除します。upvote()
、賛成のアイコンを投稿に添付します。
app/javascript/controllers
ディレクトリに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 { static targets = ["body", "add", "show"] }
このようにターゲットを定義すると、this.target-nameTarget
プロパティを使用してメソッドでターゲットにアクセスできるようになり、最初に一致するターゲット要素が得られます。 したがって、たとえば、targets配列で定義された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>"); } }
このメソッドは、letキーワードを使用してcontent
変数を定義し、ユーザーが投稿フォームに入力した投稿入力文字列と同じ値に設定します。 これは、フォームの<textarea>
要素にアタッチしたbody
データターゲットによって行われます。 this.bodyTarget
を使用してこの要素を照合すると、その要素に関連付けられている valueプロパティを使用して、入力後のユーザーが入力したcontent
の値を設定できます。
次に、このポスト入力を、sharks/posts
パーシャルのフォームビルダーの下の<ul>
要素に追加したadd
ターゲットに追加します。 これは、 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
プロパティを使用して、<div>
要素にsharks/all
パーシャルでアタッチされているshow
ターゲットを一致させます。 デフォルトのスタイル"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>
要素にアタッチしたクラス)を持つ最も近い<li>
要素をターゲットとするpost
変数を作成しています。 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
変数は、クラス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—インデックスビューの変更とアプリケーションのテスト
sharks index
ビューに最後の変更を加えると、アプリケーションをテストする準備が整います。 index
ビューは、 How To Build Ruby on RailsApplicationのステップ4で設定したアプリケーションのルートです。
ファイルを開きます。
nano app/views/sharks/index.html.erb
サメを表示して破壊するために自動生成されたlink_to
ヘルパーの代わりに、button_to
ヘルパーを使用します。 これにより、[でjavascript_include_tag
をjavascript_pack_tag
に変更したときに、手順1で使用しなくなると指定したデフォルトのRailsJavaScriptアセットの代わりに生成されたHTMLコードを操作できます。 X195X]。
ファイル内の既存の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に依存するようになりました。
編集が終了したら、ファイルを保存して閉じます。
これで、アプリケーションをテストする準備が整いました。
まず、データベースの移行を実行します。
rails db:migrate
次に、サーバーを起動します。 ローカルで作業している場合は、次のコマンドを使用してこれを行うことができます。
rails s
開発サーバーで作業している場合は、次のコマンドでアプリケーションを起動できます。
rails s --binding=your_server_ip
ブラウザでアプリケーションのランディングページに移動します。 ローカルで作業している場合、これはlocalhost:3000
になり、サーバーで作業している場合はhttp://your_server_ip:3000
になります。
次のランディングページが表示されます。
Show をクリックすると、このサメの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プロジェクトをセットアップする方法を参照してください。