下記でいつもやってるパンくずリストの表示方法についてご紹介しました。

いつもrailsで使ってるパンくずのコード - komagataのブログ

しかし弟が、

「ブログにかけるぐらい決まりきってるんだったらgemにすればいいじゃん。馬鹿なの?」

というのでgemにしました。

komagata/pankuzu: Generate breadcrumbs simply.

Dr. 林「まさかとは思いますが、この『弟』とは、あなたの想像上の存在にすぎないのではないでしょうか。」

使い方

ほとんど以前説明したままですが、

$ rails generate pankuzu:install

app/views/application/_breadcrumbs.html.erbを生成するようになっています。

最後のパンくずにもリンクを貼るようにしたのは、Googleが推奨してる方法がそうだからです。

microdataやjson+ld対応については僕が仕事でよくやるログイン必須サイトでは要らないし、上記テンプレを各自修正した方が楽だと思うのでやってません。

好みのgemが無いのでいつも書いてるヤツをご紹介します。gemにすると仰々しくなりそうでしない。

使い方

例えば、

トップページ > ブランド一覧 > ブランド個別 > モデル個別 > グレード個別

のような構造になってる車のサイトのグレード個別ページの場合。

indexやshowのviewの上の方に書く。(設定ファイルやcontrollerに書くやり方は好かん)

リンク文字とURLをadd_breadcrumbする。

- add_breadcrumb "全てのブランド", brands_path
- add_breadcrumb @grade.model.brand.name, @grade.model.brand
- add_breadcrumb @grade.model.name, @grade.model
- add_breadcrumb @grade.name, @grade

(ビューの色々)

最後のパンくずはリンク無しになります。 トップページはいつもHOMEかつroot_pathなので決め打ちです。

見た目はこんな感じになります。

https://gyazo.com/18c6e5b5e46fd324c0383c1979d81f7a

HTMLはこんな感じになります。

<ol class="breadcrumbs">
  <li class="breadcrumb"><a href="/">HOME</a></li>
  <li class="breadcrumb"><a href="/brands">全てのブランド</a></li>
  <li class="breadcrumb"><a href="/brands/455594730">メルセデス・ベンツ</a></li>
  <li class="breadcrumb"><a href="/models/64350864">Aクラス</a></li>
  <li class="breadcrumb">A 180</li>
</ol>

実装

実装は下記2ファイルです。いつもこれを前のプロジェクトからコピーしてます。

パーシャルファイルのマークアップは毎プロジェクト変わりますが、helperの方はずいぶん前から変わってない。

# app/helpers/breadcrumbs_helper.rb:
module BreadcrumbsHelper
  def add_breadcrumb(name, path)
    unless @_breadcrumbs
      @_breadcrumbs = [OpenStruct.new(name: "HOME", path: root_path)]
    end

    if @_breadcrumbs
      @_breadcrumbs << OpenStruct.new(name: name, path: path)
    end
  end

  def breadcrumbs
    @_breadcrumbs
  end
end
# app/views/application/_breadcrumbs.html.slim:
- if breadcrumbs.present?
  ol.breadcrumbs
    - breadcrumbs.each do |breadcrumb|
      li.breadcrumb
        - if breadcrumbs.last != breadcrumb
          = link_to breadcrumb.name, breadcrumb.path
        - else
          = breadcrumb.name

使用感

意識低い感じですが、僕としては以前はパンくずごときでイライラしてたのでこのゆるい実装が心地よいです。

リリース前はHerokuであっても公開したくないお客様も多いのでいつも書くやつ。

class ApplicationController < ActionController::Base
  http_basic_authenticate_with name: "user", password: ENV["BASIC_AUTH_PASSWORD"] if Rails.env.production? || Rails.env.staging?
end

全てのrailsアプリに入れてるmeta-tags gemですが、デフォルトでmeta keywordsの中身を小文字にします。

日本語的には(Aクラス → aクラスなど)小文字にされると困るので、必ず下記を設定。

# config/initializers/meta_tags.rb:
MetaTags.configure do |config|
  config.keywords_lowercase = false
end

この設定最近のバージョンで追加されたようなので皆さんチェックしてみてください。

class UsersController < ApplicationController
  ...

  def user_params
    params.require(:user).permit(
      :email,
      :first_name,
      :last_name,
      :first_name_kana,
      :last_name_kana,
      :profile
    )
  end
end

こんな風にpermitするparameterがたくさんある時、

class UsersController < ApplicationController
  ...

  def user_params
    params.require(:user).permit(%i(
      email
      first_name
      last_name
      first_name_kana
      last_name_kana
      profile
    ))
  end
end

こう書くと増減した時のメンテが楽。

概要

テスト用のfixturesとseedデータを$ rails db:fixtures:loadを使うことによって共通化する方法です。

やり方

db/seed.rbにこう書く。

# db/seed.rb:
Rake::Task["db:fixtures:load"].execute

メリット

  • seedとfixturesがDRYになる。
  • テスト時のデータが画面から見える。
  • テストに使っているエッジケースのデータを普段から意識するようになる。

Q&A

Q. factory_girlの場合は?

A. factory_girlは素人にはおすすめできない。まずはRailsデフォルトのfixturesを使いこなしましょう。

Q. seed-fuは?

A. 窓から捨てましょう。

Q. 画像ファイルがseedに必要な場合は?

A. 良い質問です。こちらを参考にしてください。

db:fixtures:loadの後処理をする - komagataのブログ

よくある下記のようなアカウント編集ページをdeviseで作る場合。

https://gyazo.com/e7b9fc1bbc0df4ccc501d3d861e76e58

  • パスワードとパスワード(確認)を入力した場合はパスワードを更新。
  • パスワードを入力しなくても他の項目(emailなど)は更新可能。

こんな感じでresource.update_without_passwordを使い分ければOK。

# app/controllers/registrations_controller.rb:
class RegistrationsController < Devise::RegistrationsController
  protected
    def update_resource(resource, params)
      if params[:password].present? && params[:password_confirmation].present?
        resource.update_attributes(params)
      else
        resource.update_without_password(params)
      end
    end
end

簡単だけどdeviseのWikiには載ってないようなので。

現状、HTMLメールでsvgを使うのは辞めたほうが良さそうです。

https://gyazo.com/19e4e37f18ef7c7dce11c01925c9ecbf

なぜなら、Gmailはセキュリティのために画像などの外部リソースを専用のプロクシ的なもの経由で表示しますが、svgは表示させてくれないようです。

Hotmailなどの他の直接表示する系サービスは問題ないです。

とりあえず、pngを使うことで回避。

svgの方が軽さとか汎用性とかいろいろ便利なんで使いたいんですけどね。

db:fixtures:loadを使えばseed-fuなどを使った場合に起きるseedデータとテストデータの二度書きの手間無くなります。

しかし、paperclipで画像を保存してる時など、fixturesからは読み込めないものを保存している場合に対応できません。

僕は下記のようにして解決しています。

rakeタスクを書く

db:image:loadという画像をアップするtaskを書く。

# lib/tasks/fixtures.rake:

namespace :db do
  namespace :images do
    desc "Upload images."
    task load: :"db:fixtures:load" do
      User.all.each do |user|
        path = Rails.root.join("test", "fixtures", "files", "users", "avatars", "#{user.name}.jpg")
        user.update!(avatar: open(path)) if File.exist?(path)
      end
    end
  end
end

db:fixtures:loadの後に実行する

# lib/tasks/fixtures.rake:

...

Rake::Task["db:fixtures:load"].enhance do
  Rake::Task["db:images:load"].execute
end

これでrails db:fixtures:loadすればその後で画像も入ります。

PaperclipでGoogle Storageに画像を保存しているときに表示がクッソ遅い。

原因は表示するたびにファイルの存在確認のリクエストを出しているためで、1ファイルにつき200msぐらい遅くなってた。(30個の表示で計6秒遅くなってた)

対応方法は、fog_hostを設定しておけばリクエスト出さなくなるようで、普通の速度に戻りました。

config/initializers/paperclip.rb:

Paperclip::Attachment.default_options[:fog_host] = "http://#{ENV["GOOGLE_STORAGE_BUCKET_NAME"]}.storage.googleapis.com"