patorashのブログ

方向性はまだない

ニックネームを管理するgem imyou(異名)をリリースした

仕事で使うためにgemを作ったったという話です。

自分が担当している製品は、情報を収集して、それを集計して…みたいなことをよくやるのですが、その時の課題が『表記揺れ』だったりします。よくありますよねー。ASUSのことをどう読むのか?みたいな問題。いくら公式が『エイスース』と言っても、『エーサス』『アーサス』『アサス』などと書かれることはあるわけです。情報を収集するときに『エーサス』と書かれているものは『エイスース』として認識したい!ということですが、そのためにはニックネームを管理する仕組みが必要です。

そこで、ニックネームを管理するためのgem imyou(異名)を作りました。

github.com

gemの名前はニックネームを被りにくい日本語にしたものです。Rails 4と5に対応しています。

使い方

使い方はREADMEに書いていますが、一応説明を。

インストール

Gemfileに書いてbundle installしてください。

gem 'imyou'

マイグレーション

imyou用のテーブルを生成する必要があります。generatorを定義してあるので、それを使ってmigration用のファイルを生成して、マイグレーションしてください。

$ rails generate imyou:migration
$ rails db:migrate

Userモデル

Userモデルには、nameカラムがあるとします。

class User < ApplicationRecord
  has_imyou
end

ニックネーム検索するときの対象として、nameカラムも含めたい場合は以下のように。

class User < ApplicationRecord
  has_imyou :name
end

実際に使う

登録系

登録は、add_nicknameメソッドと、nicknames=メソッドを定義してあります。

@user = User.create(name: '孫悟空')

# ニックネームを登録
@user.add_nickname('カカロット')

# ニックネームを取得
@user.nicknames # => ['カカロット']

# ニックネームを配列で登録
@user.nicknames = %w(カカロット 孫くん ゴクウ)
@user.nicknames # => ['カカロット', '孫くん', 'ゴクウ']
削除系

削除は、remove_nicknameメソッドと、remove_all_nicknamesメソッドを定義してあります。

@user = User.create(name: '孫悟空')
@user.nicknames = %w(カカロット 孫くん ゴクウ)

# ニックネームを削除
@user.remove_nickname('孫くん')
@user.nicknames # => ['カカロット', 'ゴクウ']

# ニックネームを全て削除
@user.remove_all_nicknames
@user.nicknames # => []
検索系

検索系は、完全一致検索と、部分一致検索を定義してあります。本名(?)を検索対象にするためにオプションwith_name_columnがあり、デフォルトでtrueになっています。 もしニックネームのみを検索対象にしたい場合は、falseを設定します。

@user = User.create(name: '孫悟空')
@user.add_nickname('カカロット')

# 名前とニックネームで完全一致検索
User.match_by_nickname('孫悟空').exists? # => true
User.match_by_nickname('カカロット').exists? # => true
User.match_by_nickname('悟空').exists? # => 完全一致していないのでfalse

# 名前とニックネームで部分一致検索
User.partial_match_by_nickname('悟空').exists? # => 部分一致しているのでtrue
User.partial_match_by_nickname('カカ').exists? # => 部分一致しているのでtrue

# ニックネームのみを対象にして検索
# 完全一致検索
User.match_by_nickname('孫悟空', with_name_column: false).exists? # => ニックネームはカカロットのためfalse
User.match_by_nickname('カカロット', with_name_column: false).exists? # => true
# 部分一致検索
User.partial_match_by_nickname('悟空', with_name_column: false).exists? # => ニックネームに部分一致していないのでfalse
User.partial_match_by_nickname('カカ', with_name_column: false).exists? # => 部分一致しているのでtrue
参照系

with_nicknamesスコープを定義しているので、これを呼ぶとeager_loadが実行されるのでN+1は起きません。

@user = User.with_nicknames.first

以上です。

こんな機能があったらいいなぁとか、IssueなりPRなりお願いします!