こちらの記事はソニックガーデン 若手プログラマ Advent Calendar 2024の1日目の記事です。
若手のトップバッターとして、ふわっとしか理解していなかったアダプターについて書きました。
はじめに
Ruby on Railsで開発を行う際に、database.ymlに設定するアダプター(adapter:
)について、どれほど理解していますか?
default: &default
adapter: postgresql
...
こちらのようにadapter:
を指定するだけで、Railsが自動的にSQLを発行してくれる仕組みが気になり、内部で何が起こっているのか調べてみました。
この記事では、以下の内容について解説します。
-
adapter:
を指定すると、内部で何が変わるのか -
pg
やmysql2
といったgemがどのタイミングで使われるのか
そもそも Active Record とは
Active Recordは、Ruby on Railsにおけるオブジェクトリレーショナルマッピング(ORM)システムです。これにより、データベースのテーブルをRubyのオブジェクトとして操作でき、SQLを直接書かずにデータベース操作を行うことが可能になります。
Railsを使って開発している場合、以下のようなイメージでActive Recordを利用していると思います。
「ActiveRecordのコードからいい感じでSQLを発行してくれてるんだな」ぐらいのイメージでいる方もいらっしゃるかと思います。
adapter:
を指定すると内部的に何が変わるのか
では、database.yml
で指定するadapter:
が何を意味するのか、詳しく見ていきましょう。
Active Recordのアダプターは、異なるデータベースエンジン(PostgreSQL、MySQLなど)間での差異を吸収し、共通のインターフェースを提供します。これにより、データベースを切り替えても、アプリケーションコードをほとんど変更せずに済みます。
例えば、database.yml
に以下のようにadapter: postgresql
を設定すると、RailsはActiveRecord::ConnectionAdapters::PostgreSQLAdapter
を使用して、PostgreSQLとの接続やSQLの発行を行います。
adapter: postgresql
このように、データベースエンジンに適切なアダプターを指定することで、Railsはそのデータベースに合わせた処理を自動的に行います。もしMySQLを使用する場合は、adapter: mysql2
を指定すれば、ActiveRecord::ConnectionAdapters::Mysql2Adapter
が使われます。
以下は、アダプターのイメージ図です。
アダプターは、異なるデータベースを使用してもActive Recordが一貫した動作をするための役割を担っています。
pg
やmysql2
はどこで使われるのか
次に、pg
やmysql2
などのgemが、実際にどこで使われるのかについて見ていきましょう。
例えば、ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
は、内部でpg
gemを利用してPostgreSQLとの接続を行います。以下は、postgresql_adapter.rb
の一部です。
require "pg"
...
def connect
@raw_connection = self.class.new_client(@connection_parameters)
...
end
def new_client(conn_params)
PG.connect(**conn_params)
...
end
require "pg"
によってpg gemが読み込まれ、new_client
メソッド内でPG.connect
が呼ばれることで、PostgreSQLとの接続が確立されます。PG.connect
はPG::Connection
というPostgresSQL接続のクラスをnewする役割を果たしています。この接続が、RailsアプリケーションからPostgreSQLに対するクエリを発行できるようにします。
以下の図で、pg gemがどのように使用されるかのイメージを示します。
結論
-
database.yml
で指定するadapter:
に応じて、Railsは異なるアダプタークラス(PostgreSQLAdapter
・Mysql2Adapter
)を使用する - アダプタークラス内では、対応するgem(
pg
・mysql2
)がrequireされ、実際のデータベースとの接続が確立される
アダプターによってRailsは異なるデータベースエンジンを抽象化し、アプリケーションコードを変更することなく、さまざまなデータベースに対応できるようなるということが分かりました。
この記事を読んでくれた方も、Railsがよしなにやっている部分のコード見てみても面白いかもしれません…!
参考文献
この記事を書く上でどのあたりのコードを読んだのか参考になれば幸いです。