Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

Railsの技: パンくずリストをgemなしで実装する(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

日本語タイトルは内容に即したものにしました。

Railsの技: パンくずリストをgemなしで実装する(翻訳)

パンくずリスト(breadcrumbs)は、多くのアプリケーションでよく用いられるUIパターンのひとつです。Railsにはパンくずリストのためのツールは特に組み込まれておらず、以下のように既存の便利なパンくずリスト用gemもいろいろあります。

fnando/breadcrumbs - GitHub

piotrmurach/loaf - GitHub

lassebunk/gretel - GitHub

zachinglis/crummy - GitHub

weppos/breadcrumbs_on_rails - GitHub

このぐらいの機能なら、わずか数行のコードを手書きすれば自分のアプリでも簡単に実装できると思います。

おそらく最終的にはパンくずリストの表示方法を完全に制御したくなるでしょうから、この機能を自分で実装してコードを掌握しておく方がよいでしょう。

方法

最初にBreadcrumbモデルをapp/modelsディレクトリに追加します。ただしデータベースへの永続化は不要なので、Active Recordモデルにする必要はありません。

class Breadcrumb
  attr_reader :name, :path

  def initialize(name, path)
    @name = name
    @path = path
  end

  def link?
    @path.present?
  end
end

次に、パンくずリストを保存および追加するメソッドをApplicationControllerに追加します。

class ApplicationController < ActionController::Base
  ...

  helper_method :breadcrumbs

  def breadcrumbs
    @breadcrumbs ||= []
  end

  def add_breadcrumb(name, path = nil)
    breadcrumbs << Breadcrumb.new(name, path)
  end
end

続いて、アプリケーションのビューレイアウトでパンくずリストを好みの方法でレンダリングします。私の場合は、パンくずリストを<head>タグの<title>タグとページヘッダーの両方に表示しています。

<head>
  <title>
    <%= breadcrumbs.map(&:name).reverse.append("My App").join(" | ") %>
  </title>
</head>

<nav>
  <ol class="breadcrumbs">
    <% breadcrumbs.each do |crumb| %>
     <li>
      <% if crumb.link? %>
        <%= link_to crumb.name, crumb.path, class: "breadcrumb-link" %>
      <% else %>
        <span class="breadcrumb-page">
          <%= crumb.name %>
        </span>
      <% end %>

      <% unless crumb == breadcrumbs.last %>
        <span class="breadcrumb-separator">/</span>
      <% end %>
     </li>
    <% end %>
  </ol>
</nav>

このAPIはシンプルですが、このモデルを使うことでどのコントローラにもパンくずリストを追加できます。パンくずリストをリンク化したい場合は、pathも指定できます。

パンくずリストはbefore_actionsや各アクションにセットアップできます。パンくずリストを表示する条件も普通のRubyコードで追加できます。

class PostsController < ApplicationController
  before_action :set_breadcrumbs

  def index
    @posts = Post.all
  end

  def show
    @post = Post.find(params[:id])

    add_breadcrumb(@post.title, @post)
  end

  def new
    @post = Post.new

    add_breadcrumb("New Post")
  end

  private

  def set_breadcrumbs
    add_breadcrumb("Admin", admin_home_path) if Current.user.admin?
    add_breadcrumb("Posts", posts_path)
  end
end

「セクシーなコードでしょうか?」いいえ。「退屈なコードでしょうか?」そうですね。「うまく動きますか?」もちろん!

関連記事

Railsの技: Active Recordバリデーションをコンテキストに応じて実行する(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。