ActiveSupport::Cache

RubyRailsキャッシュライブラリWeb開発バックエンドORM

GitHub概要

rails/rails

Ruby on Rails

スター57,276
ウォッチ2,311
フォーク21,912
作成日:2008年4月11日
言語:Ruby
ライセンス:MIT License

トピックス

activejobactiverecordframeworkhtmlmvcrailsruby

スター履歴

rails/rails Star History
データ取得日時: 2025/8/13 01:43

ライブラリ

ActiveSupport::Cache

概要

ActiveSupport::Cacheは、Ruby on Railsに組み込まれているキャッシングフレームワークです。

詳細

ActiveSupport::Cacheは、Ruby on Railsフレームワークの一部として提供される高機能なキャッシングシステムです。複数のキャッシュストア(メモリ、ファイル、Redis、データベースなど)をサポートし、統一されたAPIを通じてキャッシュ操作を行えます。read、write、delete、exist?、fetchといった基本的なメソッドを提供し、キャッシュキーの自動生成、有効期限の管理、階層的なキャッシュ無効化など高度な機能を備えています。Rails 7以降では、データベースベースのSolid Cacheがデフォルトで利用でき、分散環境でも安定したキャッシングが可能です。フラグメントキャッシュ、SQLクエリキャッシュ、ページキャッシュなど、Webアプリケーションのパフォーマンス向上に必要な機能が包括的に提供されています。

メリット・デメリット

メリット

  • 統一されたAPI: 複数のキャッシュストアを同じインターフェースで操作可能
  • 豊富なストアオプション: メモリ、ファイル、Redis、データベースなど多様な選択肢
  • Rails統合: フレームワークとの深い統合によるシームレスな利用
  • 自動キー管理: キャッシュキーの自動生成と衝突回避
  • 階層的無効化: 依存関係に基づくキャッシュクリア機能
  • 暗号化サポート: セキュアなデータキャッシングが可能
  • 分散対応: シャーディング機能による水平スケーリング

デメリット

  • Rails依存: Rails以外のプロジェクトでは利用が制限される
  • 学習コスト: 設定オプションや最適化技法の習得が必要
  • メモリ使用量: 大量のデータをキャッシュする際のメモリ管理が重要
  • デバッグの複雑さ: キャッシュ関連の問題の特定が困難な場合がある
  • パフォーマンス依存: 不適切な使用でかえってパフォーマンスが低下する可能性

主要リンク

書き方の例

基本的なキャッシュ操作

# キャッシュへの書き込み
Rails.cache.write("user:123", user_data, expires_in: 1.hour)

# キャッシュからの読み込み
cached_user = Rails.cache.read("user:123")

# 存在確認
if Rails.cache.exist?("user:123")
  puts "キャッシュが存在します"
end

# キャッシュの削除
Rails.cache.delete("user:123")

fetch メソッドの活用

# キャッシュがあれば取得、なければブロックを実行してキャッシュに保存
user = Rails.cache.fetch("user:#{id}", expires_in: 12.hours) do
  User.find(id)
end

# 条件付きキャッシュ
expensive_data = Rails.cache.fetch("calculation:#{params}", expires_in: 1.day) do
  # 重い計算処理
  perform_expensive_calculation(params)
end

# ネストしたキャッシュキー
Rails.cache.fetch(["user", user.id, "profile", user.updated_at]) do
  user.profile_data
end

複数キーの一括操作

# 複数のキャッシュを一度に読み込み
user_ids = [1, 2, 3, 4, 5]
cache_keys = user_ids.map { |id| "user:#{id}" }
cached_users = Rails.cache.read_multi(*cache_keys)

# 複数のキャッシュを一度に書き込み
users_data = {
  "user:1" => user1_data,
  "user:2" => user2_data,
  "user:3" => user3_data
}
Rails.cache.write_multi(users_data, expires_in: 2.hours)

# 複数のキャッシュを一度に削除
Rails.cache.delete_multi("user:1", "user:2", "user:3")

フラグメントキャッシュ

<!-- ERBテンプレートでのフラグメントキャッシュ -->
<% cache ["user_profile", @user, @user.updated_at] do %>
  <div class="user-profile">
    <h2><%= @user.name %></h2>
    <p><%= @user.bio %></p>
    <!-- 重い描画処理 -->
  </div>
<% end %>

<!-- 条件付きフラグメントキャッシュ -->
<% cache_if @user.cache_enabled?, ["user_data", @user] do %>
  <div class="user-data">
    <%= render 'expensive_partial' %>
  </div>
<% end %>

カスタムキャッシュストアの設定

# config/environments/production.rb
# Redisキャッシュストアの設定
config.cache_store = :redis_cache_store, {
  url: ENV['REDIS_URL'],
  connect_timeout: 30,
  read_timeout: 0.2,
  write_timeout: 0.2,
  reconnect_attempts: 1,
  namespace: 'cache'
}

# ファイルキャッシュストアの設定
config.cache_store = :file_store, '/var/cache/rails', {
  namespace: 'app_cache',
  expires_in: 1.hour
}

# メモリキャッシュストアの設定(開発環境)
config.cache_store = :memory_store, {
  size: 64.megabytes,
  namespace: 'development_cache'
}

Solid Cacheの設定と使用

# config/cache.yml
production:
  database: cache_production
  store_options:
    max_age: <%= 2.weeks.to_i %>
    max_entries: 1_000_000
    namespace: <%= Rails.env %>
    encrypt: true

development:
  database: cache_development
  store_options:
    max_size: <%= 256.megabytes %>
    namespace: development
# config/environments/production.rb
config.cache_store = :solid_cache_store

# Solid Cache固有の設定
config.solid_cache.size_estimate_samples = 1000
config.solid_cache.encrypt = true
config.solid_cache.key_hash_stage = :indexed

高度なキャッシュパターン

class UserService
  def self.fetch_user_with_associations(user_id)
    Rails.cache.fetch("user_full:#{user_id}", expires_in: 1.hour) do
      User.includes(:profile, :posts, :followers)
          .find(user_id)
          .as_json(include: [:profile, :posts, :followers])
    end
  end

  def self.invalidate_user_cache(user_id)
    # 関連するキャッシュを一括削除
    Rails.cache.delete_matched("user*:#{user_id}*")
    Rails.cache.delete("user_count")
    Rails.cache.delete("recent_users")
  end

  def self.warm_cache(user_id)
    # キャッシュのプリロード
    fetch_user_with_associations(user_id)
    Rails.cache.fetch("user_stats:#{user_id}", expires_in: 6.hours) do
      calculate_user_statistics(user_id)
    end
  end
end

# モデルでのキャッシュ統合
class User < ApplicationRecord
  after_update :expire_cache
  after_destroy :expire_cache

  def cached_profile
    Rails.cache.fetch(cache_key_with_version) do
      profile.as_json
    end
  end

  private

  def expire_cache
    Rails.cache.delete(cache_key_with_version)
    Rails.cache.delete_matched("user*:#{id}*")
  end
end