ActiveAdminのscope名は日語でベタ書きしてはいけない


TL;DR

ActiveAdminのscope名に日本語を使いたいときは、横着せずに config/locales/ja.yml に設定する。

問題

ActiveAdminを使っていて、scope名を日本語でベタ書きしていたら、表示されているscopeがなんだか足りない。
サンプルとして、ユーザーを登録年月別に表示したい場合を考える

hogehoge_admin/user.rb
ActiveAdmin.register User do

##### 略 #####

  scope("2014年前半登録") { |scope| scope.where("created_at BETWEEN '2014-01-01' AND '2014-05-31'") }
  scope("2014年後半登録") { |scope| scope.where("created_at BETWEEN '2014-06-01' AND '2014-12-31'") }
  scope("2015年前半登録") { |scope| scope.where("created_at BETWEEN '2015-01-01' AND '2015-05-31'") }
  scope("2015年後半登録", default: true) { |scope| scope.where("created_at BETWEEN '2015-06-01' AND '2015-12-31'") }
  scope :all

##### 略 #####

end

こう書くと、

こうなる。

原因

gemの中身を読んで探ってみる。

active_admin/scope.rb
module ActiveAdmin
  class Scope

##### 略 ######

    def initialize(name, method = nil, options = {}, &block)
      @name, @scope_method = name, method.try(:to_sym)

      if name.is_a? Proc
        raise "A string/symbol is required as the second argument if your label is a proc." unless method
        @id = ActiveAdmin::Dependency.rails.parameterize method.to_s
      else
        @scope_method ||= name.to_sym
        @id = ActiveAdmin::Dependency.rails.parameterize name.to_s
      end

      @scope_method               = nil        if @scope_method == :all
      @scope_method, @scope_block = nil, block if block_given?

      @show_count       = options.fetch(:show_count, true)
      @display_if_block = options[:if]      || proc{ true }
      @default_block    = options[:default] || proc{ false }
    end

##### 略 ######

  end
end

scope の引数に name, method, optionと、block が渡されている。
今回関係ありそうなのは name なので、その動きを追ってみると、

@id = ActiveAdmin::Dependency.rails.parameterize name.to_s

とあるように、 nameparameterize したものを、 scopeid としているらしい。
……怪しい。のでconsoleで試してみる。

[1] pry(main)> "2014年前半登録".parameterize
=> "2014"
[2] pry(main)> "2014年後半登録".parameterize
=> "2014"

これだー!
どうやら parameterize に日本語を渡していたのが問題だった様子。

解決策

ベタ書きせずに config/locales/ja.yml に設定を書く。

hogehoge_admin/user.rb
ActiveAdmin.register User do

  scope(:early_2014) { |scope| scope.where("created_at BETWEEN '2014-01-01' AND '2014-05-31'") }
  scope(:later_2014) { |scope| scope.where("created_at BETWEEN '2014-06-01' AND '2014-12-31'") }
  scope(:early_2015) { |scope| scope.where("created_at BETWEEN '2015-01-01' AND '2015-05-31'") }
  scope(:later_2015, default: true) { |scope| scope.where("created_at BETWEEN '2015-06-01' AND '2015-12-31'") }
  scope :all

end
config/locales/ja.yml
active_admin:
    scopes:
      all: すべて
      early_2014: 2014年前半登録
      later_2014: 2014年後半登録
      early_2015: 2015年前半登録
      later_2015: 2015年後半登録

雑感

ベタ打ちしないとか当たり前なんだけど、ActiveAdminのドキュメントに

scope :all, default: true

# assumes the model has a scope called ':active'
scope :active

# renames model scope ':leaves' to ':subcategories'
scope "Subcategories", :leaves

# Dynamic scope name
scope ->{ Date.today.strftime '%A' }, :published_today

# custom scope not defined on the model
scope("Inactive") { |scope| scope.where(active: false) }

# conditionally show a custom controller scope
scope "Published", if: proc { current_admin_user.can? :manage, Posts } do |posts|
  posts.published
end

っていうような例があったから甘えてしまった。
日本語対応は丁寧にやろうな。

参考