食べログのようなメニューをRailsで再現しようとして、どんな方法が良いのか悩みました。結論はないけれど、どんな方法で実現するのがいいのか?考えてみました
前提:したいこと
- 例えば、口コミ一覧と口コミの詳細ページは
- 現在地表示をしたい(CSSのclass名に
current
とか入れたい) - 現在地は、リンクを外したい(食べログはリンクになってますけれど...)
- 口コミ数が0件だったら、非リンクにしたい
- 現在地表示をしたい(CSSのclass名に
- 環境はRuby on Rails 4.2
ルーティング
Rails.application.routes.draw do
resources :shops do
resources :accesses
resources :official_photos
resources :photos
resources :reviews
end
end
実現方法
current_page? を使う
current_page?
を使うと、controller名や、cotroller + action名など細かい指定で、アクセスしているページ(current page)が想定通りか判別してくれます。
課題
課題なのは、/shops/:shop_id/photos/:photo_id
のようなURLの指定が難しいこと。というか、諦めた。
ソース
%ul.menu
%li
.menu_item
- unless current_page?(shop_path(@shop))
= link_to '店舗', @shop
- else
店舗
%li
.menu_item
- unless current_page?(shop_reviews_path(@shop))
= link_to '口コミ', shop_reviews_path(@shop)
- else
口コミ
%li
.menu_item
- unless current_page?(shop_photos_path(@shop))
= link_to '写真', shop_photos_path(@shop)
- else
写真
request.path から判定する
helperを用意して、request.path
に指定した文字列が含まれているか判別するようにしてみました
/shops/:shop_id/photos/:photo_id
のようなURLについても判別できるようになりました
課題
- なんかコレジャナイ感...
-
photo
とoffcial-photo
があったら、判定方法を変えないといけない -
request.path.include?(string.to_s)
というのがいけてない気がする。あまりないかもしれないけれど、routes.rbを変えたらどうなるの? - routes.rbで、
resources
は何か決まっているので、そこで判断してはどうだろう?
ソース
%ul.menu
%li
.menu_item
- unless current_page?(shop_path(@shop))
= link_to '店舗', @shop
- else
店舗
%li
.menu_item
- unless request_path_include?('reviews')
= link_to '口コミ', shop_reviews_path(@shop)
- else
口コミ
%li
.menu_item
- unless request_path_include?('photos')
= link_to '写真', shop_photos_path(@shop)
- else
写真
helperを用意
app/helpers/application_helper.rb
module ApplicationHelper
def request_path_include?(string)
request.path.include?(string.to_s)
end
end
link_to_if_with_block を使う
課題はあるままだけれど、テンプレートで同じことを書いているので1回で書けるようにしてみた
課題
- 課題は残っている
- url_for() を調べたらまだ何か別な方法がありそう
ソース
%ul.menu
%li
- shop_menu = current_page?(shop_path(@shop))
.menu_item{style: shop_menu ? "color: red;" : ""}
= link_to_if_with_block !shop_menu, @shop do
店舗
%li
- reviews_menu = request_path_include?('reviews')
.menu_item{style: reviews_menu ? "color: red;" : ""}
= link_to_if_with_block !reviews_menu, shop_reviews_path(@shop) do
口コミ
%li
- phtos_menu = request_path_include?('photos')
.menu_item{style: phtos_menu ? "color: red;" : ""}
= link_to_if_with_block !phtos_menu, shop_photos_path(@shop) do
写真
app/helpers/application_helper.rb
module ApplicationHelper
def request_path_include?(string)
request.path.include?(string.to_s)
end
def link_to_if_with_block(condition, options = nil, html_options = nil, &block)
if condition
link_to(options, html_options, &block)
else
capture(&block)
end
end
end
まとめ?
contrller 名で判別してしまう方が、すっきりするかなあ?と思ったのですが、A/BテストなどでControllerを入れ替えてしまう、ということをすると適用できないと思います。
現在のURLから判別するのは、URLが変化しない、という前提があるからだけれど、かっこ悪さを感じるのは何故なんだろう?
どんな方法が他にあるか、聞いてみたい