【Rails】検索フォームで、ひらがな・カタカナ・漢字の区別なく検索（精度は100%ではないよ）


自分がPFとして作っているアプリに検索フォームを実装しました。
ただ、【rails 検索　フォーム】 とかで検索すると、部分一致や完全一致が多く出てきます。
なんとかして漢字の部分をひらがなやカタカナで検索できないかな、と思いやってみました。

流れとしては、動画のタイトルを保存する時に、そのタイトルをローマ字に変換して専用のカラムに保存し、検索するときも検索ワードをローマ字に変換して専用のカラムと参照する、という感じです。
最初は検索する時にタイトルを全部変換しようかと思いましたが、動画が増えると時間がかかりそうだな・・・と思ったので上記の方法にしました。

如何せん初学者なので、そんな冗長なことしなくてもみたいな部分はあるのと思いますが、忘備録の意味合いも込めて書くので大目に見てやって下さい。

### 参考にしたサイト

- [ひらがな-カタカナ-漢字-ローマ字を変換するgemつくったよ](https://qiita.com/isy/items/b850d67a499e38179d3e)
- [Web上のコンテンツや入力情報などが、英語か日本語か判別したいときのメモ](https://qiita.com/okappy/items/65f9612ee29c0b0c8cef)
- [Rubyの正規表現の使い方をマスターしよう！match/gsub](https://blog.codecamp.jp/ruby-regex)

##検索フォームを作る

検索フォーム自体は色々と記事があるので簡単に作れると思います。
自分の場合は動画の投稿サイトです。検索で、検索ワードが動画のタイトルに一致する、という検索フォームを作ります。

```/application.html.erb
      <div id="search-box">
        <%= form_tag(search_path, :method => 'get') do %>
          <div class="input-tag">
            <%= text_field_tag :search, '', placeholder: '検索', value: params[:title] %>
          </div>
          <div class="submit tag">
            <%= button_tag type: 'submit', class: 'btn btn-default' do %>
              <i class="fas fa-search"></i>
            <% end %>
          </div>
        <% end %>
      </div>
```

ルーティングを、videosコントローラーのサーチアクションに飛ばします。

``` routes.rb
  # 検索機能
  get "search" => "videos#search"
```

## コントローラーに追記していく

gemを導入します。
今回、 miyabi というgemを使いました。ひらがな〜カタカナ〜ローマ字に変換したり判定したりできるgemです。
今回使ったメソッド

```
.to_roman   #文字列をローマ字に変換
.to_kanhira #漢字が含まれた文字列をひらがなに変換
.is_hira?   #文字列がひらがなか判定
.is_kana?   #文字列がカタカナか判定
```
gemを導入したらコントローラーのcreateとsearchを書いていきます。
Videoというモデルには
user_id　title　introduction
のカラムがあり、そこにタイトルをローマ字に変換した物を保存する　conversion_title　というカラムを追加しました。

```schema.rb
  create_table "videos", force: :cascade do |t|
    t.integer "user_id"
    t.string "title"
    t.text "introduction"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "conversion_title"
  end
```

videos.controllerのcreateを作るのですが、問題が発生しました。

gem 'miyabi' では、【漢字が含まれている文字列を変換】はできるのですが、【漢字が文字列に含まれているか】は判定することができません。

rubyの持つ、正規表現で漢字が含まれているかどうかを判断します。
今回は漢字がタイトルに含まれているかどうかを調べたいので、ピンポイントで漢字だけを判定させます。

```
@video.title.match(/[一-龠々]/)
```

これで漢字が含まれているかどうか判定できます。

createで投稿された動画を保存します。

```/videos_controller.rb
  def create
    @video = Video.new(video_params)
    @video.user_id = current_user.id
    if @video.title.match(/[一-龠々]/)
      @video.conversion_title = @video.title.to_kanhira.to_roman
    elsif @video.title.is_hira? || @video.title.is_kana?
      @video.conversion_title = @video.title.to_roman
    else
      @video.conversion_title = @video.title
    end
    if @video.save
      redirect_to video_path(@video)
    else
      render :new
    end
  end

  private

  def video_params
    params.require(:video).permit(:title, :introduction, :video)
  end
```

上から順に、まず、タイトルに漢字が含まれるか判定します。
含まれていれば、タイトルをひらがなに変換した後さらにローマ字に変換して保存します。

漢字が含まれておらず、全てひらがな、カタカナの場合はローマ字に変換し保存します。

どちらにも当てはまらない場合は、ローマ字で投稿されていると判断してそのまま保存します。

searchアクションも同様に書いていきます。

```/videos_controller.rb
  def search
    word = params[:search]
    unless word.blank?
      if word.match(/[一-龠々]/)
        conversion_word = word.to_kanhira.to_roman
      elsif word.is_hira? || word.is_kana?
        conversion_word = word.to_roman
      else
        conversion_word = word
      end
    end
    @search_video = Video.search(conversion_word)
  end
```

フォームで検索されたワードを、wordに代入して、wordが入っていればローマ字に変換します。
createと同様に、上から順番に条件にあった変換をします。
もし検索ワードが何も無しで検索された場合は動画を全て返しています。

検索結果のviewはこんな感じ。

``` /videos/search.html.erb
<h2>検索結果</h2>

      <% unless @search_video.blank? %>
        <div class="row">
        <% @search_video.each do |video| %>
        
        ===== 省略 =====    
        
        <% end %>
        </div>
      <% else %>
        <p>検索結果はありません</p>
      <% end %>
  </div>
```

検索したワードに一致するものがなければ、その旨を表示するようにしてあります。
これで一通りできました。

## 完成！

実際にやってみます。

![スクリーンショット 2020-09-28 13.30.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/629679/4079b400-4097-d238-5fd3-03a2218c699d.png)

ひらがなで　"うみがめ"　と入力

![スクリーンショット 2020-09-28 13.31.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/629679/64950d3f-40b5-714d-436b-701d5c46f6db.png)

"umigame" という　conversion_title　を持っている動画を返してくれました。
（海亀のタイトルを持っている動画がたくさんありますが、これは　conversion_title　を追加する前の動画です。ご愛敬。）

ローマ字でも検索してみます。

![スクリーンショット 2020-09-28 14.38.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/629679/c0f29027-cdb4-5da0-233b-73106379da6a.png)

![スクリーンショット 2020-09-28 14.38.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/629679/35236f0c-0fd4-c915-812a-fd91b2352482.png)

表示されました。

## その他

テストをしながら、ブラウザバック等が入るとパラメーターの動きが変わるのか、全ての動画が読まれたりというとが発生します。
多分キャッシュとかなんだろうな...JSも勉強しないとなぁ...と思うところであります。

漢字に関しては、タイトルにもありますが１００％完璧に変換してくれる訳ではないようです。
（実際、 "最強" という文字が "saikiu" と変換されていました）
ちょっとした検索を作りたい時などに利用できるかと思います。

もっといい方法があれば、ぜひお願いします。