Arelの不具合修正
こんにちは、tanakenです。第15回のtanaken on Rails始めます。今週は2つプルリクエストをピックアップして紹介します。
ちょっと短めにサクッとやりたいと思います。1つ目、FixesUnionSelectParenthesesかな。
ActiveRecordに関する変更です。Arelというモジュールがあります。
Arelですね。Aだけ大文字ですね。Arelというモジュールがあって、このArelに関する変更が行われたプルリクエストです。
Arelというのは、公式のRailsのAPIドキュメントにはあまり記載がなくてですね、あんまりお勧めはされていないものです。
Arelについて、様々な個人ブログだったり、会社のテックブログだったりで書かれている記事がいくつかあったんですけども、
今回は、テックラッチョさん、BPS株式会社のテックラッチョという媒体でのArelのすすめという記事へのリンクを貼っておきました。
ArelはSQLを生成するライブラリで、ActiveRecordがSQLを生成する際に内部的に使われていますと記載があります。
また、Arelを使いこなせるようになると、複雑なSQLを文字列として実装しなくてよくなるため、
ActiveRecordの生成するSQLと親和性の高いSQLを組み立てられるようになります。
そんな一言も書いてあります。
複雑なSQLをどうしてもActiveRecordの機能でうまく作れない、作るのが難しいというような場合に、文字列でSQLを記載してそれを実行するというようなことが稀にあるんですよね。
それもいいんだけども、このArelを使いこなせたらもっと便利なんじゃないというようなことを書いてくださっている記事というふうに理解しています。
Arelの詳しい説明は一旦置いておいて、今回のプールリクでは、このArelを使ってテーブルをユニオン結合する。
そういった際に、特定のケースでシンタックスエラーになる場合があったので、それを修正しましたというプールリクエストです。
どんな場合にエラーになっていたかというと、オーダーバイだったり、リミットだったりを使ったクエリ、それらをユニオンする際に問題が発生していましたということです。
まずユニオンをどんな感じでやるのかということをまず紹介したい。
僕も今回プールリクエストやイシューを見て知ったんですけども、
例えばTという変数を定義します。
TイコールArelコロンコロンテーブルドットニュー括弧でシンボルのusersと。
usersテーブルというのを変数Tに入れたみたいな感じですよ。
Arelテーブルインスタンスを入手しましたと。
ワーキングという変数をまた新たに定義して、先ほどのTを使ってユニオンをしたArelテーブルオブジェクトを作りましょうという感じかな。
ワーキングイコールTドットプロジェクト括弧TのブラケットのシンボルIDドットユニオン括弧を括弧で括って
Tドットプロジェクト括弧TブラケットシンボルID括弧と字という感じ。
ちょっと言葉で言うと難しいですね。
何をやっているかというと、usersテーブルからIDをセレクトして、そのIDをセレクトしたテーブル同士をユニオンしますということをやっていると。
そんなことはあまりないと思うんですけど、普通は異なるテーブルからデータを取ってきてユニオンするということがやりたいことだと思うんですけど、
今回は説明のため、usersというテーブルからプロジェクトというのがセレクトで取ってくるカラムを指定するみたいな感じっぽい。
正式なドキュメントちゃんと読んでないですけど、サンプルコードを見たらそんな感じっぽいので、
TドットプロジェクトIDでIDカラムを取ってくるよという感じですね。
ユニオンで括弧内に同じくIDカラムを取ってくるというのを書いてて、
つまり、ユーザーステーブルからIDを取ってくるという2つのSQLをユニオンすると。
そんな感じの仕組みになってます。
さっきのワーキング変数に今書いたユニオンってやった、
アレルテーブルオブジェクトを入れてると。
アレルテーブルオブジェクトなのかな。ちょっと待ってくださいね。
こいつは、アレルノード、アレルコロンコロンノーズ、ノードイ、ノードの複数形。
アレルコロンコロンノーズコロンコロンユニオンっていうオブジェクトなんだ。
ユニオンオブジェクトっていうのがあるんですね。
なのでこのワーキング変数にユニオンオブジェクトっていうのが入ってると。
そのワーキング.SQLってやると、実際に発行されるSQLが文字列で見れるんですけど、
それを見ると括弧で括られてて、全体が括弧で括られてて、
セレクトユーザーズ.IDフロムユーザーズ、ユニオンセレクトユーザーズ.IDフロムユーザーズと。
そんなクエリができますよっていう感じですね。
アクティブレコードベースコネクションのExecクエリ、クエリを実行するというメソッドで、
そのクエリをToSQLしたクエリを文字列渡してあげると、
もちろんユーザーのIDがユニオンされた、同じIDが2回ずつ登場するユニオンされたテーブルとかデータができますよねというような感じですね。
これは基本の使い方でございます。
何が不具合があったかという話なんですけど、
このユニオンのときにオーダーバイやリミットを含んでいると、
シンタクセーラーになるクエリが作られるということで、
さっきの例で、さっきはworkingという変数に入れたんですけど、
じゃあwithlimitという変数にちょっと入れてみることにしましょう。
新しくね。
何を入れるかというと、
t.projectのIDをセレクトしてくると。
これにメソッドチェーンして、
.take1、take1ってやると、
リミット1ですね。
ユーザーのテーブルからリミット1でレコード1件取っていきますっていうクエリになると。
これにまたメソッドチェーンで、
.unionで括弧で括弧の中に、
t.projectidと。
前半部分でユーザーズテーブルから1レコードだけ取ってきて、
その後ろにユーザーテーブルから全部取ってきたIDをユニオンしますよというようなことをやりたいというクエリですね。
これもユニオンオブジェクトなんだと思います。
withlimit変数にユニオンオブジェクトを入れたという感じですね。
これを2sqlすると、
括弧書きでselectusers.idfromusers limit1
unionselectusers.idfromusersという感じになるんですけど、
これがクエリを実行すると、
シンダクスエラーになります。
何でかというと、
何でかというとっていうとそこまで分かってないんだけど、
リミット1の位置が前半部分、
リミット1を含むクエリとユニオンのところで、
前半部分で括弧で括ってあげないと、
クエリのシンタックスとして正しくないんですよね。
多分リミットがどこにかかるのとかが微妙に分かんなくなっちゃうのかな。
なので、ユニオンというジョイン結合文が、
リミット1の直後には直接は置けないんですよ、多分。
前半部分をしっかり括弧で括ってあげて、
IDを取ってきた、
Arelのユニオン結合に関する修正
1行だけ取ってきたテーブル構造になっているものなんだよっていうものを
明記した上で、
それにユニオンするならできるんだけど、
括弧つけずにリミット1ユニオンってやるのはできないというのは
シンタックスエラーになるということで、
これは困るねというのが今回のプレリクエストの問題でした。
なので、今回のプレリクエストでは、
前半部分、リミット1を含む部分だけをまず括弧で括れるように
修正を行っているということですね。
なかなか修正自体は細かく追いかけていないですけども、
やりたいことはそういうことですね。
なので、前半部分を括弧で括った上でユニオンできると。
前半後半、多分後半にテイク1してても一緒なんですけど、
後半だったらうまく動くのかな、ユニオンした後にテイク1だからうまく動くのかな、
みたいなのがあるかも。
微妙に前半につくのか後半にリミットつく場所によっても、
多分シンタックスエラーになるにならない変わってきそうだなって気がしますが、
そういうことですね。
なので前半部分にリミットがあってもちゃんと括弧で括れるんで、
シンタックスとして問題ないものになるよということみたいですね。
はい。
サクッとと言いつつ結構1個目で時間かけてしまった。
はい、では2個目。
2個目のプレリクエストは、
フィックスアクティブジョブコロンコロン延期アフタートランザクションコミットAPI
というプレリクエストです。
こちらはアクティブジョブに関する変更で、
先週紹介したものに関係のある変更です。
先週アクティブジョブに関する変更の紹介をして、
トランザクションがコミットされるまではジョブの延期を遅延するようになりましたと。
トランザクションが全部コミット終わった後にジョブを延期するようになったよと。
便利だねみたいな話をしたと思うんですが、
あのプレリクエストに関して、
あの後ですね、フィードバックのコメントがありました。
今回のプレリクエストはそれに基づく変更で、
どんなコメントがあったのかというと、
先年はアクティブジョブのジョブのパフォームレイター、
後で実行するような、非同期実行するようなやつは、
給が入れられたジョブのインスタンスを返すという動きになっていましたと。
ところが先日のプレリクエストで、
延期するのが遅延されるようになりましたと。
その先日のプレリクエストの実装的に、
返す値が変わっちゃってたんですよね。
強制的にジョブを延期するようになるという実装方法の問題で、
先週はアラウンド延期っていうブロックで括って、
いろんな処理を書いてたんで、
アラウンド延期で括ると戻る値がニルになっちゃうのかな、
っていう感じですね。
なので今まではジョブのインスタンスを返してくれてたのに、
返るようになってきちゃったと。
それは困るかもっていうことですね。
ジョブのインスタンスが返ってくることを期待して、
その後の処理とかが書かれていた可能性があって、
その場合に困りますと、困るかもしれないです、
っていうフィードバックのコメントがありましたね。
なので今回のプレリクエストでは、
それは良くないねということで、
パフォームレーターを呼んだときに返ってくる値は、
ジョブのインスタンスが返るように変更されています。
ただジョブのインスタンスが返ってくるんですけど、
実際にジョブが延期されるのは、
トランゾクションがコミットされた後なので、
例えば延期されていることを前提に書かれた処理とかは、
ActiveJobのパフォームレイターの修正
また困っちゃうわけですよね。
必要であればパフォームレーターが返すジョブのインスタンスを、
変数とかに保持しておいて、
successfully underscore enqueued はてなというメソッドがあるので、
それを使ってメソッドが延期されたかどうかを確認した上で、
いろんな処理をしてくださいね、
というようなことが書いてありましたという感じでございます。
ということかな。
というあたりで、
二つ目のプロジェクトの紹介も終わりにしたいと思います。
今週はアクティブレコードのアレルに関する変更、
ユニオンする場合の不具合の修正と、
アクティブジョブに関して、
パフォームレーターの戻ってくる値が変わってきたので、
それをジョブのインスタンスが返るように戻したよ、
という修正のお知らせでございました。
ではこんなところで、
今日のたなきゃんオンラインレース終わりにしたいと思います。
ではまた来週。
バイバイ。