以下のようなネストしたルーティングを考える。
resources :publishers do
resources :books
end
んで,例えば books の一覧ページに「修正」のリンクを置くのに,ビューで
link_to "修正", edit_publisher_book_path(@publisher, @book)
とかって書くことになる。メソッド名が長えよ。
いやまあ,上の例だとモデル名が Publisher だの Book だの短いからまだかわいい。
モデル名が長かったり,namespace 使ってたりすると,
link_to "修正", edit_admin_counterpart_favorite_item_path(@counterpart, @favorite_item)
とかワケわからん。
モデルの CRUD に使うパスなんだからモデルに言われせればいいんじゃね?
ただ,モデルに直接やらせるのはおかしいので,デコレーターに定義することにする。
ActiveDecorator を使った場合,
module BookDecorator
def edit_path
edit_publisher_book_path(publisher, self)
end
end
みたいにする。(publisher
は変数ではなく self
の publisher
メソッドを呼び出してる)
これで,
link_to "修正", @book.edit_path
と書ける。
同じようにして,
module BookDecorator
def path
publisher_book_path(publisher, self)
end
end
module PublisherDecorator
def new_book_path
new_publisher_book_path(self)
end
def books_path
publisher_books_path(self)
end
end
とかも定義しておく。
ビューがスッキリする。
ただ,こういうやり方がよい流儀なのかどうか,よく分からない。
「てめえの Rails は〇〇じゃねえ!」とか叱ってくれ。
コントローラーで使う(2019-06-18 追記)
パスヘルパーはコントローラーでも多用する。
例えば特定の Publisher の Book を create したり update したりしたあと,
redirect_to publisher_book_path(@publisher, @book)
みたいに,その書籍のページにリダイレクトする,ということはよくある。
こういうとき
redirect_to @book.path
と書ければよいのだが,そういうわけにはいかない。
ビューで @book.path
と書けたのは,ActiveDecorator が裏で @book
をデコレートしてくれていたからで,この機構はビューに持ち込まれるインスタンス変数にしか働かない。
手動でデコレートするには
ActiveDecorator::Decorator.instance.decorate(@book)
とすればよい。
そこで,ApplicationRecord
に
class ApplicationRecord < ActiveRecord::Base
# 中略
def decorate
ActiveDecorator::Decorator.instance.decorate self
end
end
と書いておけば,コントローラーで
redirect_to @book.decorate.path
と書ける。
もちろん,コントローラー以外の場所でも .decorate
を使うことができる。
ビューの中で自動デコレートが効かない場合(それは良いプログラミングスタイルではないかもしれないが)にも役立つ。
2021-01-26 追記
何たる不覚。ActiveDecorator は,デコレーターをモジュールとして定義するのに,間違ってクラスにしてた。
投稿から 4 年も経って気づいたので,今さらだが直した。