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アソシエーションを作成します。投稿は特定のサメに属し、各サメは複数の投稿を持つことができます。
開始するには、に移動します sharkapp
前提条件でRailsプロジェクト用に作成したディレクトリ:
- 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
The belongs_to
アソシエーションは、宣言モデルの単一インスタンスが名前付きモデルの単一インスタンスに属するモデル間の関係を設定します。 私たちのアプリケーションの場合、これは単一の投稿が単一のサメに属することを意味します。
Railsはすでに設定していますが belongs_to
私たちの協会 Post
モデル、指定する必要があります has_many
私たちの協会 Shark
その関係が適切に機能するためにもモデルを作成します。
追加するには has_many
への関連付け Shark
モデル、オープン app/models/shark.rb
を使用して nano
またはお気に入りの編集者:
- nano app/models/shark.rb
次の行をファイルに追加して、サメと投稿の関係を確立します。
class Shark < ApplicationRecord
has_many :posts
validates :name, presence: true, uniqueness: true
validates :facts, presence: true
end
ここで検討する価値のあることの1つは、特定のサメが削除されると投稿がどうなるかということです。 削除されたサメに関連付けられた投稿をデータベースに残したくない場合があります。 特定のサメが削除されたときに、そのサメに関連付けられている投稿が確実に削除されるようにするために、 dependent
関連付けのオプション。
次のコードをファイルに追加して、 destroy
特定のサメに対するアクションは、関連する投稿を削除します。
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
現在、ファイルは次のようになっています。
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
. ファイル内のコードを次のように更新します。
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
クラス自体、および2つ private
メソッド: get_shark
、特定のサメを参照できるようになり、 post_params
、paramsメソッドを介してユーザーが送信した情報にアクセスできます。
次のコードをファイルに追加します。
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
メソッド:
. . .
def create
@post = @shark.posts.create(post_params)
end
def destroy
@post = @shark.posts.find(params[:id])
@post.destroy
end
. . .
これらのメソッドは関連付けます @post
特定のインスタンス @shark
インスタンスを作成し、作成時に使用可能になったコレクションメソッドを使用します。 has_many
サメとポストの間の関連付け。 などの方法 find
と create
特定のサメに関連する投稿のコレクションをターゲットにできます。
完成したファイルは次のようになります。
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
現在、ファイルは次のようになっています。
<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
:
. . .
<p>
<strong>Facts:</strong>
<%= @shark.facts %>
</p>
<h2>Posts</h2>
<%= render 'sharks/posts' %>
. . .
これにより、新しい投稿オブジェクトのフォームビルダーでパーシャルがレンダリングされます。
次に、以下 Edit
と Back
リンクには、ページ上の古い投稿の表示を制御するセクションを追加します。 次の行をファイルに追加して、呼び出された部分をレンダリングします sharks/all
:
<%= 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をインストールすることから始めましょう。 まず、パッケージリストを更新します。
- 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
あなたのプロジェクトへの宝石。
プロジェクトのGemfileを開きます。これには、プロジェクトのgem依存関係が一覧表示されています。
- nano 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 window
と document
オブジェクトと <html>
要素はレンダリング間で持続します。 これは、ページの読み込み時間が遅くなる主な原因の1つであるCSSおよびJavaScriptリソースの再読み込みに対処します。
GemfileではデフォルトでTurbolinksを取得しますが、追加する必要があります webpacker
Stimulusをインストールして使用できるようにするためのgem。 下 turbolinks
宝石、追加 webpacker
:
. . .
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5'
gem 'webpacker', '~> 4.x'
. . .
終了したら、ファイルを保存して閉じます。
次に、gemをプロジェクトのバンドルに追加します。 bundle
指図:
- bundle
これにより、新しい Gemfile.lock
file —プロジェクトのgemとバージョンの決定的な記録。
次に、次のバンドルのコンテキストでgemをインストールします bundle exec
指図:
- bundle exec rails webpacker:install
インストールが完了したら、アプリケーションのコンテンツセキュリティファイルを少し調整する必要があります。 これは、コンテンツセキュリティポリシー(CSP)制限付き環境であるRails 5.2+を使用しているためです。つまり、アプリケーションで許可されるスクリプトは、信頼できるソースからのもののみである必要があります。
開ける config/initializers/content_security_policy.rb
、これは、Railsがアプリケーション全体のセキュリティポリシーを定義するために提供するデフォルトのファイルです。
- nano config/initializers/content_security_policy.rb
ファイルの最後に次の行を追加して、許可します webpack-dev-server
—アプリケーションのwebpackバンドルを提供するサーバー—許可されたオリジンとして:
. . .
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をインストールできるようになります。
- 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]
└─ sti[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
:
. . .
<%= 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
最初、ファイルは次のようになります。
. . .
console.log('Hello World from Webpacker')
import "controllers"
そこにあるボイラープレートコードを削除し、次のコードを追加してStimulusコントローラーファイルをロードし、アプリケーションインスタンスを起動します。
. . .
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/posts
と sharks/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コントローラー、アクション、およびターゲットをフォームに追加します。
まず、パーシャルの新しいファイルを作成します。
- nano app/views/sharks/_posts.html.erb
ファイル内に次のコードを追加して、を使用して新しい投稿オブジェクトを作成します form_with
ヘルパー:
<%= 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アクションのおかげでページに投稿されたことがわかります。
まず、コントローラーをというフォームに追加します posts
で <div>
エレメント:
<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コントローラー:
<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>
エレメント:
<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>
:
. . .
<% end %>
<ul data-target="posts.add">
</ul>
</div>
と同じように body
ターゲット、ターゲット記述子には、コントローラーの名前とターゲットの両方が含まれます—この場合、 add
.
完成したパーシャルは次のようになります。
<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/
ディレクトリ:
- nano 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をプロジェクトに含めます。
. . .
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のスタイルをプロジェクトに含めます。
. . .
*
*= 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
:
<% 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つのアクションを追加しました。 remove
と upvote
. 繰り返しになりますが、アクション記述子では、ボタン要素に関連付けられたデフォルトのイベントがクリックであるため、コントローラーとメソッドを定義するだけで済みます。 これらの各ボタンをクリックすると、それぞれがトリガーされます remove
と upvote
コントローラで定義されたメソッド。
編集が終了したら、ファイルを保存して閉じます。
コントローラの定義に進む前に行う最後の変更は、データターゲットとアクションを設定して、いつどのように sharks/all
部分的に表示されます。
を開きます show
テンプレートをもう一度、レンダリングするための最初の呼び出し sharks/all
現在定義されています:
- nano app/views/sharks/show.html.erb
ファイルの下部に、 <div>
現在このように見える要素:
. . .
<div>
<%= render 'sharks/all' %>
</div>
まず、これにコントローラーを追加します <div>
アクションとターゲットをスコープする要素:
. . .
<div data-controller="posts">
<%= render 'sharks/all' %>
</div>
次に、ページ上のパーシャルの外観を制御するボタンを追加します。 このボタンはトリガーします showAll
投稿コントローラーのメソッド。
下にボタンを追加します <div>
要素以上 render
声明:
. . .
<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
ボタンの下および部分的なレンダリングステートメントの上にある定義:
. . .
<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
テンプレートは次のようになります。
<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
クラス:
import { Controller } from "stimulus"
export default class extends Controller {
}
次に、次のターゲット定義をファイルに追加します。
. . .
export default class extends Controller {
static targets = ["body", "add", "show"]
}
このようにターゲットを定義すると、メソッドでターゲットにアクセスできるようになります。 this.target-nameTarget
プロパティ。これにより、最初に一致するターゲット要素が得られます。 したがって、たとえば、 body
ターゲット配列で定義されたデータターゲット、 this.bodyTarget
. このプロパティを使用すると、入力値やcssスタイルなどを操作できます。
次に、次のように定義できます。 addBody
ページ上の新しい投稿の外観を制御するメソッド。 このメソッドを定義するには、ターゲット定義の下に次のコードを追加します。
. . .
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
ページ上の古い投稿の外観を制御するメソッド:
. . .
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
特定の投稿へのアイコン。
このメソッドを定義するには、次のコードを追加します。
. . .
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
方法:
. . .
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"
ページ上の投稿を非表示にします。
完成したコントローラーファイルは次のようになります。
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で設定したアプリケーションのルートです。
ファイルを開きます。
- nano app/views/sharks/index.html.erb
の代わりに link_to
サメを表示して破壊するために自動生成されたヘルパーを使用します button_to
ヘルパー。 これにより、変更時に手順1で使用しなくなると指定したデフォルトのRails JavaScriptアセットの代わりに、生成されたHTMLコードを操作できるようになります。 javascript_include_tag
に javascript_pack_tag
の app/views/layouts/application.html.erb
.
既存のものを交換してください link_to
次のファイル内のヘルパー button_to
ヘルパー:
. . .
<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
このサメのビュー。 ここに、投稿に記入するためのフォームが表示されます。
投稿フォームに「これらのサメは怖いです!」と入力します。
投稿の作成をクリックします。 このページに新しい投稿が表示されます。

必要に応じて、別の新しい投稿を追加できます。 今回は、「これらのサメは映画で誤って表現されることが多い」と入力し、投稿の作成をクリックします。
古い投稿を表示機能の機能をテストするには、このページを離れる必要があります。これは、現在、グレートホワイトには、追加したばかりの投稿よりも古い投稿がないためです。
戻るをクリックしてメインページに移動し、表示をクリックしてグレートホワイトのランディングページに戻ります。
古い投稿を表示をクリックすると、作成した投稿が表示されます。
[Upvote Post] ボタンをクリックして、投稿に賛成票を投じることができます。
同様に、 [投稿を削除]をクリックすると、投稿が非表示になります。
これで、Stimulusを使用してネストされた投稿リソースを個々のサメページに表示する方法を制御するRailsアプリケーションが機能していることを確認しました。 これは、Stimulusを使用した将来の開発と実験の出発点として使用できます。
結論
Stimulusは、 rails-ujs 、 JQuery 、およびReactやVueなどのフレームワークを操作するための可能な代替手段を表しています。
はじめに説明したように、Stimulusは、サーバーによって生成されたHTMLを直接操作する必要がある場合に最も効果的です。 軽量で、コード、特にHTMLを可能な限り自明にすることを目的としています。 クライアント側で状態を管理する必要がない場合は、Stimulusが適しています。
Stimulusを統合せずにネストされたリソースを作成する方法に興味がある場合は、 RubyonRailsアプリケーションのネストされたリソースを作成する方法を参照してください。
ReactをRailsアプリケーションと統合する方法の詳細については、ReactFrontendを使用してRubyonRailsプロジェクトをセットアップする方法を参照してください。