はじめに
Ruby on RailsのAction Controllerは、Webアプリケーションのリクエストとレスポンスを管理するための強力なツールです。基本的な使い方に慣れてきたら、さらに高度な機能を活用することで、アプリケーションの性能と可読性を向上させることができます。
本記事では、Action Controllerの応用的な使い方を詳しく解説し、日常の開発業務に役立つ実践的なテクニックを紹介します。これらのテクニックをマスターすることで、より洗練された、効率的なRailsアプリケーションを構築できるようになるでしょう。
フィルター
フィルターは、コントローラーのアクションが実行される前や後に特定のコードを実行するために使用されます。フィルターを使用することで、共通のロジックを簡単に管理し、コードの重複を減らすことができます。
フィルターの種類
種類 | 説明 |
---|---|
before_action |
アクションが実行される前に呼び出される |
after_action |
アクションが実行された後に呼び出される |
around_action |
アクションの実行前後にブロックとして呼び出される |
フィルターの定義
フィルターは、コントローラー内で以下のように定義します。
class ApplicationController < ActionController::Base
before_action :set_locale
after_action :log_activity
around_action :wrap_in_transaction
private
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
end
def log_activity
ActivityLog.create(user: current_user, action: action_name)
end
def wrap_in_transaction
ActiveRecord::Base.transaction do
yield
end
end
end
before_action
before_action
は、指定されたアクションが実行される前に実行されるメソッドを定義します。例えば、ユーザーが認証されているかを確認する場合に使用されます。
class ArticlesController < ApplicationController
before_action :authenticate_user!, only: [:edit, :update, :destroy]
def edit
@article = Article.find(params[:id])
end
def update
@article = Article.find(params[:id])
if @article.update(article_params)
redirect_to @article
else
render 'edit'
end
end
def destroy
@article = Article.find(params[:id])
@article.destroy
redirect_to articles_path
end
private
def authenticate_user!
unless user_signed_in?
flash[:alert] = "You need to sign in before continuing."
redirect_to login_path
end
end
end
authenticate_user!
- ユーザーがサインインしているかを確認し、サインインしていない場合はログインページにリダイレクトします。
only
オプション- このフィルターが適用されるアクションを制限します。この例では、
edit
,update
,destroy
アクションの前に実行されます。
- このフィルターが適用されるアクションを制限します。この例では、
after_action
after_action
は、指定されたアクションが実行された後に実行されるメソッドを定義します。例えば、ユーザーの操作ログを記録する場合に使用されます。
class ArticlesController < ApplicationController
after_action :log_activity, only: [:create, :update, :destroy]
def create
@article = Article.new(article_params)
if @article.save
redirect_to @article
else
render 'new'
end
end
def update
@article = Article.find(params[:id])
if @article.update(article_params)
redirect_to @article
else
render 'edit'
end
end
def destroy
@article = Article.find(params[:id])
@article.destroy
redirect_to articles_path
end
private
def log_activity
ActivityLog.create(user: current_user, action: action_name)
end
end
log_activity
- アクションが実行された後に操作ログを記録します。
only
オプション- このフィルターが適用されるアクションを制限します。この例では、
create
,update
,destroy
アクションの後に実行されます。
- このフィルターが適用されるアクションを制限します。この例では、
around_action
around_action
は、アクションの実行前後にブロックとして呼び出されます。例えば、データベースのトランザクションを管理する場合に使用されます。
class ArticlesController < ApplicationController
around_action :wrap_in_transaction, only: [:create, :update, :destroy]
def create
@article = Article.new(article_params)
if @article.save
redirect_to @article
else
render 'new'
end
end
def update
@article = Article.find(params[:id])
if @article.update(article_params)
redirect_to @article
else
render 'edit'
end
end
def destroy
@article = Article.find(params[:id])
@article.destroy
redirect_to articles_path
end
private
def wrap_in_transaction
ActiveRecord::Base.transaction do
yield
end
end
end
wrap_in_transaction
- アクションの実行前後にデータベースのトランザクションを開始し、ブロック内で例外が発生した場合にロールバックします。
only
オプション- このフィルターが適用されるアクションを制限します。この例では、
create
,update
,destroy
アクションの前後に実行されます。
- このフィルターが適用されるアクションを制限します。この例では、
フィルターのオプション
フィルターには、適用範囲を細かく指定するためのオプションがいくつかあります。
オプション | 説明 |
---|---|
only |
特定のアクションに対してフィルターを適用します。 |
except |
指定したアクションを除くすべてのアクションにフィルターを適用します。 |
ストロングパラメーター
ストロングパラメーターは、Ruby on Railsにおけるマスアサインメントの脆弱性を防ぐための機能です。Rails 4から導入され、ActiveModel::ForbiddenAttributesErrorを防ぐために必須となりました。
この機能は、ユーザーからの入力データをモデルに安全に渡すために使用されます。
基本的な使い方
ストロングパラメーターを使用するためには、コントローラー内で許可するパラメーターを明示的に指定します。通常、private
メソッドとして定義されます。
class ArticlesController < ApplicationController
def create
@article = Article.new(article_params)
if @article.save
redirect_to @article
else
render 'new'
end
end
def update
@article = Article.find(params[:id])
if @article.update(article_params)
redirect_to @article
else
render 'edit'
end
end
private
def article_params
params.require(:article).permit(:title, :body)
end
end
params.require(:article)
article
キーを必須とします。パラメーターがハッシュ内に存在しない場合、例外が発生します。
permit(:title, :body)
title
とbody
の2つのパラメーターだけを許可します。これにより、これら以外のパラメーターが無視され、セキュリティが向上します。
ネストされたパラメーター
フォームがネストされたパラメーターを送信する場合、ストロングパラメーターもそれに対応する必要があります。
class ArticlesController < ApplicationController
def create
@article = Article.new(article_params)
if @article.save
redirect_to @article
else
render 'new'
end
end
def update
@article = Article.find(params[:id])
if @article.update(article_params)
redirect_to @article
else
render 'edit'
end
end
private
def article_params
params.require(:article).permit(:title, :body, author_attributes: [:name, :email])
end
end
author_attributes: [:name, :email]
- ネストされた
author
のname
とemail
パラメーターを許可します。この構文により、ネストされた属性も安全に取り扱うことができます。
- ネストされた
動的に許可するパラメーター
場合によっては、条件に応じて許可するパラメーターを動的に変更する必要があります。
class ArticlesController < ApplicationController
def create
@article = Article.new(article_params)
if @article.save
redirect_to @article
else
render 'new'
end
end
def update
@article = Article.find(params[:id])
if @article.update(article_params)
redirect_to @article
else
render 'edit'
end
end
private
def article_params
if current_user.admin?
params.require(:article).permit(:title, :body, :published_at)
else
params.require(:article).permit(:title, :body)
end
end
end
- 条件による許可
- 管理者ユーザーの場合は
published_at
パラメーターを許可し、それ以外のユーザーには許可しません。
- 管理者ユーザーの場合は
配列パラメーターの許可
フォームから送信される配列パラメーターを許可する方法もあります。
class ArticlesController < ApplicationController
def create
@article = Article.new(article_params)
if @article.save
redirect_to @article
else
render 'new'
end
end
def update
@article = Article.find(params[:id])
if @article.update(article_params)
redirect_to @article
else
render 'edit'
end
end
private
def article_params
params.require(:article).permit(:title, :body, category_ids: [])
end
end
category_ids: []
- 空の配列を渡すことで、配列パラメーターを許可します。この場合、
category_ids
パラメーターは整数の配列として受け取られます。
- 空の配列を渡すことで、配列パラメーターを許可します。この場合、
レスポンスフォーマット
RailsのAction Controllerでは、様々な形式でレスポンスを返すことができます。これにより、同じアクションからHTML、JSON、XMLなどの異なるフォーマットのレスポンスを提供することができます。
レスポンスフォーマットの設定
レスポンスフォーマットを設定するために、respond_to
メソッドとformat
オブジェクトを使用します。respond_to
メソッドは、リクエストのフォーマットに応じて異なるレスポンスを生成するためのブロックを受け取ります。
class ArticlesController < ApplicationController
def show
@article = Article.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: @article }
end
end
end
format.html
- リクエストがHTMLフォーマットの場合、
show.html.erb
テンプレートがレンダリングされます。
- リクエストがHTMLフォーマットの場合、
format.json { render json: @article }
- リクエストがJSONフォーマットの場合、
@article
オブジェクトをJSON形式でレンダリングします。
- リクエストがJSONフォーマットの場合、
レスポンスフォーマットの指定方法
リクエストのフォーマットは、URLの拡張子やHTTPヘッダーで指定できます。
URLの拡張子
URLに拡張子を追加することで、レスポンスフォーマットを指定できます。
/articles/1.html
/articles/1.json
HTTPヘッダー
Acceptヘッダーを使用して、クライアントは希望するレスポンスフォーマットを指定できます。
Accept: application/json
カスタムフォーマット
デフォルトのHTMLやJSON以外のフォーマットを使用したい場合、カスタムフォーマットを定義することもできます。
class ArticlesController < ApplicationController
def index
@articles = Article.all
respond_to do |format|
format.html # index.html.erb
format.csv { send_data @articles.to_csv, filename: "articles-#{Date.today}.csv" }
end
end
end
# ArticleモデルにCSV変換メソッドを追加
require 'csv'
class Article < ApplicationRecord
def self.to_csv
attributes = %w{id title body created_at updated_at}
CSV.generate(headers: true) do |csv|
csv << attributes
all.each do |article|
csv << attributes.map{ |attr| article.send(attr) }
end
end
end
end
format.csv { send_data @articles.to_csv, filename: "articles-#{Date.today}.csv" }
@articles
をCSV形式でレンダリングし、ファイルとして送信します。
- Articleモデルの
to_csv
メソッドCSV.generate
メソッドを使用して、記事のデータをCSV形式に変換します。
レスポンスステータスの設定
レスポンスのフォーマットに加えて、HTTPステータスコードを設定することも重要です。
class ArticlesController < ApplicationController
def show
@article = Article.find(params[:id])
respond_to do |format|
format.html
format.json { render json: @article, status: :ok }
end
rescue ActiveRecord::RecordNotFound
respond_to do |format|
format.html { redirect_to articles_path, alert: "Article not found." }
format.json { render json: { error: "Article not found." }, status: :not_found }
end
end
end
status: :ok
- 正常なレスポンスとして
200 OK
ステータスコードを設定します。
- 正常なレスポンスとして
status: :not_found
- レコードが見つからなかった場合、
404 Not Found
ステータスコードを設定します。
- レコードが見つからなかった場合、
レスポンスヘッダーの設定
カスタムヘッダーをレスポンスに追加することもできます。
class ArticlesController < ApplicationController
def show
@article = Article.find(params[:id])
respond_to do |format|
format.html
format.json { render json: @article, status: :ok }
end
response.headers['Custom-Header'] = 'This is a custom header'
end
end
response.headers['Custom-Header'] = 'This is a custom header'
- レスポンスにカスタムヘッダーを追加します。
レスポンスフォーマットのデフォルト設定
コントローラー全体にデフォルトのレスポンスフォーマットを設定することも可能です。
class ApplicationController < ActionController::Base
before_action :set_default_response_format
private
def set_default_response_format
request.format = :json
end
end
request.format = :json
- リクエストフォーマットをJSONに設定します。これにより、明示的に指定されない限り、すべてのアクションがJSONフォーマットでレスポンスを返します。
カスタムエラーハンドリング
アプリケーションが予期しないエラーや特定の条件に基づくエラーを適切に処理し、ユーザーに適切なフィードバックを提供するためにカスタムエラーハンドリングを使用します。
カスタムエラーハンドリングを実装することで、アプリケーションの信頼性とユーザーエクスペリエンスを向上させることができます。
基本
Action Controllerでは、rescue_from
メソッドを使用してカスタムエラーハンドリングを実装します。rescue_from
メソッドは、特定の例外が発生したときに実行されるメソッドを指定することができます。
class ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound, with: :record_not_found
private
def record_not_found
render file: 'public/404.html', status: :not_found
end
end
rescue_from ActiveRecord::RecordNotFound, with: :record_not_found
- ActiveRecord::RecordNotFound例外が発生したときに、
record_not_found
メソッドが呼び出されます。
- ActiveRecord::RecordNotFound例外が発生したときに、
render file: 'public/404.html', status: :not_found
record_not_found
メソッドでは、404エラーページをレンダリングし、ステータスコードを404に設定します。
rescue_from
はブロックを渡すこともできます。
class ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound do
render file: 'public/404.html', status: :not_found
end
end
特定のコントローラーでのカスタムエラーハンドリング
カスタムエラーハンドリングは、特定のコントローラー内でも定義できます。これにより、コントローラーごとに異なるエラーハンドリングを実装することが可能です。
class ArticlesController < ApplicationController
rescue_from ActiveRecord::RecordNotFound, with: :article_not_found
def show
@article = Article.find(params[:id])
end
private
def article_not_found
redirect_to articles_path, alert: 'Article not found.'
end
end
rescue_from ActiveRecord::RecordNotFound, with: :article_not_found
- ArticlesController内でActiveRecord::RecordNotFound例外が発生したときに、
article_not_found
メソッドが呼び出されます。
- ArticlesController内でActiveRecord::RecordNotFound例外が発生したときに、
redirect_to articles_path, alert: 'Article not found.'
article_not_found
メソッドでは、記事が見つからなかった場合に記事一覧ページにリダイレクトし、アラートメッセージを表示します。
カスタムエラークラスの作成とハンドリング
アプリケーション固有のカスタムエラークラスを作成し、それに対するハンドリングを実装することもできます。
class MyCustomError < StandardError; end
class ApplicationController < ActionController::Base
rescue_from MyCustomError, with: :handle_custom_error
private
def handle_custom_error
render file: 'public/500.html', status: :internal_server_error, layout: false
end
end
class ArticlesController < ApplicationController
def show
raise MyCustomError, "Something went wrong!"
end
end
class MyCustomError < StandardError; end
- アプリケーション固有のカスタムエラークラスMyCustomErrorを定義します。
rescue_from MyCustomError, with: :handle_custom_error
- MyCustomErrorが発生したときに、
handle_custom_error
メソッドが呼び出されます。
- MyCustomErrorが発生したときに、
render file: 'public/500.html', status: :internal_server_error, layout: false
handle_custom_error
メソッドでは、500エラーページをレンダリングし、ステータスコードを500に設定します。
複数の例外をハンドリング
複数の例外を一つのメソッドでハンドリングすることも可能です。
class ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound, ActiveRecord::RecordInvalid, with: :handle_record_error
private
def handle_record_error(exception)
case exception
when ActiveRecord::RecordNotFound
render file: 'public/404.html', status: :not_found
when ActiveRecord::RecordInvalid
render file: 'public/422.html', status: :unprocessable_entity
else
render file: 'public/500.html', status: :internal_server_error
end
end
end
rescue_from ActiveRecord::RecordNotFound, ActiveRecord::RecordInvalid, with: :handle_record_error
- 複数の例外が発生したときに、
handle_record_error
メソッドが呼び出されます。
- 複数の例外が発生したときに、
case
文- 例外の種類に応じて適切なエラーページをレンダリングし、対応するステータスコードを設定します。
ロギングと通知
エラーハンドリングと同時に、エラーのロギングや通知を行うことも重要です。
class ApplicationController < ActionController::Base
rescue_from StandardError, with: :handle_standard_error
private
def handle_standard_error(exception)
# エラーをログに記録
logger.error "#{exception.class.name} (#{exception.message}):"
logger.error exception.backtrace.join("\n")
# エラー通知(例: Airbrake, Sentry)
# Airbrake.notify(exception)
render file: 'public/500.html', status: :internal_server_error, layout: false
end
end
logger.error
- エラー情報をログに記録します。
Airbrake.notify(exception)
- エラー通知サービス(例: AirbrakeやSentry)を使用して、エラーを通知します。
render file: 'public/500.html', status: :internal_server_error, layout: false
- 500エラーページをレンダリングし、ステータスコードを500に設定します。
セッションの管理
Action Controllerにおけるセッション管理は、ユーザーの状態を保持し、異なるリクエスト間で情報を共有するための重要な機能です。主にセッションを使用して、ログイン状態の維持やユーザーの設定の保存、一時的なデータの保持などが行われます。
有効化と設定
Railsでは、デフォルトでセッションが有効になっており、セッションストアとしてCookieを使用します。以下は、セッションを有効にする方法と、設定をカスタマイズする例です。
config/application.rb または config/initializers/session_store.rb
Rails.application.config.session_store :cookie_store, key: '_myapp_session'
# その他のオプション
Rails.application.config.session_store :cookie_store, key: '_myapp_session', expire_after: 1.hour, secure: true
:cookie_store
- セッションデータをブラウザのCookieに保存します。
key: '_myapp_session'
- クライアントサイドに保存されるCookieの名前を指定します。
expire_after: 1.hour
- セッションの有効期限を指定します。
secure: true
- HTTPSでのみCookieを送信するようにします。
データの保存と取得
セッションにデータを保存するには、session
ヘルパーメソッドを使用します。これにより、ハッシュの形式でデータを保存および取得できます。
class SessionsController < ApplicationController
def create
user = User.find_by(email: params[:email])
if user&.authenticate(params[:password])
session[:user_id] = user.id
redirect_to root_url, notice: 'Logged in successfully!'
else
flash.now[:alert] = 'Invalid email or password'
render :new
end
end
def destroy
session.delete(:user_id)
redirect_to root_url, notice: 'Logged out successfully!'
end
end
session[:user_id] = user.id
- ログイン成功時に、セッションにユーザーIDを保存します。
session.delete(:user_id)
- ログアウト時に、セッションからユーザーIDを削除します。
セキュリティー
セッション管理はセキュリティーに関して非常に重要です。Railsでは以下のようなセキュリティー対策が自動的に実装されています。
項目 | 説明 |
---|---|
CSRF対策 | RailsではCSRFトークンを自動的に生成し、フォーム送信時に検証します。 |
Cookieの暗号化 | セッションCookieは暗号化され、改ざんを防ぎます。 |
セッションのタイムアウト管理 | expire_after を設定することで、セッションの有効期限を管理します。 |
カスタムセッションストア
必要に応じて、デフォルトのCookieストア以外のセッションストアを使用することもできます。例えば、データベースやキャッシュストアをセッションストアとして使用することができます。
config/initializers/session_store.rb
Rails.application.config.session_store :active_record_store, key: '_myapp_session'
ヘルパーメソッドの使用
Action Controllerには、コントローラー内で利用可能な便利なヘルパーメソッドが多数用意されています。これらのヘルパーメソッドは、ビューで利用可能なヘルパーメソッドとは異なり、主にコントローラー内での操作を簡略化し、共通の機能を提供するために使用されます。
パス関連のヘルパーメソッド
Railsでは、ルーティングに基づいてパスを生成するための便利なヘルパーメソッドが提供されています。これらのメソッドを使用することで、リダイレクトやリンク生成などを簡単に行うことができます。
redirect_to
リダイレクトを行う際に使用します。指定したパスにリダイレクトさせることができます。
class SessionsController < ApplicationController
def create
if login_successful?
redirect_to root_path
else
redirect_to login_path, alert: 'Invalid credentials'
end
end
end
render
ビューをレンダリングする際に使用します。指定したビューテンプレートやパーシャルをレンダリングします。
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
render :show # app/views/users/show.html.erb をレンダリング
end
end
パスヘルパー
ルーティングで定義された各ルートに対して、パスヘルパーが自動的に生成されます。これにより、ルートに対応するパスを簡単に取得できます。
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
redirect_to user_path(@user) # users#show のパスを取得してリダイレクト
end
end
パラメーターの操作と取得
リクエストのパラメーターにアクセスし、操作するためのヘルパーメソッドも提供されています。
params
リクエストパラメーターにアクセスするためのヘルパーメソッドです。コントローラー内で受け取ったパラメーターを取得できます。
class UsersController < ApplicationController
def update
@user = User.find(params[:id])
if @user.update(user_params)
redirect_to @user
else
render :edit
end
end
private
def user_params
params.require(:user).permit(:name, :email)
end
end
request
リクエストに関する情報にアクセスするためのオブジェクトです。ヘッダーやHTTPメソッドなどの情報を取得できます。
class UsersController < ApplicationController
def index
if request.xhr? # AJAXリクエストかどうかを判定
render json: User.all
else
@users = User.all
end
end
end
このオブジェクトをを通じて参照できる主なリクエストに関連する情報は以下の通りです。
HTTPメソッド関連の情報
項目 | コード | 説明 |
---|---|---|
HTTPメソッド | request.method |
現在のリクエストのHTTPメソッドを取得します(GET, POST, PUT, DELETEなど)。 |
HTTPバージョン | request.env['HTTP_VERSION'] |
リクエストのHTTPバージョンを取得します。 |
リクエストURI | request.original_url |
リクエストされた完全なURIを取得します。 |
パス | request.path |
リクエストされたパス部分を取得します。 |
クエリパラメーター | request.query_parameters |
クエリ文字列(GETパラメーター)のパラメーターを取得します。 |
ヘッダー関連の情報
項目 | コード | 説明 |
---|---|---|
HTTPヘッダー | request.headers |
すべてのHTTPヘッダーが含まれるハッシュを取得します。個別のヘッダーは、request.headers['Header-Name'] のようにしてアクセスします。 |
リファラー | request.referer |
リクエストのリファラー(前のページのURL)を取得します。 |
ユーザーエージェント | request.user_agent |
リクエストを送信したクライアントのユーザーエージェント情報を取得します。 |
コンテントタイプ | request.content_type |
リクエストのコンテントタイプ(例:application/json)を取得します。 |
セキュリティ関連の情報
項目 | コード | 説明 |
---|---|---|
IPアドレス | request.remote_ip |
リクエストを送信したクライアントのIPアドレスを取得します。 |
SSL関連情報 | request.ssl? /request.protocol |
リクエストがSSL経由で送信されたかどうかや、プロトコル(httpまたはhttps)を取得します。 |
その他の情報
項目 | コード | 説明 |
---|---|---|
セッション | request.session |
リクエストに関連付けられたセッション情報を取得します。 |
クッキー | request.cookies |
リクエストに含まれるクッキー情報を取得します。 |
レスポンスの操作
コントローラーでのレスポンスの操作に役立つヘルパーメソッドもあります。
head
HTTPヘッダーとステータスコードを指定して、空のレスポンスを返します。
class UsersController < ApplicationController
def destroy
@user = User.find(params[:id])
@user.destroy
head :no_content # HTTPステータスコード204を返す
end
end
response
レスポンスに関連する情報にアクセスするためのオブジェクトです。レスポンスのヘッダーやボディなどを操作できます。
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
respond_to do |format|
format.html # app/views/users/show.html.erb をレンダリング
format.json { render json: @user }
end
end
end
セッションの操作
セッションに関連する操作もヘルパーメソッドを通じて行うことができます。
session
セッションデータにアクセスし、操作するためのヘルパーメソッドです。セッションにデータを保存したり、取得したりできます。
class SessionsController < ApplicationController
def create
user = User.find_by(email: params[:email])
if user&.authenticate(params[:password])
session[:user_id] = user.id
redirect_to root_path
else
redirect_to login_path, alert: 'Invalid credentials'
end
end
def destroy
session.delete(:user_id)
redirect_to root_path
end
end
キャッシュの設定
Action Controllerにおけるキャッシュの使用は、パフォーマンスの向上やリクエストの処理時間の短縮に役立ちます。
キャッシュを使用することで、頻繁に更新されないデータや計算結果をメモリやストレージに保存し、後続のリクエストで再利用することができます。これにより、データベースや外部サービスへのアクセス回数を減らし、アプリケーションのレスポンス時間を改善することができます。
フラグメントキャッシュ
フラグメントキャッシュは、ビューの一部をキャッシュするための方法です。コントローラー内で直接キャッシュを定義することができます。
class UsersController < ApplicationController
def index
@users = Rails.cache.fetch('all_users', expires_in: 1.hour) do
User.all
end
end
end
Rails.cache.fetch
- 指定したキーでキャッシュを取得します。キャッシュが存在しない場合は、ブロック内の処理(例えば、
User.all
)を実行して結果をキャッシュします。
- 指定したキーでキャッシュを取得します。キャッシュが存在しない場合は、ブロック内の処理(例えば、
expires_in: 1.hour
- キャッシュの有効期限を設定します。ここでは1時間としていますが、必要に応じて変更することができます。
app/views/users/index.html.erb
<% cache 'all_users' do %>
<% @users.each do |user| %>
<div>
<%= user.name %>
</div>
<% end %>
<% end %>
<% cache 'all_users' do %>
all_users
というキーで指定されたフラグメントをキャッシュします。このブロック内のコードはキャッシュされ、再度同じリクエストが来た場合にはキャッシュから読み込まれます。
ページキャッシュ
ページキャッシュは、整形済みのHTMLページ全体をキャッシュする方法です。これにより、リクエストが発生した時点でキャッシュされたHTMLファイルを直接返すことができます。
class ProductsController < ApplicationController
before_action :authenticate_user!, only: [:admin_dashboard]
caches_page :index, :show
def index
@products = Product.all
end
def show
@product = Product.find(params[:id])
end
def admin_dashboard
@orders = Order.all
end
end
caches_page :index, :show
index
とshow
アクションのページをキャッシュします。これにより、同じURLへのリクエストに対して、キャッシュされたHTMLファイルが返されます。
ページキャッシュは通常、public
ディレクトリ以下にHTMLファイルとして保存されます。これにより、Webサーバーがキャッシュを直接提供することができます。
モデルキャッシュ
Active Recordのクエリ結果やモデルインスタンスそのものをキャッシュする方法もあります。これにより、データベースからのクエリを減らし、処理時間を短縮することができます。
class Product < ApplicationRecord
def self.cached_products
Rails.cache.fetch('cached_products', expires_in: 1.hour) do
Product.all.to_a
end
end
end
Rails.cache.fetch('cached_products', expires_in: 1.hour) do ... end
cached_products
というキーでキャッシュされたクエリ結果を取得します。有効期限は1時間としています。
キャッシュのクリア
キャッシュを定期的にクリアすることが重要です。特にデータが頻繁に更新される場合、古いキャッシュが使われることを防ぐために、キャッシュのクリアを行う必要があります。
class UsersController < ApplicationController
def create
@user = User.new(user_params)
if @user.save
Rails.cache.delete('all_users') # キャッシュの削除
redirect_to @user
else
render :new
end
end
end
Rails.cache.delete('all_users')
all_users
というキーで保存されたキャッシュを削除します。新しいユーザーが作成された場合など、データが更新された際にキャッシュをクリアすることが推奨されます。
まとめ
Action Controllerの応用的な使い方を理解し、実践することで、Railsアプリケーションの開発が一段とスムーズになります。
フィルターの活用、強力なパラメーターの使用、レスポンスフォーマットのカスタマイズ、カスタムエラーハンドリング、セッション管理、ヘルパーメソッドの定義、キャッシュの設定など、これらのテクニックは、より柔軟でメンテナブルなコードを書くための強力なツールです。
これからのプロジェクトでこれらのテクニックを取り入れ、Railsの力を最大限に引き出してみてください。