Deployボタンの実装
今日はRailsで実装しているAPI側のおはなしです。
APIを経由してEleventyがサイトをビルドできるようになったのですが、任意のタイミングでNetlify側にビルドさせるようにする必要がありました。 Netlifyでビルドを開始するにはWebhookを送信すればいいのでビルドそのものは簡単です。 ビルドには投稿や個別のページだけでなく、ページ上部のナビゲーションと一覧に何件表示するかとかといったブログの設定も含まれています。 そのためビルドは各モデルを更新時ではなく、数時間おきに更新されたかどうかを調べてからビルドをするようにしました。
こういった仕組み自体の計画や実装はそこまで難しいわけでもないのですが、実装にそこそこ時間がかかってしまいました。 何が大変だったかというと「Deployボタン」の実装です。 具体的にはユーザーがログインしたら常にページの右上に表示されているのですが、ビルドが可能なときだけボタンを押せるようにしました。 NodejsやReactからRailsの世界に戻ってきたので、それぞれのDOMが独立しています。
まず考えられる簡単なボタンを表示します:
<%= button_to 'Deploy Site', build_queues_path, remote: true %>
Rails UJSの機能で:remote => true
を指定するとサーバーにAJAXを送信できるようになります。
しかし、送信後にこのDOMを更新するにはどうしたら良いのだろうかと悩みました。
Rails 5までならjQueryを使ってIDをもとにHTMLごと置き換えればよかったはずです。
当然Rails 6になってもjQueryを使い続けるのは意味がないため残念ながらこの方法は諦めました。
今になってRails UJSのイベントを調べてレスポンスを置き換えたりなどと流れはイメージできるものの、実際の実装までは至りませんでした。
Rails 6からはWebpackerがデフォルトでゴリ押しでインストールされるようになったので、VueやReact、Stimulusあたりのフレームワークを使うことはおそらく避けられないと思っています。
ただ現時点では単にクラスとdisabled
要素を切り替えるのに果たしてそれらのフレームワークは必要でしょうか。
今朝はStimulusのチュートリアル動画などを見て情報を集めたつもりでしたが、まだ現時点では採用できていません。
もともとVueやReactはRailsと独立させて利用するつもりだったので、どうもWebpackerの考え方に馴染んでいません。
Rails 5の頃に比べるとrails s
でwebpack-dev-serverが起動してくれるようになったので抵抗は減りましたけれども。
最終的にはボタンを更新するのはTurbolinksが頑張ってくれるだろうという期待を込めてそのまま書きました。
<%= button_to 'Deploy Site', build_queues_path, params: { redirect_to: url_for(only_path: true) } %>
View側で現在のURLをそのままサーバーに送信して、リダイレクトする方式です。 Controller側はこうなりました:
class BuildQueuesController < ApplicationController
def create
SendBuildHookJob.perform_later({ user_id: current_user.id }) if current_user.build_queues?
begin
uri = URI(params[:redirect_to])
redirect_to uri.path, only_path: true
rescue ArgumentError
redirect_to root_path, only_path: true
end
end
end
さすがにパラメータの値をそのままリダイレクトさせちゃうのは危険なのでパスを抜き出しました。 ホスト側は書き換えられるのを防ぐことはできていますが、パスは素通りしちゃいます。 正規表現とかも大変そうだし、controllerとactionを渡す方法も考えましたが、考えれば考えるほど複雑になりそうだったので諦めました。 現時点ではユーザーが新規登録できないし、自分で使うだけなら妥協できるかなということでこのような形になっていますが、中途半端感は否めません。
これでようやくずっとやりたかった動的サイトと静的サイトのいいところを組み合わせるという発想が実現できたので、しばらくはこれでブログの更新を頑張っていけたらいいなと思っています。