一から勉強させてください( ̄ω ̄;)

最下級エンジニアが日々の学びをアウトプットしていくだけのブログです。

Railsでパンくずリストを実装するためにbreadcrumbs_on_railsを使ってみた

最近、Railsアプリでパンくずリストをいい感じに実装するために、breadcrumbs_on_railsというGemを使用してみました。

すでにネット上に使ってみた的な記事はちらほら見受けられましたが、自分なりにどのように使ったかなどを書いておきたいと思います。

breadcrumbs_on_railsの基本的な使い方

以下のようにController側でadd_breadcrumbメソッドを呼んでおくと、呼び出した順に@breadcrmbsに要素がセットされるようになっている。

class PostsController
  add_breadcrumb 'ホーム', :root_path
  add_breadcrumb '投稿一覧', :posts_path
  
  def index
    @posts = Post.all
  end
end

後はView側でrender_breadcrumbsメソッドを呼べば、@breadcrumbsの中身をもとにBreadcrumbsOnRails::Breadcrumbs::SimpleBuilderが要素をレンダリングしてくれるようになっている。html_safeもしてくれているし、separatorを渡すこともできる。

body
  = render_breadcrumbs, separator: '>'

でもこのレンダリングは単純にアンカーリンクを生成してERBで吐いているだけなので、やはりマークアップ自体をカスタマイズしたいという欲求が出てくる。

これはBreadcrumbsOnRails::Breadcrumbs::Builderを継承した独自Builderを定義して、そいつのrenderメソッドを実装することで出来そう。

パンくずリストマークアップをカスタマイズする

以下のようなBuilderをconfig/initializers以下に定義して、自分が使いたいテンプレートを使えるようにした。

module BreadcrumbsOnRails
  module Breadcrumbs
    class MyBuilder < Builder
      # 元々protectedで定義されているが、View側で使いたかったのでpublicにしてる
      public :compute_name, :compute_path 

      def render
        # 使いたいテンプレートのパスを指定する
        @context.render '/layouts/breadcrumbs', elements: @elements, builder: self
      end
    end
  end
end
/ Slimです
- if elements.present?
  nav
    ul
      - elements.each do |elem|
        - name = builder.compute_name elem
        - path = builder.compute_path elem
        li
          - if path.present?
            = link_to_unless_current name, path
          - else
            = name

ホームへのリンクなど、ほぼ全ての画面で必要なリンクをApplicationControllerで定義する

今回、例えば投稿詳細画面にホーム < 投稿一覧 < Awesome post!(投稿詳細)みたいなリストが表示されるようなケースを想定していて、この中のホームはホーム画面以外の全画面で必要になることが予想される。

このような処理はとりあえずApplicationControllerにホームリンク用のadd_breadcrumbを書いてしまって、パンくずリストを表示したくない画面のController内で@breadcrmbsを消し去るメソッドを呼ぶようにしてみる。

class ApplicationController < ActionController::Base
  add_breadcrumb 'Home', :root_path
  
  def remove_breadcrumbs
    @breadcrumbs = nil
  end
end
class HomeController < ApplicationController
  before_action :remove_breadcrumbs
end

Symbolで指定できないパスを指定する

root_pathのようなパスではなく、post_path(@post)のようなものを指定したい場合の話。一例として、画面設計は完全に適当だけど、ホーム < 投稿一覧 < Awesome post!(投稿詳細)< コメント一覧みたいなものをコメント一覧画面で表示したいとすると、以下のようにすれば指定できる。

module Posts
  class CommentsController
    add_breadcrumb '投稿一覧', :posts_path
    before_action :add_post_breadcrumb
    add_breadcrumb 'コメント一覧', :post_comments_path
    
    
    def index
      @comments = Comment.all
    end
    
    private
    
    def add_post_breadcrumb
      add_breadcrumb @post.title, view_context.post_path(@post)
    end
  end

まとめ

breadcrumbs_on_railsというGemは実装も小さいし、特に不満なく使えました。

実際「フルスクラッチでパンくず表示リストを表示する仕組みを実装するぞ」ってなったとしても、結局breadcrumbs_on_railsみたいな実装になってしまう気もするので、Railsパンくずリストを実装したい人はガンガン使っていけば良いのではないでしょうか。