Picture of the s2terminal
s2terminal.log

あるWeb開発者のブログ

Ruby on RailsでHeadless CMSを作った

公開日:

このブログを作った時、Headless CMSとしてContentfulを使っていたけど、以下の理由でやめることにした。

  • スマホ向けエディタ画面が無い
  • 画像配信ドメインが選べない?
    • TwitterでOGPを出す時に問題になる
  • 画像の挿入がやや面倒
    • 画像もひとつのコンテンツとして厳格に管理するという考え方のため

よって10日間も使わないうちにContentfulを脱して、別のHeadless CMSを構築して移行することにした。この記事は、その新しいHeadless CMSに移行してから初めて書いた記事になる。(フロントエンドは変わっていないので見た目は同じだけど)

構成

  • Blog(※変わらず)
    • フロントエンド: Next.js
    • インフラ: Vercel
  • Headless CMS
    • バックエンド: Ruby on Rails
    • インフラ: heroku

結論から言うと、あまり良い構成ではなかったと思う。。。

Ruby on Rails

Headless CMSはRuby on Rails(以下Rails)で自前で構築した。迷ったのはStrapi等のOSSを使うかどうかだけど、一応所属している会社ではプロダクトのうち大半がRails製ということで、Headless CMSぐらいRailsで作っておこうと思った。ちなみにRubyはdocker latestで取ってきたためRuby 3.0という7年ぶりに出たメジャーバージョンアップがさっそく使えるようになったが、特にそれらしい機能は利用していない。

RailsでHeadless CMSを構築するにあたって、具体的には、Active Storage(Rails >= 5.2)Action Text(Rails >= 6.0)という、ここ数年のRailsに入った標準機能を使えば比較的かんたんに構築できるのではないか?と思った。(この目論見は外れた)

RailsにはAPIモードがあるのでHeadless CMSと相性が良さそうだけど、管理画面をscaffoldで適当に作りたいのと、特にAction Textがフロントエンド側と割と密結合で作られているのもあり、APIモード等ではなく普通の状態で作った。

Action Text

Railsでリッチテキストエディタが簡単に利用できる機能。実際にはcontenteditableを利用したエディタで、内部的にはHTMLで保存される。特にActive Storageと連携し、画像をドラッグアンドドロップやコピーアンドペーストで記事にすぐ貼り付けできるのが便利。

このAction Textは、内部でBasecamp Trix Editorというのを使っている。Trix Editorのデモページを開いて使ってみると秒で気付く重大な問題点があり、このエディタ、日本語入力に対応していない

※2021年1月17日追記: 本事象はChromeOSでのみ再現する模様

「こんにちは」とだけ入力しようとしたら、こうなる。

(もちろんGitHub上で開発されているOSSなのでContributeするのが礼儀だと思うけど)今回は対策として、なんとか機能を制限して使う方向でやってみた。 どうやら特定のリッチテキスト要素(たぶんaタグ)が入っていると日本語入力に不具合が発生するようなので、リッチテキスト要素を使わなくても済むようにした。具体的にはredcarpetを使う事でMarkdownで書けるようにした。リッチテキスト編集可能なエディタにMarkdownしか入力しないというのが、もう本来の目的を大きく見失っている。

ツールバーの太字ボタンや見出しボタンが虚しい。

heroku

インフラにはherokuを選んだ。GCPでCloudRun + CloudSQLか、AWSでLambdaContainer + AuroraServerlessの構成かで迷っていたけど、どちらもちょっと今回の要件からするとオーバースペックだな...と思った。そこで、そういえばRailsといえばherokuをよく聞くけど使ったこと無いなと思い、使ってみた。

このherokuも今回のプロジェクトと要件が悪かった。今回のプロジェクトは既成のNext.js製のフロントエンド部分があり、そこにRailsのHeadless CMSが同居する形で、monorepoのようなディレクトリの切り方をしていた。これがherokuと相性が悪かった。herokuは基本的にgitのプロジェクトルートディレクトリを参照するようで、そこに多分GemfileとかなんやかんやがあってRailsを起動できる状態じゃないとうまく行かない。起動ディレクトリを選んだりはできないみたい。

上記の問題だけであればsubtreeを使ったやり方等で回避できるけど、もうひとつ問題があった。herokuはmasterブランチかmainブランチを使うことでデプロイが走り、他のブランチ名では起動しないみたい。ところがmonorepoみたいな構成にしている別ディレクトリはmasterブランチを切られたらCI/CDが動いてしまう。普通であればdevelop等の適当なブランチをmasterで別名でpushすれば良いけど、subtreeを使っているせいかうまく行かなかった。つまりローカルではmasterブランチを使いつつorigin masterにはpushせずherokuの開発を進めなければならない。いま開発してherokuに載せようとしているAPIは後付なので、フロントエンド部分よりも先にheroku側をデプロイして動作確認してからmasterブランチでデプロイしたい。運用で回避はできるけど、ぐちゃぐちゃになってしまう。

そこでひらめいたのが、masterブランチを他ディレクトリの通常通りのCI/CDとして、mainブランチをheroku用として使い分ける事で回避した。絶対こんな使い方は想定されていない。これで、フロントエンド等が載っている本来のmasterブランチと、開発中のherokuが動くmainブランチとで分けて開発ができるようになった。mainがデフォルトブランチ名として浸透していなかったらこの回避策は使えなかったと思う。


以上でHeadless CMSが完成したけど、ここに書いていない細かい所も色々と怪しい仕様や劣化した点が多く、まだまだ未完成という感じ。特にAction Textがただの動作不安定なテキスト入力欄になっていたりするので、これは早く直したいと思う。

なおContentfulからRailsへのデータ移管は、記事3件しかないので手作業のコピペで行った。Contentfulにはnpmもgemもライブラリがあるので、移行用スクリプトを書こうと思えば比較的簡単に書けると思う。