一から勉強させてください

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

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パンくずリストを実装したい人はガンガン使っていけば良いのではないでしょうか。