ネストしたリソースの問題の解決策を考えてみた
ちょうどタイミング良く@maihaさんから、@yuguiさんが 近くに来てるという情報をもらったので、 @yamazさんも交えて、ネストしたリソースを扱うコントローラの問題の答えを得るべく、ミーティングをしました。
問題の定義:
モデル層で Post has_many Comment な関係にある時に、 Commentのリストとコメント投稿フォームを含むPosts#show画面(典型的な例としてはブログの一記事表示画面)から、Commentを投稿した場合に、
- Comments#createで受け取ると、Commentのsaveに失敗した時に、Post#showを表示したいが、
redirect resource(@comment.po
すると、@comment.erst) rorsの情報がロストしてしまう。 - Posts#create_com
mentなどで受け取ると、Commentリソースの処理をPostsコントローラで行う事になって責任の範囲が不明確になり、格好が悪い。
解決策
Merbベースでコンセプトを示します。 まずは、Postsコントローラの中で、以下のような包含関係を宣言するようにします。
1 class Posts < Application 2 has_many :comments 3 end 4 5 class Admin < Applicatio n 6 has_many :comments 7 end
これにより、コントローラ同士の協調関係を、コントローラ自身が知っているという事になります。 具体的にhas_manyがやることは、以下のようなbeforeフィルターをshowアクションに対してセットする事です。
1 class Posts < Application 2 before :only => :show do 3 controller = Comment.new(request) 4 @comment = case request.method 5 when "POST"; controller ._dispatch(:create) 6 when "PUT"; controller ._dispatch(:update) 7 when "DELETE"; controller ._dispatch(:destroy) 8 end 9 end
:showアクションに対して、本来は使われない"POST", "PUT", "DELETE" の各メソッドでのリクエストがあった場合に、Commentsコントローラに処理を回します。"GET"の場合は普通にPosts#showが行われます。 Commentsコントローラ側では、メソッドの返り値としてcommentオブジェクトを返します。
1 def create(comment) 2 Comment.create(comment) 3 end
作成に失敗した場合は、@comment.er
Posts#show内のComment投稿フォームは以下のような感じで、 Post#showに対してサブミットします。
1 <%= form_for @comment, :action => resource(@post) do %> 2 <%= partial "comments/form" %> 3 <% end =%>
コンセプトなので実際に動くかどうかまだ検証してないですが、 こんな感じで良いのではないかと。
MerbだとController