クライアントベースの Web サイト (Ruby on Rails) に最適なデータベース戦略
概要
私は、小規模なニッチ市場のニーズに応える優れた Web サイト システムを構築しました。私は昨年、Capistrano を使用してソフトウェアのコピーを Web サーバーに展開することで、これらの Web サイトを販売してきました。
これらの Web サイトの唯一の違いは、データベース、CSS ファイル、および個々のクライアントのグラフィック デザインに使用される少数の画像セットであると私は思いました。
それ以外はすべてまったく同じ、または同じであるべきです…現在、これらのサイトを約 20 個展開しているため、すべてを同じコードで更新し続けるのが面倒になってきています。そしてこの問題はさらに悪化するばかりです。
このシステムをリファクタリングして、デプロイされた 1 セットの Ruby コードを使用し、受信リクエストの URL によって正しいデータベースなどを動的に選択できるようにする必要があると考えています。
データベースを扱うには次の 2 つの方法があるようです。
すべての CRUD 操作に client_id フィールドを追加するためにアプリケーション内のすべてのモデルをリファクタリングする必要がないため、現時点では複数データベースのアプローチが最も簡単です。
ただし、データベースを移行するたびに、数十または数百の異なるデータベースに対して「rake db:merge」を実行しなければならないのは面倒です。もちろんこれはスクリプトで実行できますが、あまり良い匂いではありません。
一方、すべてのクライアントの「アイテム」テーブルには 20,000 ~ 50,000 のアイテムが含まれます。 items テーブルに 50 万件または 100 万件のアイテムがある場合、全文検索の速度が心配になります。 client_id フィールドにインデックスがある場合でも、アイテムが異なるクライアント データベースに分割されていれば、検索が高速になるのではないかと思います。
この問題に取り組む最善の方法について知識のある方がいらっしゃいましたら、ぜひお聞きしたいと思っています。
解決策
私は複数データベースのアプローチを採用することにしました。アプリケーション全体を作り直す必要がないので、これが私にとって最も簡単な方法です。
私がやろうとしているのは、application_controller に before_filter を追加して、すべてのコントローラーに適用することです…次のようなものです。
before_filter :client_db # switch to client's db
次に、application_controller.rb に次のような内容を含めます。
def client_db
@client = Client.find(params[:client_id])
spec = Client.configurations[RAILS_ENV]
new_spec = spec.clone
new_spec["database"] = @client.database_name
ActiveRecord::Base.establish_connection(new_spec)
end
次に、example.com?client_id=12345 のような URL により、正しいデータベースが選択されます。
Mongrel の前でプロキシとして Apache を使用しているため、Apache はクライアントの Web サイト URL に基づいて、すべてのリクエストに正しい client_id を追加します。したがって、client_id は実際にはユーザーに表示される URL の一部ではありません。 Apache と Mongrel の間でのみ渡されます。これを適切に説明できているかどうかはわかりませんが、これは機能し、物事をクリーンかつシンプルに保ちます。
将来単一のデータベースを使用する必要があると判断した場合は、すべてのコードをリファクタリングできます。現時点では、これが最も簡単なアプローチのようです。