RailsAdminと遊ぼう~カスタマイズ戦記~

この記事は[ウェブクルー Advent Calendar 2019](https://qiita.com/advent-calendar/2019/webcrew)の17日目の記事です。
昨日は@yagiyuuuuさんの[Nginx + uWSGI + Python(Django)の環境をdockerで作成する](https://qiita.com/yagiyuuuu/items/7d72db6c54754731855c)でした。

# この記事について
弊社は社内のデータ管理ツールに[RailsAdmin](https://github.com/sferik/rails_admin)を導入しています。
導入に関しては[こちら](https://qiita.com/da-shi/items/aa76afdea3c528a9b128)に過去のアドベントカレンダーで書かれた記事があります。
本記事は、RailsAdminを利用していく上でたまったり社内で共有されている知見や運用中に直面した問題のトラブルシューティングについて書こうと思います。

## テーブルの主キーをid以外にしたい
- シチュエーション：外部キーを主キーとしたい
- 対応：対象のモデルに下記の1行を追加

app/models/author_introduction.rb

```
  self.primary_key = :author_id
```

複合キーも試してみましたがすぐにはできなさそうなのであきらめました。
お勧めしません。

ちなみに、上記の一行を忘れるとモデルの一覧画面を開くとエラーが起きるので注意。

```
Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'desc LIMIT 20 OFFSET 0' at line 1: SELECT  `author_introductions`.* FROM `author_introductions` ORDER BY author_introductions. desc LIMIT 20 OFFSET 0
```

## データをcsvからインポートしたい
- シチュエーション：初期データを非エンジニアのユーザーが一括で入力できるようにしたい
- 対応：[rails_admin_import](https://github.com/stephskardal/rails_admin_import#installation)を導入

各ファイルに以下を追加。
Gemfile

```Gemfile
gem "rails_admin_import", "~> 2.2"
```

config/initializers/rails_admin.rb

```
  config.actions do
    all
    import
  end


  # Optional:
  # Configure global RailsAdminImport options
  config.configure_with(:import) do |config|
    config.logging = true
  end

  # Optional:
  # Configure model-specific options using standard RailsAdmin DSL
  # See https://github.com/sferik/rails_admin/wiki/Railsadmin-DSL
  config.model 'User' do
    import do
      include_all_fields
      exclude_fields :secret_token
    end
  end
```

csvのサンプル。外部キーがある場合は一行目はモデル名を記入。
なんでかエクセルで保存するときに `CSV UTF-8`を選択するとインポートに失敗するので、素直にShift-JISのcsvで保存するかエディタ使ってUTF-8のデータを作ってください。

```csv
Email, Book, Book, Book
peter.gibbons@initech.com, 9781119997870, 9780671027032
michael.bolton@initech.com, 9780446677479
```


### トラブル：インポートの動作確認がしたいのにローカルでうまく動かない
- シチュエーション：タイトルまま
- 対応①：rails 再起動
→model更新後にimportを実行するとエラーになる。対応としてサーバ再起動すればOK。
https://github.com/stephskardal/rails_admin_import#import-error-due-to-rails-class-reloading

- 対応②：development.rbの設定を変更
リクエストのたびにclassを読み込もうとすると、リクエストの処理中にインポート対象のモデルのinstanceが生成されなおしちゃう？っぽいです。
雑に流し読んだだけなので、詳しくは[こちらのISSUE](https://github.com/stephskardal/rails_admin_import/issues/88#issuecomment-455374671)をご覧ください。

```
  config.cache_classes = true
```

## 私が参照したいのはidでもnameでもない
- シチュエーション：`belongs_to` で関係づけしているテーブルの、参照元での表示を特定のカラムの値にしたい
補足：RailsAdminでは、参照先の外部テーブルの値は `name` > `id` の優先度で参照先のレコードの値が参照している子テーブルに表示される。これを別のものにしたい。
- 対応：show ブロックの中の該当fieldの設定を以下のように変更
https://github.com/sferik/rails_admin/issues/2356

initializers/rails_admin.rb

```
RailsAdmin.config do |config|
  config.model 'Book' do
    show do
      field :author do
        pretty_value do value.try(:last_name) end
      end
    end
  end
```

### Edit画面でも↑と同じことがしたい
- シチュエーション：edit画面で新規データを追加するときに、 `belongs_to` で関係づけしてるテーブルの特定のカラムを見て参照先レコードを決めたい
- 対応：editブロックに記述追加

initializers/rails_admin.rb

```
RailsAdmin.config do |config|
  config.model 'Book' do
    edit do
      field :author, :enum do
       enum do
         Author.all.collect {|a| [a.last_name, a.id]}
       end
    end
  end
```

editブロックでfieleの値をenum [['表示名', value],[],...] 見たいに与えると、画面上の該当フィールドにはdrop downが表示されるようですね。
入力できる値を制限したいときとかにも使えそう。

## モデルの一覧画面でデータを加工して表示したい
- シチュエーション： `has_one` で関連付けしてる子テーブルの値があるかないかを親テーブルの一覧画面で見たい
- 対応：親テーブルにvirtual fieldを追加

注意：悲しいことにこのやり方で表示されるデータは、ソートや絞り込みの基準としては指定できません。

app/models/author.rb

```
  # Virtual field method
  def introduced
    AuthorIntroduction.exists?(author_id: self.id)
  end
```

initializers/rails_admin.rb

```
RailsAdmin.config do |config|
  config.model Author do
    list do
      # virtual field
      configure :introduced do
      end
    end
  end
end
```

仮想フィールドはいろいろ作れそうです。
詳しくは本家の[wiki](https://github.com/sferik/rails_admin/wiki/Fields#virtual-fields)をどうぞ。


# 終わりに
サンプルコードを上げようとrailsの環境を作ってたら記事にかける時間が消えました。
~~結局実装途中なので、今度実装してそのうちこっそりここにサンプルコードのリンクを貼りたいなという面持ちです。~~
→追記　以下にサンプルコードをアップしました。
https://github.com/tsutsui-yuko/bookshelves

日本語の記事がよく出てる内容は省いて、私自身が調べるときの参照先が英語で書かれたものを今回載せてみました。
ググり力が足りないせいで日本語の記事に普通に書いてある内容だった場合はすみません。
RailsAdminはカスタマイズするのにつらみがあるという共通認識があるかなと思いますが、たくさんの人に使われているだけあって、wikiやissueを調べてみると自分がやりたいことをすでにやってる人が結構いて意外といろいろできそうです。
暇で暇で寝すぎて頭が痛くなってしまったときなどに時間つぶしとして読むと楽しいかもしれません。

「こんな機能もおすすめだよ」というものがありましたらコメントや編集リクエストなどでお知らせくださいますと私が喜びます。

明日の記事は@wc-takaharaさんです。
よろしくお願いします。