【Rails】Arel とはなにか
概要
Arel::Table は Ruby on Rails の ActiveRecord の機能の一部です。
SQL テーブルを Ruby のオブジェクトとして表現することができます。
複雑なクエリや、外部サービスに向けてクエリを発行するときに便利です。
詳細
前提知識
例えば以下のようなクエリを実行したいとします。
SELECT `articles`.* FROM `articles`
普通に ActiveRecord
を使うと、以下のように書けます。
Article.all
to_sql
メソッドで発行されるクエリを確認できます。
> Article.all.to_sql
=> "SELECT `articles`.* FROM `articles`"
このクエリを、Article モデルを使わずに実行する場合、以下のように書けます。
> ActiveRecord::Base.connection.exec_query("SELECT `articles`.* FROM `articles`")
=>
#<ActiveRecord::Result:0x0000ffffb8b65770
@column_types={},
@columns=["id", "title", "body", "is_published", "created_at", "updated_at"],
@hash_rows=nil,
@rows=[[1, "title", "ああああ", 0, 2024-03-13 05:39:29.082136 UTC, 2024-03-13 05:39:29.082136 UTC]]>
この実行結果として、ActiveRecord::Result
のインスタンスが返ります。
クエリの実行結果を扱いやすい形にしています。ここでは詳しい説明は端折りますが、
rows
に結果のレコードが配列で格納されていることに注目してください。
Arel はクエリを組み立てるときに便利なクラス
上記のように、いわゆる生クエリを組み立てるときに便利なのが Arel クラスです。
シンプルなクエリならまだ問題ないですが、複雑なクエリになってくる(join したり)とコードの見通しも悪くなりますし、SQL インジェクションのリスクも高くなります。
Arel クラスを使うことで、メソッドチェーンすることができるため、書きやすくなります。
以下がその例です。
Arel::Table.new(:articles).project(Arel.star)
to_sql
で確認すると、目的のクエリが作成できています。
> Arel::Table.new(:articles).project(Arel.star).to_sql
=> "SELECT * FROM `articles`"
Arel::Table.new(:articles)
でテーブルのオブジェクトを作成しています。
project
は SLECT
、Arel.star
は*
を意味しています。
必要なカラムだけ欲しいときは、project
の引数に以下のように指定すると良いです。
> Arel::Table.new(:articles).project(table[:title], table[:body]).to_sql
=> "SELECT `articles`.`title`, `articles`.`body` FROM `articles`"
Arel で作成したクエリを、先程のように ActiveRecord::Base.connection.exec_query
で実行すると、同じ結果が得られることがわかります。
> sql = Arel::Table.new(:articles).project(Arel.star).to_sql
=> "SELECT `articles`.`title`, `articles`.`body` FROM `articles`"
> ActiveRecord::Base.connection.exec_query(sql)
=>
#<ActiveRecord::Result:0x0000ffffb947bdf0
@column_types={},
@columns=["id", "title", "body", "is_published", "created_at", "updated_at"],
@hash_rows=nil,
@rows=[[1, "title", "ああああ", 0, 2024-03-13 05:39:29.082136 UTC, 2024-03-13 05:39:29.082136 UTC]]>
以下のようにメソッドチェーンでクエリを作成していけます。
hogehoge_table = Arel::Table.new(:hogehoge)
fugafuga_table = Arel::Table.new(:hogehoge)
hogehoge_table
.join(fugafuga_table)
.on(hogehoge_table[:id].eq(fugafuga_table[:hogehoge_id]))
.project(
hogehoge_table[:id], hogehoge_table[:title], hogehoge_table[:body]
).to_sql
=> "SELECT `hogehoge`.`id`, `hogehoge`.`title`, `hogehoge`.`body` FROM `hogehoge` INNER JOIN `hogehoge` ON `hogehoge`.`id` = `hogehoge`.`hogehoge_id`"
外部サービス(Amazon Redshift)などに投げるクエリを Arel で作成するといった使い方ができます。
まとめ
Arel について簡単な使い方を書いていきました!
Rails を使っていると ActiveRecord が便利すぎて SQL に慣れないことがありますが、
Arel を使うと少しはアレルギーを解消できると思います!
Discussion