Go to this month’s calendar
2019 / 09 / 16

ひたすらコードを書いていた

今日も昨日に引き続きひたすら日記サイトのコードを書いていた。今日もとても充実していた。

今日もいろいろいじったが、特に大きな機能実装として、sortable.js というものを導入してテンプレートの順番を入れ替えられるようにした。

フロントエンド側の実装は、ただ単にライブラリを CDN から読み込んで数行書いただけで終わったのだが、大変だったのはサーバサイドの実装だ。

順番を入れ替えられるようにあらかじめ position というカラムをテンプレートテーブルに用意していたのだが、これにはユニーク制約がかかっている。入れ替えようとしたときに、一時的にでも同じ position を持つレコードが 2 つ存在してしまうとユニーク制約違反になってしまうので、一旦別の値に変更して入れ替える必要があった。

さらに、sortable.js は単に 2 つのレコードの順番を入れ替えるような挙動ではなく、ドラッグした要素を下または上にずらすような感じなので、移動元から移動先までの間のレコードすべての position を一つひとつずらすという処理が発生した。これがいっぺんにまとめてできれば良かったのだが、先述したとおりユニーク制約がある関係上、一つひとつレコードの position の値を退避しながらずらさなければならなかった。この処理を書くのにかなり骨が折れた。

もっというと、何回かに分けてトランザクションをコミットしているので、途中で例外が発生した場合に、今までコミットしていた内容をロールバックしないと不整合が起きてしまう。その処理を書くのにも少し苦労した。なぜか ActiveRecord::Rollback の例外を捕捉できなかった。

そんなこんなで 5 〜 6 時間かけてやっと書いたのだが、案の定、クソコードになってしまった。

ユニーク制約があるカラムの値を入れ替えるというのは、アンチパターンな気もしてきた。

一応、ActiveRecord のレコードの順番を入れ替えるような RubyGems も見つけたのだが、これは順番入れ替え用に親子関係を持つテーブルをもう一つ用意して、子テーブル側で順番を保持するというものらしい。

Acts As List

本当はこういう設計にしたほうが良いのだろうが、今回は一つのテーブル内で完結させたかったので、この Gem を使わずに無理やり実装してみた。無理やり実装した今回の方法はネットで調べても全然出てこなかった。まあかなりひどいコードになってしまうような書き方しかできなかったし、仕方ないといえばそうなのかもしれない。

順番入れ替えのロジックが頭の中だけでは混乱してしまうので紙を使った。こういうときのメモ用紙(電子的なメモではないもの)はとても便利だと思った。

39790ec2a1e327f1

d94d55b877664360

だいぶ脳を使って疲れたが、やりたいことは実装できたので良かった。昨日もそうだったが、昼ごはんを食べていない。

次のデプロイをするまで実装したいことがまだまだあるのでもくもくと実装していこう。

余談だが、gist-it というサービスを使うと、こんな感じで GitHub のコードを埋め込むことができるらしい。

<script src="https://gist-it.appspot.com/github/noraworld/diary/blob/d3bb18230710f0c57e094703794024627aff7e16/app/controllers/templates_controller.rb?footer=minimal&slice=61:122"></script>

GitHub が公式で用意しているのは Gist のほうだけだったのね。