こんにちは!最近子供が生まれたRailsエンジニアの鈴木( @suzan2go )です。
クラウドソーシングのクラウドワークスでは日報文化が定着しており、エンジニアだけではなく営業やコーポレートの方たちも毎日日報を書いて全社に共有しています。日報といえばesa.ioやQiita:team といった素晴らしいプロダクトがありますが、クラウドワークスではDirectoryというマークダウンで日報を書いて共有できるサービスを社内向けに公開していて、エンジニアが業務の合間の気分転換に、あるいは新技術のお試しの場として開発をしています。
今回は、このDirectoryに「GitHub, Qiita Likeなemojiサジェスト機能」を実装したお話です。
なぜやったのか?
GitHubやQiitaには:
と打つと候補のemojiをサジェストしてくれる機能がありますよね?
Directoryには長いことその機能がなかったため、普段からマークダウンを書くエンジニア以外の方にはあまりemojiが使われていませんでした。
普段マークダウンを書かない人でも気軽にemojiを使って投稿できれば、より楽しく日報をかけるはず!と思いたちカッとなって自分でemojiサジェスト機能を実装してみました。
どうやったのか
以下のOSSを使って実装しました。
- jquery-textcomplete (Qiitaのemojiサジェストにも使われているOSS!)
- gemoji (マークダウンでemojiをrenderするために必要なOSS!)
jquery-textcompleteのデモページにemojiのサジェスト機能のサンプルはありますが、これをRailsでやる場合はemojiの画像ファイルにつくdigestの値を考慮する必要があります。
色々方法は有ると思いますが、今回はemoji名で検索してヒットしたemoji名とemojiの画像パスを返すAPIを作ってサクッと対応してみました。
gemoji
gemojiとはGitHubが提供する、emoji名とそれに紐づくemojiのimageファイルを管理するライブラリです。Directoryでも使用しているマークダウンプロセッサのqiita-markdownでは、gemoijを内部で使っていてマークダウン上の :sushi:
をのような画像イメージに変換しているというわけです。
*1
gemojiにはActiveRecordでいうfind
系のメソッドは提供されているのですが、where
なメソッドは提供されていません。ですので今回やりたいLike検索的な機能は自前で作る必要があります。
そこでgemojiが提供するEmoji::Character
クラスには生えている、name
とaliases
というメソッドを使って検索するメソッドを拡張してみます。
# たとえば :+1: だったらnameは+1、aliasesは ["+1", "thumbsup"]といった感じです。 # ちなみにnameはaliases.firstのaliasだったりします。 module Emoji def start_with(name) emojis = Emoji.all.select do |emoji| emoji.aliases.any? do |_alias| _alias =~ /^#{name}/ end end emojis.sort_by{ |e| e.name } end end
できた!
pry(main)> Emoji.start_with("smile") => [#<Emoji::Character:smile(1f604)>, #<Emoji::Character:smile_cat(1f638)>, #<Emoji::Character:smiley(1f603)>, #<Emoji::Character:smiley_cat(1f63a)>]
API側はこんな感じになります。 emojiの名前と、pathを返すJSONを返します。
class Api::EmojisController < ApplicationController EMOJI_NUM_LIMIT = 10 def index @emojis = Emoji.start_with(params[:query]).first(EMOJI_NUM_LIMIT) end end
json.array!(@emojis) do |emoji| json.value emoji.name json.url image_path("emoji/#{emoji.image_filename}") end
jquery-textcomplete
ほぼサンプルコードそのままな感じですが、先ほど作ったAPIに対してリクエストを投げて、返って来たjsonで候補を作ってあげます。
$(this.refs.textarea).textcomplete([ { match: /\B:([\-+\w]*)$/, search(term, callback) { return $.getJSON("/api/emojis", { query: term }) .done( (data) => callback(data) ) .fail( () => callback([]) ) }, template(data) { return `<img src="${data.url}" class="emoji" /> ${data.value}`; }, replace(data) { return `:${data.value}:`; }, index: 1 } ])
完成
できた!
今回APIやJavaScriptはQiitaの実装をすごーく参考にさせていただきました
普段何気なく使っているものでも、実際に自分で作ってみると理解が深まりますね!
最後に
クラウドワークスではユーザー指向でサービス改善していきたいエンジニアを募集しています!