Railsで非同期リクエストを使いこなそう!初心者でもわかるTurbo・fetch APIとコントローラ設計の基本
生徒
「Railsで、ボタンを押したときだけ部分的にページを更新する方法ってありますか?全部の画面を再読み込みしたくないです。」
先生
「その場合は非同期リクエストが便利ですよ。Turboやfetch APIを使えば、ページ全体をリロードせずに動きのあるアプリが作れます。」
生徒
「非同期って難しそうですね……」
先生
「大丈夫です!Railsでは仕組みが整っているので、初心者でも扱いやすいんですよ。順番に解説していきましょう!」
1. 非同期リクエストとは?
非同期リクエストとは、ページ全体を更新するのではなく、一部分だけをサーバーと通信して書き換える技術のことです。英語ではAJAX(エージャックス)とも呼ばれます。
例えば、「いいねボタンを押したときに、その部分だけカウントが増える」といった動作が可能になります。これにより、ユーザー体験(UX)が大きく向上します。
2. Rails 7からのTurboとは?
Turboは、Rails 7で導入された標準の非同期通信ツールです。JavaScriptを書かなくても、HTMLだけで非同期リクエストを実現できるのが特徴です。
たとえば、以下のようにフォームにdata-turbo-frameを指定するだけで、自動で部分的な更新が可能になります。
<turbo-frame id="comment_form">
<%= form_with model: @comment do |f| %>
<%= f.text_area :content %>
<%= f.submit "投稿" %>
<% end %>
</turbo-frame>
これだけで、フォームを送信してもページ全体をリロードせずに、新しいコメントだけが反映されます。
3. Turboを使うときのコントローラ設計
Turboを使った場合、通常のHTMLとTurbo用のレスポンスを切り分けることがポイントです。
def create
@comment = Comment.new(comment_params)
if @comment.save
respond_to do |format|
format.turbo_stream
format.html { redirect_to post_path(@comment.post) }
end
else
render :new
end
end
format.turbo_streamとすることで、Railsは自動でcreate.turbo_stream.erbというテンプレートを探して表示してくれます。
4. fetch APIとは?JavaScriptで非同期通信する方法
fetch APIは、ブラウザに標準搭載されているJavaScriptの機能で、手動で非同期リクエストを送ることができます。
Turboではできない複雑な動作をしたいときや、APIと連携する場面で活躍します。
<button id="like-btn">いいね!</button>
<script>
document.getElementById("like-btn").addEventListener("click", () => {
fetch("/likes", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRF-Token": document.querySelector("meta[name='csrf-token']").content
},
body: JSON.stringify({ post_id: 1 })
})
.then(response => response.json())
.then(data => {
alert(`現在のいいね数: ${data.count}`);
});
});
</script>
5. fetch API用のRailsコントローラ設計
fetch APIで通信する場合、Rails側のコントローラではrender json:を使ってJSON形式で返すようにします。
def create
like = Like.create(post_id: params[:post_id])
render json: { count: Like.where(post_id: params[:post_id]).count }
end
これで、JavaScript側にデータが返され、動的に画面に反映させることができます。
6. Turboとfetch APIの使い分けポイント
- Turbo:フォームや部分更新がシンプルなとき。JavaScript不要。
- fetch API:細かい動作やアニメーション、API連携が必要なとき。
どちらも非同期通信を実現する手段ですが、用途に応じて適切に選ぶことが大切です。
7. 非同期対応でRailsアプリはもっと快適に
非同期通信を取り入れることで、Railsアプリケーションはページの切り替えが少なくなり、動きのある快適な操作感を提供できます。
Turboやfetch APIを理解して使いこなすことで、今までよりもぐっと使いやすいアプリを作れるようになります。コントローラ設計も、レスポンス形式を意識するだけなので初心者にも優しい仕組みです。
これをきっかけに、あなたのRailsアプリにもインタラクティブな非同期機能を取り入れてみましょう!
まとめ
これまでに学んできたRailsにおける非同期リクエストの仕組み、Turboやfetch APIの活用方法、そしてそれらを支えるコントローラ設計について、重要なポイントを振り返ってみましょう。非同期通信は、現代のWebアプリケーション開発において、ユーザーにストレスを与えないスムーズな操作性(UX)を提供するために欠かせない技術です。
非同期通信のメリットとRailsの親和性
ページ全体をリロードする「同期通信」とは異なり、「非同期通信」は必要なデータだけを背後でやり取りします。Rails 7からはHotwire(Turbo/Stimulus)が標準搭載されたことで、複雑なJavaScriptを大量に記述しなくても、Railsらしい直感的なコードで高度な非同期処理が実装できるようになりました。
特に、データベースの情報を更新しつつ、その結果を即座に画面の一部へ反映させる処理は、RailsのMVCモデルと非常に相性が良いです。ここでは、具体的なデータベース操作とSQL、そしてRubyコードを交えて、一連の流れを詳しく見ていきましょう。
データベース操作とコントローラでの実装例
例えば、記事に対する「いいね(Like)」機能を実装する場合を考えます。まずは現在のデータベースの状態を確認しましょう。
id | user_id | post_id | created_at
---+---------+---------+--------------------
1 | 10 | 101 | 2026-01-25 10:00:00
2 | 11 | 101 | 2026-01-25 10:05:00
3 | 12 | 102 | 2026-01-25 10:10:00
4 | 13 | 101 | 2026-01-25 10:15:00
ここで、新しい「いいね」が追加された際のRailsコントローラの動きをSQLと共に追ってみます。Turboを利用する場合、RailsはHTMLの断片(Turbo Stream)を返却します。
# app/controllers/likes_controller.rb
class LikesController < ApplicationController
def create
@post = Post.find(params[:post_id])
@like = @post.likes.build(user_id: current_user.id)
if @like.save
respond_to do |format|
# Turbo用のレスポンス
format.turbo_stream
# 非同期非対応ブラウザ用のフォールバック
format.html { redirect_to @post }
end
end
end
end
このとき、バックエンドでは以下のようなSQLが発行され、データベースが更新されます。
INSERT INTO likes (user_id, post_id, created_at, updated_at)
VALUES (14, 101, '2026-01-30 17:00:00', '2026-01-30 17:00:00');
SELECT COUNT(*)
FROM likes
WHERE post_id = 101;
実行後のデータベースの状態は以下のようになります。
id | user_id | post_id | created_at
---+---------+---------+--------------------
1 | 10 | 101 | 2026-01-25 10:00:00
2 | 11 | 101 | 2026-01-25 10:05:00
3 | 12 | 102 | 2026-01-25 10:10:00
4 | 13 | 101 | 2026-01-25 10:15:00
5 | 14 | 101 | 2026-01-30 17:00:00
fetch APIを活用した柔軟なデータ取得
一方で、JavaScript側でより緻密な制御を行いたい場合は、fetch APIを利用してJSONデータを取得します。例えば、特定のユーザー情報を動的に取得して表示するようなケースです。
# app/controllers/users_controller.rb
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
render json: {
id: @user.id,
name: @user.name,
status: "Active"
}
end
end
JavaScript側での呼び出し例:
async function fetchUserInfo(userId) {
const response = await fetch(`/users/${userId}`, {
method: 'GET',
headers: {
'Accept': 'application/json'
}
});
const data = await response.json();
console.log("取得したユーザー:", data.name);
}
適切な技術選定のために
Rails開発において、非同期リクエストの実装手段を選ぶ基準はシンプルです。
- Turbo Drive / Turbo Frames: ページ遷移を高速化したい、あるいは特定のHTML要素を差し替えたい。
- Turbo Streams: フォーム送信後に複数の箇所を同時に更新したい、あるいはリアルタイムな通知を実現したい。
- fetch API (with Stimulus): Railsの枠組みを超えた複雑なUI操作や、外部APIとの通信、JSONデータを元にしたグラフ描画などを行いたい。
これらのツールを組み合わせることで、開発効率を維持したまま、モダンなシングルページアプリケーション(SPA)に近い体験をユーザーに提供することが可能になります。まずはTurboから触れてみて、必要に応じてfetch APIを導入していくというステップが、Rails初心者にとっては最もスムーズな習得への近道と言えるでしょう。
生徒
「先生、まとめを読んで非同期リクエストの使い分けがかなり明確になりました!基本的にはTurboを使って、HTMLをそのままやり取りするのがRails流なんですね。」
先生
「その通りです。Rails 7からは『JavaScriptをなるべく書かない』という方向性が強まっています。Turbo Framesを使えば、特定の範囲だけを切り取って更新できるので、コードがとてもスッキリしますよ。」
生徒
「でも、さっきのfetch APIの例みたいにJSONを返してJSで処理する場合も、やっぱり現場では使われますか?」
先生
「もちろんです。例えば、地図アプリでピンの情報を動的に変えたり、複雑なチャートを表示したりするときはJSONの方が扱いやすいんです。大切なのは、何でもかんでもJSでやろうとせず、Railsが用意してくれた強力なTurbo機能をまずは信じて使い倒すことですね。」
生徒
「なるほど!まずはTurboで実装してみて、どうしても表現が足りない時にfetch APIやStimulusを検討する、という優先順位でやってみます!」
先生
「素晴らしい心がけですね。Railsのコントローラ側で format.turbo_stream を使う感覚に慣れてくると、Webアプリ作りがもっと楽しくなりますよ。ぜひ自分のプロジェクトでも、小さな『いいねボタン』から非同期化に挑戦してみてください。」