rails generate コマンドを簡単に組み立てられるサービスをリリースしました【個人開発】

Rails エンジニアのための開発支援ツール [rails-generate.com](https://rails-generate.com/) をリリースしました。フォームを埋めていくだけで簡単に rails generate コマンドを組み立てることができます。

https://rails-generate.com/

## Model

[rails generate model](https://rails-generate.com/) はこんな感じです。カラム名、型、インデックスの有無や種類を入力すると下部に表示されている rails generate コマンドがリアルタイムで組み立てられていきます。

![model.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39972/92de51bd-5355-cda9-4a87-71cf5714cbfa.gif)

## Controller

[rails generate controller](https://rails-generate.com/controller) もサポートしています。Rails 標準の7つの RESTful アクションの選択に加えて、独自のアクションも追加できるようになっています。

![controller.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39972/9d0ea249-78dc-cfc4-8b9a-d2ed7c4b0fe8.gif)

また、[rails generate scaffold もサポートしています](https://rails-generate.com/scaffold) が、rails generate model と大部分の説明が重複するためここでは紹介を省きます。ぜひ実際に触ってみてください。

## 開発の経緯

- 覚えられない
  - DB カラムの型など
  - 7種類の action の名前など
  - オプションなど
- タイポしがち
  - `references` とかのスペルが覚えられない
- `name:string` と書くところを `string:name` って逆に書いてて後から気づく

今までは Evernote に保存してある個人的なメモ書きを見ながらコマンドを組み立てていましたが、毎度毎度、面倒なのでサービスを作ってみました。

## 主な機能

主要な機能の紹介していきます。

### バリデーション

モデル名なのに複数形だったり、コントローラー名なのに単数形だった場合、警告が表示されます。

#### モデル名に複数形が入力された場合

![validation-model.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39972/65cddb87-7db0-931e-3aae-10332b419924.gif)

#### コントローラー名に単数形が入力された場合

![validation-controller.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39972/38e1fb68-f024-9ae7-5161-06bb955f4628.gif)

このバリデーションの実装には [pluralize](https://www.npmjs.com/package/pluralize) という npm package を使用しました（詳細は後述）。

### 詳細設定

`rails generate` には指定できるオプションが多数あります。「詳細設定を表示」をクリックすると、これらのオプションを指定できます。

![advanced-options.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39972/9e3aca67-b98b-5b16-e239-fbcfdbdfda22.gif)

これは Model の例ですが、Controller や Scaffold にも同様の詳細設定を実装しました。同様にオプションの指定ができるようになっています。

### 修飾子の指定

[polymorphic, precision, scale, limit などの修飾子](https://railsguides.jp/active_record_migrations.html#%E4%BF%AE%E9%A3%BE%E5%AD%90%E3%82%92%E6%B8%A1%E3%81%99) を指定することができます。

#### polymorphic

データ型として `references` を選択した場合、 [polymorphic](https://railsguides.jp/active_record_migrations.html#%E4%BF%AE%E9%A3%BE%E5%AD%90%E3%82%92%E6%B8%A1%E3%81%99) のチェックボックスが表示されます。

![Screen Shot 2022-10-31 at 0.06.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39972/bf680c0f-f76c-768d-a359-cf89581d8756.png)

#### precision, scale

データ型として `decimal` を選択した場合、 [precision と scale](https://railsguides.jp/active_record_migrations.html#%E3%82%AB%E3%83%A9%E3%83%A0%E4%BF%AE%E9%A3%BE%E5%AD%90) を指定できます。

![Screen Shot 2022-10-31 at 0.05.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39972/9d9962e6-7508-aa73-2efa-db98caf18826.png)

#### limit

データ型として `integer`, `string`, `text` または `binary` を選択したうえで詳細設定を表示した場合、 [limit](https://railsguides.jp/active_record_migrations.html#%E3%82%AB%E3%83%A9%E3%83%A0%E4%BF%AE%E9%A3%BE%E5%AD%90) を指定できます。

![Screen Shot 2022-10-31 at 0.07.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39972/1b89d873-507b-8837-d80d-d4b52ee52793.png)


### 多言語対応

現状、日本語版と英語版があります。

![i18n.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39972/b2863f2d-0fb0-6bd2-1b19-4697ce29c005.gif)

- ブラウザのロケール `navigator.language` をもとに言語設定を判定
- 手動で言語設定を切り替えた場合はそちらを優先

言語設定は localstorage に設定を記録しているので、一度入力すれば次からはブラウザが覚えていて再度切り替える必要はありません。この多言語対応の実装には [react-i18next と i18next](https://react.i18next.com/guides/quick-start#install-needed-dependencies) という npm package を使用しました（詳細は後述）。

## 実装予定の機能

- rails generate migration
- rails new

Migration は個人的に一番欲しい機能です（仕事で `rails g migration` を使用する機会が頻繁にあるため）。

rails new のオプションを組み立てるのも手動では面倒なので、是非対応しようと思っています。rails new は、Rails 本体に [rails new cool_app --interactive by hahmed · Pull Request #39444 · rails/rails](https://github.com/rails/rails/pull/39444) というプルリクが上がっていて、このプルリクがマージされれば interactive に rails new のオプションを指定できるようになるので、この機能が Rails 本体に実装されるのであれば不要かなと思っていたんですが、既に一年以上放置されていて、いっこうにマージされる気配がないので、rails new も実装しようと思っています。

## 使用技術

本当は [Stimulus](https://stimulus.hotwired.dev/) を使いたかったんですが、特にバックエンドは必要なさそうだったのと、フロントは React のほうが慣れているので今回は React で書きました。

- Next.js
- React
- Vercel
- TypeScript
- Material UI

Next.js と Vercel は今回はじめて使ったんですが簡単でした。

Material UI は提供されているコンポーネントが非常に豊富なのと、Tailwind UI と違って無料なので採用しました。Material UI を使用すると、[rails-generate.com](https://rails-generate.com/) を見れば分かると思うんですがクールな印象のデザインになってしまうのですが、もっと可愛い・親しみのわく印象のサイトを作りたい場合などであれば Tailwind UI 等のほうが良いかもしれないです。[rails-generate.com](https://rails-generate.com/) にはクールなデザインがあっていると思ったので今回は Material UI を採用しました。

## 開発の感想

React がとても便利でした。フォームの入力値に "反応" してコマンドを組み立てて表示する、という処理が Virtual DOM に適していて、実 DOM でこれと同じことをしようと思うと状態管理が大変だと思います。こういった処理を jQuery 等で普通に実装しようと思うと状態管理のための分岐が複雑になって、バグが頻発しそうです。もし自分が実 DOM だけで同じようなものを実装することになったとしたら、Array や Object で状態を管理して、それを View に反映するような、簡易的な Virtual DOM のようなレイヤーを自前で実装すると思います。React を使うだけで同様のことが手軽にできて便利ですね。技術の進歩を感じました。

## 苦労したポイント

CSS が苦手で、スタイルをあてるのに一番苦労しました。コマンドを表示している領域を画面の下部に固定に固定するために Flexbox を使用していて、上部に `flex: 1` を指定することで実現しているんですが、[iOS の Safari では 100vh がビューポートの高さではない](https://coliss.com/articles/build-websites/operation/css/large-small-dynamic-viewports.html) という問題があり、一方で [dvh は一部のブラウザでは未だにサポートされておらず](https://caniuse.com/viewport-unit-variants)、結局、ブラウザを判定して dvh と vh を動的に切り替えることで対応しました。ブラウザの差異で苦しむのはしんどいですね。。

![footer.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39972/c2ab5376-0ce9-383c-5086-81a0329fab37.gif)

## Rails コントリビューション

[rails-generate.com](https://rails-generate.com/) を開発する過程で、rails generate コマンドの一部のオプションの説明文が雑な文章になっているところを見つけて、Rails コントリビューションのネタを拾うことができました。

- [The description of `--api` option doesn't make sense by ttanimichi · Pull Request #45938 · rails/rails](https://github.com/rails/rails/pull/45938)
- [The description of `force_plural` doesn't make sense by ttanimichi · Pull Request #45936 · rails/rails](https://github.com/rails/rails/pull/45936)

文言の修正をプルリクすると、ネイティブに英文を推敲してもられるのも良いですね。良い勉強になりました。

## 最後に

SNS や会社の Slack で共有して貰えると嬉しいです！特に初心者の方には重宝して貰えるんじゃないでしょうか。