Rails プラグイン作成入門

本ガイドは、Rails アプリケーションの動作を拡張または変更するために、Railsプラグインを作成したい開発者を対象としています。

このガイドの内容:

  • Railsプラグインの概要と、使うべきタイミング
  • プラグインをゼロから作成する
  • Rubyのコアクラスを拡張する
  • ApplicationRecordにメソッドを追加する
  • プラグインをRubyGemsに公開する

1 プラグインとは

Railsプラグインは、Railsアプリケーションに機能を追加するためのパッケージ化された拡張です。プラグインは、いくつかの目的を果たします。

  • プラグインは、コアコードベースの安定性を損なわずに新しいアイデアを試す方法を開発者に提供します。
  • プラグインは、モジュールアーキテクチャをサポートし、機能を独立してメンテナンス・更新・リリースできるようにします。
  • プラグインは、すべてを直接フレームワークに含める必要なしに、強力な機能を導入する手段をチームに提供します。

技術的なレベルでは、プラグインはRailsアプリケーション内で動作するように設計されたRuby gemのことです。多くの場合、プラグインはRailtieでRailsの起動プロセスにフックし、フレームワークの動作を構造化された方法で拡張または変更できるようにします。RailtieはRailsを拡張する最も基本的な統合ポイントであり、通常、「設定」「rakeタスク」「初期化コード」を追加する必要がある場合に使います。ただし、プラグインはコントローラー、ビュー、モデルを公開しません。

Railsエンジン(または単にエンジン)は、一種の高度なプラグインであり、ミニRailsアプリケーションのように振る舞います。エンジンには、独自のルーティング、コントローラー、ビューに加えて、アセットも含められます。すべてのエンジンはプラグインですが、すべてのプラグインがエンジンとは限りません。プラグインとエンジンの主な違いはスコープにあります。プラグインは通常、小さなカスタマイズやアプリ間で共有される振る舞いを扱うのに対し、エンジンは独自のルーティング、モデル、ビューを持ち、完全に近い機能を提供します。

2 ジェネレータのオプション

Railsのプラグインはgemとして構築されます。必要であればRubyGemsBundlerを用いて、異なるRailsアプリケーション間で共有できます。

rails plugin newコマンドは、生成されるプラグイン構造の種別を決定するいくつかのオプションをサポートしています。

基本プラグイン(デフォルト): オプションを指定しない場合、コアクラスのメソッドやユーティリティ関数などのシンプルな拡張に適した最小限のプラグイン構造を生成します。

$ rails plugin new api_boost

本ガイドでは、基本的なプラグインジェネレータで解説します。ジェネレータには--full--mountableの2つのオプションがあり、これら2つについてはRailsエンジンガイドで説明されています。

フルプラグイン--full): このオプションは、appディレクトリツリー(モデル、ビュー、コントローラー)、config/routes.rbファイル、およびlib/api_boost/engine.rbにエンジンクラスを含む、より完全なプラグイン構造を作成します。

$ rails plugin new api_boost --full

--fullオプションは、独自のモデル、コントローラー、ビューが必要だが、名前空間の分離は必要としないプラグインを作成するときに使います。

マウンタブルエンジン--mountable): このオプションは、--fullのすべての要素に加えて、以下の要素も含む完全に分離されたマウンタブルエンジンを作成します。

  • 名前空間の分離(すべてのクラスにApiBoost::がプレフィックスされる)
  • アセットマニフェストファイル
  • 名前空間付きのApplicationControllerApplicationHelper
  • テスト用のダミーアプリでの自動マウント機能
$ rails plugin new api_boost --mountable

--mountableオプションは、管理パネル、ブログ、APIモジュールなど、独立したアプリケーションとして機能できる自己完結型の機能を構築するときに使います。

Railsエンジンについて詳しくは、Railsエンジンのガイドを参照してください。

以下は、適切なオプションを選択するための目安です。

  • 基本プラグイン: シンプルなユーティリティ、コアクラスの拡張、または小さなヘルパーメソッド
  • --fullプラグイン: モデル/コントローラーが必要だが、ホストアプリの名前空間を共有する複雑な機能
  • --mountableエンジン: 管理パネル、ブログ、APIモジュールなどの自己完結型機能

利用法やオプションについては、ヘルプを参照してください。

$ rails plugin new --help

3 セットアップ

本ガイドでは、「API構築中に、リクエストのスロットリング、レスポンスのキャッシュ、自動APIドキュメント生成など、一般的なAPI機能を追加するプラグインを作成したい」という想定で解説します。そのためにApiBoostというプラグインを作成し、任意のRails APIアプリケーションを強化できるようにします。

3.1 プラグインを生成する

以下のコマンドを実行して、基本的なプラグインを作成します。

$ rails plugin new api_boost

これにより、api_boost/という名前のディレクトリにApiBoostプラグインが作成されます。生成された内容を見てみましょう。

api_boost/
├── api_boost.gemspec
├── Gemfile
├── lib/
│   ├── api_boost/
│   │   └── version.rb
│   ├── api_boost.rb
│   └── tasks/
│       └── api_boost_tasks.rake
├── test/
│   ├── dummy/
│   │   ├── app/
│   │   ├── bin/
│   │   ├── config/
│   │   ├── db/
│   │   ├── public/
│   │   └── ... (full Rails application)
│   ├── integration/
│   └── test_helper.rb
├── MIT-LICENSE
└── README.md

lib/ディレクトリには、プラグインのソースコードが含まれています。

  • lib/api_boost.rb: プラグインのメインエントリポイント
  • lib/api_boost/: プラグイン機能のためのモジュールやクラスはここに配置する
  • lib/tasks/: プラグインが提供するRakeタスクはここに配置する

test/dummyディレクトリには、プラグインのテストに使用される完全なRailsアプリケーションが含まれています。このダミーアプリケーションは以下を行います。

  • プラグインをGemfileで自動的に読み込む
  • プラグインとの統合をテストするためのRails環境を提供する
  • テストに必要なジェネレーター、モデル、コントローラー、ビューが含まれている
  • rails consolerails serverを使って対話的に利用できる

Gemspecファイルapi_boost.gemspec)は、プラグインgemのメタデータ、依存関係、およびパッケージング時にインクルードするファイルを定義します。

3.2 プラグインをセットアップする

プラグインを含むディレクトリに移動し、api_boost.gemspecをエディタで編集して、値がTODOの行を置き換えます。

spec.homepage    = "http://example.com"
spec.summary     = "Enhance your API endpoints"
spec.description = "Adds common API functionality like request throttling, response caching, and automatic API documentation."

...

spec.metadata["source_code_uri"] = "http://example.com"
spec.metadata["changelog_uri"] = "http://example.com"

続いて、bundle installコマンドを実行します。

終わったら、テスト用データベースをセットアップします。test/dummyディレクトリに移動して、以下のコマンドを実行します。

$ cd test/dummy
$ bin/rails db:create

ダミーアプリケーションは、通常のRailsアプリケーションと同じように動作します。これによって、モデルの生成、マイグレーションの実行、サーバーの起動、コンソールのオープンなどのプラグインの機能を、プラグインの開発中にテストできます。

データベースが作成されたら、プラグインのrootディレクトリに戻ります(cd ../..)。

これで、bin/testでテストを実行できます。以下のような出力が表示されるはずです。

$ bin/test
...
1 runs, 1 assertions, 0 failures, 0 errors, 0 skips

これで、生成がすべて正しく行われ、機能追加の準備が整ったことを確認できました。

4 コアクラスを拡張する

本セクションでは、Railsアプリケーションのどこからでも利用できるように、Integerクラスにメソッドを追加する方法を説明します。

コアクラスを拡張する場合は、その前に「StringArrayHashなどのコアクラスの拡張は、たとえ使うとしても控えめにすべきである」ことを十分理解しておかなければなりません。コアクラスの拡張は壊れやすく、危険であり、多くの場合不要です。
コアクラスを拡張すると、以下のような問題を引き起こす可能性があります。 - 複数のgemが同じクラスを同じメソッド名で拡張した場合にメソッド名が競合する - RubyやRailsがアップデートされてコアクラスの振る舞いが変更された場合に予期せず壊れる - 拡張メソッドの場所が不明なため、デバッグが困難になる - プラグインと他のコードの間に結合の問題を引き起こす コアクラスを拡張する前に、まず以下の代替案を検討してください。 - ユーティリティモジュールやヘルパークラスを作成する - モンキーパッチではなく、コンポジションを使う - 独自のクラスのインスタンスメソッドとして機能を実装する コアクラスを拡張すると問題を引き起こす理由について詳しくは、『The Case Against Monkey Patching』を参照してください。ただし、コアクラスを拡張するしくみを理解しておくことには価値があります。以下の例ではコアクラスを拡張する具体的な方法を示していますが、実際の利用は慎重に検討すべきです。

このサンプルでは、RubyのコアクラスであるIntegerクラスにrequests_per_hourというメソッドを追加します。

lib/api_boost.rbファイルをエディタで開いて、require "api_boost/core_ext"を追加します。

# api_boost/lib/api_boost.rb

require "api_boost/version"
require "api_boost/railtie"
require "api_boost/core_ext"

module ApiBoost
  # ここに独自のコードを書く
end

core_ext.rbファイルを作成し、10.requests_per_hourというRateLimitを定義するメソッドをIntegerクラスに追加します。このメソッドは、Timeを返す10.hoursメソッドに形が似ています

# api_boost/lib/api_boost/core_ext.rb

ApiBoost::RateLimit = Data.define(:requests, :per)

class Integer
  def requests_per_hour
    ApiBoost::RateLimit.new(self, :hour)
  end
end

これを実際に動かしてみましょう。test/dummyディレクトリに移動し、bin/rails consoleを起動して、APIレスポンスのフォーマットをテストします。

$ cd test/dummy
$ bin/rails console
irb> 10.requests_per_hour
=> #<data ApiBoost::RateLimit requests=10, per=:hour>

ダミーアプリケーションはプラグインを自動的に読み込むため、追加した拡張をその場でテストできます。

5 "act_as"メソッドをActive Recordに追加する

Railsのモデルにacts_as_somethingメソッドを追加するのは、プラグインでよく使われるパターンです。ここでは、Active RecordモデルにAPI固有の機能を追加するacts_as_api_resourceというメソッドを追加したいとします。

APIを構築中に、リソースに最後にアクセスし時間をトラッキングしたいとします。たとえば、ProductのようなリソースがAPIで最後にアクセスされた時間を追跡したいとします。このタイムスタンプを使って次のようなことができます。

  • リクエストのスロットリング(減速)
  • 管理パネルに「最後にアクティブだった時刻」を表示する
  • 古くなったレコードを優先的に同期する

プラグインを共有することで、このロジックをすべてのモデルに書かなくても済むようになります。act_as_api_resourceメソッドは、この機能を任意のモデルに追加して、タイムスタンプフィールドを更新してAPIアクティビティをトラッキング可能にします。

まず、必要なファイルを以下のようにセットアップします。

# api_boost/lib/api_boost.rb

require "api_boost/version"
require "api_boost/railtie"
require "api_boost/core_ext"
require "api_boost/acts_as_api_resource"

module ApiBoost
  # Your code goes here...
end
# api_boost/lib/api_boost/acts_as_api_resource.rb

module ApiBoost
  module ActsAsApiResource
    extend ActiveSupport::Concern

    class_methods do
      def acts_as_api_resource(api_timestamp_field: :last_requested_at)
        # APIタイムスタンプ用のフィールド名を指定するオプションを保存するクラスレベルの設定を作成する
        cattr_accessor :api_timestamp_field, default: api_timestamp_field.to_s
      end
    end
  end
end

上のコードでは、ActiveSupport::Concernを使って、クラスメソッドとインスタンスメソッドの両方を持つモジュールを手軽にincludeできるようにしています。class_methodsブロック内のメソッドは、モジュールがincludeされたタイミングでクラスメソッドになります。詳しくは、APIドキュメントのActiveSupport::Concernを参照してください。

5.1 クラスメソッドを追加する

デフォルトでは、このプラグインはモデルにlast_requested_atという名前のカラムがあることを前提としていますが、そのカラム名がすでに他の目的で使われている可能性があるため、プラグインでカスタマイズ可能にしています。 api_timestamp_field:オプションで別のカラム名を渡すことで、デフォルトのカラム名を上書きできます。この値はクラスレベルの設定api_timestamp_fieldに保存され、プラグインがタイムスタンプを更新するときに使われます。

たとえば、カラム名をlast_requested_atではなくlast_api_callにしたい場合、以下のようにします。

まず、この機能をテストするために、"dummy" Railsアプリケーションでいくつかのモデルを生成しておきます。以下のコマンドをtest/dummy/ディレクトリで実行します。

$ cd test/dummy
$ bin/rails generate model Product last_requested_at:datetime last_api_call:datetime
$ bin/rails db:migrate
$ cd test/dummy
$ bin/rails generate model Product last_requested_at:datetime last_api_call:datetime
$ bin/rails db:migrate

次に、Productモデルを以下のように更新して、APIリソースとして機能するようにします。

# test/dummy/app/models/product.rb

class Product < ApplicationRecord
  acts_as_api_resource api_timestamp_field: :last_api_call
end

このプラグインをすべてのモデルで利用可能にするには、ApplicationRecordにモジュールをincludeします(この作業を自動化する方法については後述します)。

# test/dummy/app/models/application_record.rb

class ApplicationRecord < ActiveRecord::Base
  include ApiBoost::ActsAsApiResource

  self.abstract_class = true
end

これで、この機能をRailsコンソールでテストできます。

irb> Product.api_timestamp_field
=> "last_api_call"

5.2 インスタンスメソッドを追加する

このプラグインは、track_api_requestというインスタンスメソッドを、acts_as_api_resourceを呼び出す任意のActive Recordモデルに追加します。このインスタンスメソッドは、設定されたタイムスタンプフィールドの値を現在の時刻(または提供されたカスタム時刻)に設定し、APIリクエストが行われた日時をトラッキングできるようにします。

この振る舞いを追加するには、acts_as_api_resource.rbファイルを以下のように更新します。

# api_boost/lib/api_boost/acts_as_api_resource.rb

module ApiBoost
  module ActsAsApiResource
    extend ActiveSupport::Concern

    class_methods do
      def acts_as_api_resource(options = {})
        cattr_accessor :api_timestamp_field,
                       default: (options[:api_timestamp_field] || :last_requested_at).to_s
      end
    end

    def track_api_request(timestamp = Time.current)
      write_attribute(self.class.api_timestamp_field, timestamp)
    end
  end
end

上のサンプルコードではwrite_attributeメソッドでモデルのフィールドに書き込んでいますが、これはプラグインがモデルとやり取りする方法の一例を示したに過ぎず、常に適切な方法とは限りません。たとえば、sendでセッターメソッドを呼び出す方法を好む場合もあります。

send("#{self.class.api_timestamp_field}=", timestamp)

これで、この機能をRailsコンソールでテストできます。

irb> product = Product.new
irb> product.track_api_request
irb> product.last_api_call
=> 2025-06-01 10:31:15 UTC

6 高度な統合: Railtiesを利用する

これまで構築したプラグインは、基本的な機能には十分ですが、Railsのフレームワークとより深いレベルで統合する必要が生じた場合は、Railtieを利用することも可能です。

プラグインでRailtiesが必要になるのは、以下のような場合です。

  • Rails.application.config経由で設定オプションにアクセスする
  • Railsクラスにモジュールを自動的にincludeする
  • Rakeタスクをホストアプリケーションに提供する
  • Railsの起動中にイニシャライザをセットアップする
  • アプリケーションのスタックにミドルウェアを追加する
  • 独自のRailsジェネレーターを設定する
  • ActiveSupport::Notificationsにサブスクライブする

これまで見てきたようなシンプルなプラグインでは、Railtieは必要ありません。

6.1 設定オプションにアクセスする

たとえば、to_throttled_responseメソッド内のデフォルトのレート制限を設定可能にしたいとします。

まず、Railtieを作成します。

# api_boost/lib/api_boost/railtie.rb

module ApiBoost
  class Railtie < Rails::Railtie
    config.api_boost = ActiveSupport::OrderedOptions.new
    config.api_boost.default_rate_limit = 60.requests_per_hour

    initializer "api_boost.configure" do |app|
      ApiBoost.configuration = app.config.api_boost
    end
  end
end

プラグインに設定モジュールを追加します。

# api_boost/lib/api_boost/configuration.rb

module ApiBoost
  mattr_accessor :configuration, default: nil

  def self.configure
    yield(configuration) if block_given?
  end
end

コア拡張を更新して、設定を利用できるようにします。

# api_boost/lib/api_boost/core_ext.rb

module ApiBoost
  module ActsAsApiResource
    def to_throttled_json(rate_limit = ApiBoost.configuration.default_rate_limit)
      limit_window = 1.send(rate_limit.per).ago..
      num_of_requests = self.class.where(self.class.api_timestamp_field => limit_window).count
      if num_of_requests > rate_limit.requests
        { error: "Rate limit reached" }.to_json
      else
        to_json
      end
    end
  end
end

プラグインのメインのファイルで、新しいファイルをrequireします。

# api_boost/lib/api_boost.rb

require "api_boost/version"
require "api_boost/configuration"
require "api_boost/railtie"
require "api_boost/core_ext"
require "api_boost/acts_as_api_resource"

module ApiBoost
  # ここに独自のコードを書く
end

これで、このプラグインを利用するアプリケーションで以下のように設定できるようになります。

# config/application.rb
config.api_boost.default_rate_limit = "100 requests per hour"

6.2 モジュールを自動的にincludeする

ApplicationRecordでユーザーが手動でActsAsApiResourceincludeしなくてもよいように、以下のようにRailtieで自動的に行うことができます。

# api_boost/lib/api_boost/railtie.rb

module ApiBoost
  class Railtie < Rails::Railtie
    config.api_boost = ActiveSupport::OrderedOptions.new
    config.api_boost.default_rate_limit = 60.requests_per_hour

    initializer "api_boost.configure" do |app|
      ApiBoost.configuration = app.config.api_boost
    end

    initializer "api_boost.active_record" do
      ActiveSupport.on_load(:active_record) do
        include ApiBoost::ActsAsApiResource
      end
    end
  end
end

ActiveSupport.on_loadフックは、Railsの初期化中に適切なタイミングで(ActiveRecordが完全に読み込まれた後)モジュールがincludeされることを保証します。

6.3 Rakeタスクを提供する

プラグインを使っているアプリケーションにRakeタスクを提供したい場合は、以下のようにします。

# api_boost/lib/api_boost/railtie.rb

module ApiBoost
  class Railtie < Rails::Railtie
    # ...既存の設定...

    rake_tasks do
      load "tasks/api_boost_tasks.rake"
    end
  end
end

Rakeタスクファイルを作成します。

# api_boost/lib/tasks/api_boost_tasks.rake

namespace :api_boost do
  desc "Show API usage statistics"
  task stats: :environment do
    puts "API Boost Statistics:"
    puts "Models using acts_as_api_resource: #{api_resource_models.count}"
  end

  def api_resource_models
    ApplicationRecord.descendants.select do |model|
      model.include?(ApiBoost::ActsAsApiResource)
    end
  end
end

これで、このプラグインを利用しているRailsアプリケーションでrails api_boost:statsコマンドを実行可能になります。

6.4 Railtiesをテストする

ダミーアプリケーションを使うことで、Railtieが正しく動作することをテストできます。

# api_boost/test/railtie_test.rb

require "test_helper"

class RailtieTest < ActiveSupport::TestCase
  def test_configuration_is_available
    assert_not_nil ApiBoost.configuration
    assert_equal 60.requests_per_hour, ApiBoost.configuration.default_rate_limit
  end

  def test_acts_as_api_resource_is_automatically_included
    assert Class.new(ApplicationRecord).include?(ApiBoost::ActsAsApiResource)
  end

  def test_rake_tasks_are_loaded
    Rails.application.load_tasks
    assert Rake::Task.task_defined?("api_boost:stats")
  end
end

Railtiesは、プラグインをRailsの初期化プロセスとクリーンに統合する方法を提供します。Railsの完全な初期化ライフサイクルについて詳しくは、Rails初期化プロセスのガイドを参照してください。

7 プラグインをテストする

テストを追加するのはよい習慣です。Railsプラグインジェネレータは、テストフレームワークも作成してくれます。ここでは、先ほど構築した機能のテストを追加してみましょう。

7.1 コア拡張をテストする

コア拡張をテストするためのファイルを作成します。

# api_boost/test/core_ext_test.rb

require "test_helper"

class CoreExtTest < ActiveSupport::TestCase
  def test_to_throttled_response_adds_rate_limit_header
    response_data = "Hello API"
    expected = { data: "Hello API", rate_limit: 60.requests_per_hour }
    assert_equal expected, response_data.to_throttled_response
  end

  def test_to_throttled_response_with_custom_limit
    response_data = "User data"
    expected = { data: "User data", rate_limit: "100 requests per hour" }
    assert_equal expected, response_data.to_throttled_response("100 requests per hour")
  end
end

7.2 "acts_as"メソッドをテストする

自作の"acts_as"メソッドをテストするためのファイルを作成します。

# api_boost/test/acts_as_api_resource_test.rb

require "test_helper"

class ActsAsApiResourceTest < ActiveSupport::TestCase
  def test_a_users_api_timestamp_field_should_be_last_requested_at
    assert_equal "last_requested_at", User.api_timestamp_field
  end

  def test_a_products_api_timestamp_field_should_be_last_api_call
    assert_equal "last_api_call", Product.api_timestamp_field
  end

  def test_users_track_api_request_should_populate_last_requested_at
    user = User.new
    freeze_time = Time.current
    Time.stub(:current, freeze_time) do
      user.track_api_request
      assert_equal freeze_time.to_s, user.last_requested_at.to_s
    end
  end

  def test_products_track_api_request_should_populate_last_api_call
    product = Product.new
    freeze_time = Time.current
    Time.stub(:current, freeze_time) do
      product.track_api_request
      assert_equal freeze_time.to_s, product.last_api_call.to_s
    end
  end
end

テストを実行して、すべてが正常に動作していることを確認します。

$ bin/test
...
6 runs, 6 assertions, 0 failures, 0 errors, 0 skips

8 ジェネレータ

ジェネレータは、プラグインgemのlib/generators/ディレクトリに配置するだけで手軽に追加できます。ジェネレータの作成について詳しくは、ジェネレータのガイドを参照してください。

9 Gemを公開する

今開発しているgemプラグインをGitリポジトリに配置することで、簡単に共有できます。ApiBoost gemを他の人と共有するには、コードをGitリポジトリ(GitHubなど)にコミットし、対象のアプリケーションのGemfileに以下の行を追加します。

gem "api_boost", git: "https://github.com/YOUR_GITHUB_HANDLE/api_boost.git"

bundle installを実行すると、アプリケーションでgemの機能を利用できます。

Gemを正式なリリースとして共有できる準備が整ったら、RubyGemsに公開できます。

BundlerのRakeタスクを利用することも可能です。利用可能なタスクの一覧は以下のコマンドで確認できます。

$ bundle exec rake -T

$ bundle exec rake build
# Build api_boost-0.1.0.gem into the pkg directory

$ bundle exec rake install
# Build and install api_boost-0.1.0.gem into system gems

$ bundle exec rake release
# Create tag v0.1.0 and build and push api_boost-0.1.0.gem to Rubygems

自作のgemをRubyGemsで公開する方法について詳しくは、RubyGemsの『Publishing your gem』を参照してください。

10 RDocドキュメントを追加する

プラグインが安定したら、ドキュメントを作成できます。最初のステップは、README.mdファイルを更新して、プラグインの使用方法に関する詳細情報を追加することです。以下の情報をドキュメントに含める必要があります。

  • 自分の名前
  • インストール方法
  • アプリに機能を追加する方法(一般的なユースケースのいくつかの例)
  • ユーザーにとって有用な、時間を節約できる警告、注意点、ヒント

README.mdファイルの内容が固まったら、開発者が利用するすべてのメソッドにRDocコメントを追加します。また、パブリックAPIに含めないコード部分には# :nodoc:コメントを追加するのが慣習です。

APIドキュメントが準備できたら、プラグインディレクトリに移動して、次のコマンドを実行します。

$ bundle exec rake rdoc

フィードバックについて

Railsガイドは GitHub の yasslab/railsguides.jp で管理・公開されております。本ガイドを読んで気になる文章や間違ったコードを見かけたら、気軽に Pull Request を出して頂けると嬉しいです。Pull Request の送り方については GitHub の README をご参照ください。

原著における間違いを見つけたら『Rails のドキュメントに貢献する』を参考にしながらぜひ Rails コミュニティに貢献してみてください 🛠💨✨

本ガイドの品質向上に向けて、皆さまのご協力が得られれば嬉しいです。

Railsガイド運営チーム (@RailsGuidesJP)

支援・協賛

Railsガイドは下記の協賛企業から継続的な支援を受けています。支援・協賛にご興味あれば協賛プランからお問い合わせいただけると嬉しいです。

  1. Star
  2. このエントリーをはてなブックマークに追加