QA@IT

Restfulなroutes.rb設計

3279 PV

Ruby On Railsにて開発中なのですが、Restfulなroutes.rb設計についてご質問させていただきました。

出来る限り理想的なRestfulに準拠して、routing構成にて設計をおこないたいと
考えていますが、下記の場合どのように設計するのが理想すればよろしいでしょうか。

例えば従業員管理システムを作る際、社員作成フォーム(new,create,edit,update,show,destroy,,etc)とアルバイト社員作成フォーム
を作りたい場合2通り考えられると思います。

①とてもシンプルな方法

1.従業員(member)の作成

rails g model member …

で作成します。

2.Controller作成

rails g controller jyugyoin syain_new parttime_new ….

とすれば、
syain_new,shain_edit,shain_show,parttime_new,parttime_edit,parttime_show,,,,
のようにcontroller.rbとshowにて作成していけば、問題なく作成することができるとおもいます。

問題点(だと考えられる事):Resufulな構成ではない。よりresutfulに準拠した作成方法はないものでしょうか?

② nsamespaceを使った方法

1.従業員(member)の作成(ここは変わらず)

rails g model member …

で作成します。

2.namespaceを使った作成

rails g controller jyugyoin:syain

rails g controller jyugyoin:parttime

vi routes.rb

namespace :jyugyoin do

resources syain

resources parttime

end

にてrestfulな構成にて設計することができると思います。

問題点:controllerに違和感を感じる。
jyugyoin/syain_controller.rb , jyugyoin/parttime_controller.rb
が出来て、機能が増える事にコントローラーを増やし、管理して行かないといけない。

namespaceを使わないといけないものでしょうか?もうすこし、routes.rb
を効率的に使った方法などがありそうですが、教えていただけないでしょうか。

どうぞよろしくお願い致します。

回答

あくまで私の考え方ですが、回答させていただきます。

RESTfulにするということは、操作対象となる概念を一つのリソースとして捉えて、アプリケーションの機能をそのリソースに対する単純なCRUD処理で実現できるように設計する、ということです。
これはあくまで、URLを通じてアクセスしてくる外側から見たシンプルさです。

しかし、常にindex, show, create, update, destroyだけではカバーできない事もあります。
その際も出来るだけ、対象となっているリソースを「参照する」「作成する」「更新する」「削除する」という考え方で処理できるようなメソッドにしていくのがRESTfulな設計だと思います。

一つの指針として、URLが名詞になっているかという考え方があります。CRUDに関わる動詞はHTTPメソッドとして表現できるので、RESTfulになっていれば多くの場合URLはリソースの場所を示すだけで済むはずです。

コントローラーについて

RESTfulな設計を行う場合、コントローラー数はどうしても増加する傾向になります。
操作対象によってコントローラーをしっかり分けることで、一つ一つのコントローラーは単純になり、よりモデルにロジックを書き易くなります。

とは言え、常にコントローラーを増やすのかについては議論の余地があります。
例えば、何かの一覧が欲しい時に全ての一覧と入力された文字列で検索されたパターンの両方が欲しい場合、コントローラーを増やして新しいリソースとして表現するよりも、searchというアクションを追加する方が自然なこともあります。

RESTfulな設計を行った場合、リソースとして表現するものは、必ずしもActiveRecordのモデルと1:1に対応するものではありません。
複数のテーブルをジョインした結果や、あるモデルの一部を切り出したものが一つのリソースとなる場合もあります。
それはURLを通じてアクセスするクライアントが、どの単位で情報を扱いたいのかに関わってきます。

今回の例で言うなら、従業員(Member)、社員(RegularMember),アルバイト(ParttimeMember)がリソースの候補になります。

もし、従業員全体を一つの集合として扱いたい場合があるなら、Memberというリソースを扱うコントローラーが必要です。
個別に社員とアルバイトを扱う用途が存在するなら、RegularMemberとParttimeMemberを扱うコントローラーが必要です。

URLについて

URLを表現するのに必ずしもnamespaceは必要ありません。
それもリソースがどういう扱いになるかで変化します。
社員とかアルバイトという概念が、あくまで従業員という概念の一部でしかないなら、namespaceで区切る方が自然かもしれません。

扱うリソースが増えてきた場合の対応

今回の例のように、ほぼ同じような処理が必要となる複数のリソースを扱う場合、実装が重複しないような対応策が必要になる場合があります。
最近のRailsでは、concernという考え方を用いてこれに対処するのがRailsらしいと思います。

concernは日本語だと「横断的関心事」と表現されます。

そのリソースに対してどういった処理が必要になるか、という事を「関心事」として振舞いを分離し、処理を共通化します。

例えば、従業員の検索が必要になった場合、RegularMembersControllerと、ParttimeMemmbersControllerにsearchメソッドを追加すると重複してしまいます。
そこで、Searchableのように「検索できる」という関心事に名前を付けてモジュールとして振舞いを分離します。

イメージとしては以下のような形です。

# app/controllers/concerns/searchable_resource.rb
module SearchableResource
  def search
    @searchable = searchable_model.search(params[:query])
    respond_with @searchable
  end
end

# app/controllers/regular_members_controller.rb
class RegularMembersController < ApplicationController
  include SearchableResource

  private
  def searchable_model
    RegularMember
  end
end

# app/controllers/parttime_members_controller.rb
class ParttimeMembersController < ApplicationController
  include SearchableResource

  private
  def searchable_model
    ParttimeMember
  end
end

# config/routes.rb
## 省略

concern :searchable do
  collection do
    get :search
  end
end

resources :regular_members, concerns: [:searchable]
resources :parttime_members, concerns: [:searchable]
## 省略

# モデルのメソッド呼び出しの形式も揃えておく必要があるので、モデル側にも似たようなconcernモジュールが入ることになります。

実際にはこんな綺麗にまとめられないことの方が多いですが、本当に同じ関心事を持った処理なら、このようにしてまとめていくのがRailsっぽいスタイルです。

ちなみに、routes.rbでのconcernの活用はRails4からの機能なので、利用しているRailsのバージョンに気を付けてください。

編集 履歴 (0)
ウォッチ

この質問への回答やコメントをメールでお知らせします。