Kaigi on Rails 動画(Simplicity on Rails - RDB, REST and Ruby ②)

引き続き、Simplicity on Rails - RDB, REST and Ruby を観ていく。

イベントエンティティの例として、Conference モデルと User モデルを「登録」という概念により結びつけるものならば、Registration モデルというものが考えられる。 これは、実装としては次のようなものになる。

class User < ApplicationRecord
  has_many :registrations
  has_many :conferences, through: :registrations
end

class Registration < ApplicationRecord
  belongs_to :user
  belongs_to :conference
end

発表では省略されているけれども、Conference 側にも次のような記述が必要。

class Conference < ApplicationRecord
  has_many :registrations
  has_many :users, through: :registrations
end

イベントエンティティを見出すとできることとして、次の 3 つが挙げられている。

  • registrations にカラムを追加して、付加情報をもたせられる
  • 後続イベントの親レコードにできる
  • 登録したこと自体を記録できる

1 つ目「カラムを追加して、付加情報をもたせられる」と 3 つ目「登録したこと自体を記録できる」は、言われればそうなんだけれども、もし自分がイベントエンティティのメリットを説明するように求められたなら、咄嗟に出てくるかは怪しい。 2 つ目の「後続イベントの親レコードにできる」は、パッと読んで意味が分からなかったが、説明を読んで分かった。

  • 例: 参加費用を決済したコト payments、当日に参加したコト attendances など
    • belongs_to :registration な AR モデルとなる

なるほど、こういう状態を親レコードと呼ぶのか。 後続イベント、というのは、後続のイベントエンティティのことか。 また、『AR モデル』という表現も自分の語彙にないので、納めておきたい。

なお、イベントエンティティは、命名に迷うことが多いとのこと。 registration や attendance といった動詞の名詞形を使うことが多い。

ここまで読んで、自分が開発しているプロダクトのことを考えると「もしかして、あそこって、ああした方が良かったのか?」というのが思い当たる。 ただ、ツラいのは、こういった修正はフロントエンドのリファクタリングなどとは異なり、後から施すのが難しいという点だと思う。気軽にできるイメージがない。

DB で表現したコトをユーザーが扱えるようにする

→ REST の表現を上手く適用できると、Rails が色んなことをやってくれて便利。

ここで、自分は REST とは何かを理解できていないと気付いたので、調べて自分なりの言葉でまとめてみる。 要は、CRUD を HTTP リクエストでやれるようにすること、なのではなかろうか? ちなみに、REST は Representational State Transfer の略らしいけれども、Representational State Transfer がいまいちよく分からないな。 そこで調べたところ、まず、Representational というのは、あるリソースがあるデータ形式(例えば JSON)で represent されていることを表している、とのこと。ユーザーがデータを操作する際も、そのデータ形式に則って行う。 また、Transfer というのは、クライアントとサーバーとのやりとりを意味しているとのこと。 こう表してみると、まあまあ分かった気もする。

セッションに戻る。 moro さんが REST のセクションで表したいのは、

  • コトを REST リソースとして定義し、サービスの機能をその CRUD で表現する
  • コトの操作のための状態遷移も、URL へのアクセスで表現する

こと、とのこと。 イベントエンティティを RESTful にするとはどういうことかを懇切丁寧に表現してくださっていて、自分のような Rails 初心者に優しい。 これを実現するためのルーティングを定義する手段としては、routes.rb で resourcesresource 宣言を使うのが良いだろう、昔から一貫している方法だし、とのこと。 しかし、リソースを HTTP 経由で CRUD するというマインドセットも難しい、とのこと。 ルーティング定義がたくさん生まれるから、というようなことを仰っている。 そして、集約したい気持ちになることについて、それを無駄なく使う方法をご紹介くださるとのこと。

「REST で CRUD するリソースとテーブルは、似ることもあるけれども、違いが発生するのも、それはそう。違うこと自体で悩まないで!」とのことなのだけれども、自分は具体的な例を思い浮かべられず、いまいち理解できない。

登録の URL をオシャレにネストするのをやめるともっとシンプルにできる

resources :conferences do
  resource :registration, only: [:new, :create]
end

resources :registrations

とのこと。どういう意味だろう。 これは、

登録 → create (例: POST /conferences/kaigionrails2023/registration) 内容の確認 → show 更新 → update

でできるため、resources 宣言で Rails が一気に設定してくれる、とのこと。

これに対して、REST ではないケースの例。

resources :conferences do
  # POST /conferences/:conference_id/register
  #    => conferences#register
  post :register
end

のように ConferencesController#register アクションを定義してしまうと、ルーティングが増え、controller の肥大化も招いてしまう、とのこと。 これが「REST ではない」ということは、CRUD の基本のパターンから外れているということかな? このようにアクションが増えると、偶発的な複雑さが増してしまう、とのこと。

コトを new する

最初は不要なので使わなくて良いだろう、とのこと。 例えば、カンファレンスへの登録ボタンを押せば登録完了するなら、直接 registrations#create にサブミットして良いだろう、と。 また、この resources 宣言の方法だと、ページ遷移にてリソースの状態の遷移を表現できて良いとのこと。 例えば、「登録時情報の入力待ち」という「状態」と「ページ」が対応して表現される。 ただ、これは Rails が推奨している方法であるにも関わらず、概念として難しいのであまり流行っていないとのこと。そのため、推奨する意味でご紹介なさっている様子。 次は 16:40 から。