+3

Rails gem gemoji

Gem gemoji

Emoji là các biểu tượng và hình mặt cười được sử dụng trong các tin nhắn điện tử và các trang web. Gem gemoji hỗ trợ hiển thị emoji đối với các trang web được phát triển bằng RoR. Link tham khảo: https://github.com/github/gemoji.

a. Cài đặt:

  • Thêm gem "gemoji" vào Gemfile.
gem "gemoji"
  • Chạy bundle install để cài đặt gem "gemoji".
bundle install

b. Extract images để hiển thị image cho emoji:

  • Để extract image hiển thị emoji trên web và lưu vào thư mục public/images/emoji , ta chạy câu lệnh
bundle exec gemoji extract public/images/emoji
  • Đối với các máy chạy hệ điều hành window hoặc ubuntu, ta nhận được lỗi Errno::ENOENT
  • Theo source code của gem gemoji, nguyên nhân lỗi là do hệ điều hành ubuntu và window không có file Apple Color Emoji.ttc
  • Emoji::Extractor sử dụng biến EMOJI_TTF để lưu file ttc chứa toàn bộ hình ảnh emoji của hệ điều hành.
EMOJI_TTF = "/System/Library/Fonts/Apple Color Emoji.ttc"
  • Ta có thể download file Apple Color Emoji.ttc tại đây , trong source code tham khảo có để file Apple Color Emoji.ttc tại thư mục vendor.
  • Ta cũng sửa lại source của gem gemoji tại máy sau khi đã cài đặt gem gemoji cho project.
  • Mở file gemoji/lib/emoji/extractor.rb sửa giá trị của biến EMOJI_TTF về đường dẫn của file Apple Color Emoji.ttc lưu tại thư mục vendor của project.
  • Chạy lại câu lệnh extract image.
bundle exec gemoji extract public/images/emoji
  • Image sau khi extract được lưu tại thư mục public/images/emoji của source code tham khảo.

c. EmojiHelper:

  • Xem danh sách các emoji tại đây.
  • Tạo EmojiHelper, viết hàm emojify(content) để thay thế các emoji có trong chuỗi content bằng hình ảnh tương ứng.
module EmojiHelper
  def emojify content
    h(content).to_str.gsub(/:([\w+-]+):/) do |match|
      if emoji = Emoji.find_by_alias($1)
        %(<img alt="#$1" src="#{image_path("emoji/#{emoji.image_filename}", skip_pipeline: true)}" style="vertical-align:middle" width="20" height="20" />)
      else
        match
      end
    end.html_safe if content.present?
  end
end
  • Ta tạo model post có 2 cột title và content để test hàm emojify.
rails generate scaffold post title:string content:string
  • Sau khi chạy câu lệnh scaffold, ta tạo 1 bài post có nột dung là it's raining 🐱s and 🐶s!
  • Ta gọi hàm emojify(@post.content) trong file app/views/posts/show.html.erb để hiển thị emoji có trong nội dung bài post.
  • Kết quả thu được.

d. CustomEmojiHelper:

  • Theo như file db/emoji.json thì gem gemoji chỉ support các emoji của ios có version từ 10.2 trở xuống và không hỗ trợ 1 số emoji chỉ có ở android.
  • Trong thực tế, khi user tạo bài post hoặc comment thì các ký tự emoji sẽ là các kí tự unicode chứ không phải các kí tự như trong emoji cheat sheet .
  • Tạo CustomEmojiHelper và các hàm cần thiết để giải quyết vần đề trên.
  • Ta xem file emoji/character.rb của gem emoji, các hàm image_filename(), default_image_filename(), self.hex_inspect(str), raw()add_unicode_alias(str).
  • Ta xem file lib/emoji.rb của gem emoji hàm parse_data_file() dòng 90, ta thấy emoji được tạo ra và gọi hàm add_unicode_alias(uni), uni được truyền vào là kí tự unicode ứng với emoji được lưu trong file db/emoji.json.
  • Từ các hàm trên, ta có thể thấy từ kí tự unicode của emoji, ta có thể có được tên của image file ứng với emoji đó.
  • Tiến hành cài đặt các hàm cần thiết choCustomEmojiHelper.

a. Hàm is_emoji_char?(char)

  • Xem danh sách các emoji và kí tự unicode tương ứng tại đây.
module CustomEmojiHelper
  attr_accessor :emoji_char_codepoints

  def is_emoji_char? char
    @emoji_char_codepoints ||= (0x1F600...0x1F64F).to_a +
      (0x1F300...0x1F5FF).to_a +
      (0x1F680...0x1F6FF).to_a +
      (0x2600...0x26FF).to_a +
      (0x2700...0x27BF).to_a +
      (0xFE00...0xFE0F).to_a +
      (0x1F900...0x1F9FF).to_a +
      (0x1F1E6...0x1F1FF).to_a

    @emoji_char_codepoints.include? char.codepoints.first
  end
end

b. Hàm emoji_image_url(char)

def emoji_image_url char
  providers = ["apple", "emoji-one", "emojidex", "emojipedia", "facebook", "google", "htc", "lg", "messenger", "microsoft", "mozilla", "samsung", "twitter"]
  base_url = "https://raw.githubusercontent.com/loicpirez/EmojiExtractor/master/emojipedia.org"
  image_name = char.codepoints.map { |c| c.to_s(16).rjust(4, '0') }.join('-').gsub(/-(fe0f|200d)\b/, '')
    
  providers.each do |provider|
    image_url = "#{base_url}/#{provider}/#{image_name}.png"
    return image_url if url_exists?(image_url)
  end
end

c. Hàm is_url_exists? url

  • Có 1 số emoji chỉ có cho 1 provider mà không có cho provider khác, ta cần kiểm tra emoji_image_url của emoji ứng với provider có tồn tại hay không.
def url_exists? url
    begin
      uri = URI.parse url
      request = Net::HTTP.new uri.host, uri.port
      request.use_ssl = true
      result = request.request_head uri.path
      result.code == "200"
    rescue
      false
    end
end

d. Hàm insert_emoji_image(content)

  • Hàm thực hiện tìm các kí tự emoji trong chuỗi content và thay thế bằng thẻ <img> tương ứng với emoji đó, tương tự hàm emojify() của EmojiHelper ở trên.
  def insert_emoji_image content
    emoji_chars = []

    content.each_char do |char|
      if is_emoji_char(char)
        emoji_chars << char
      end
    end

    emoji_chars.each do |emoji_char|
      content.gsub! emoji_char, "<img src=#{emoji_image_url emoji_char} style='vertical-align:middle; width: 18px; height: 18px;' >"
    end

    content.html_safe
  end

e. Nội dung CustomEmojiHelper:

module CustomEmojiHelper
  attr_accessor :emoji_char_codepoints

  def is_emoji_char? char
    @emoji_char_codepoints ||= (0x1F600...0x1F64F).to_a +
      (0x1F300...0x1F5FF).to_a +
      (0x1F680...0x1F6FF).to_a +
      (0x2600...0x26FF).to_a +
      (0x2700...0x27BF).to_a +
      (0xFE00...0xFE0F).to_a +
      (0x1F900...0x1F9FF).to_a +
      (0x1F1E6...0x1F1FF).to_a

    @emoji_char_codepoints.include? char.codepoints.first
  end

  def emoji_image_url char
    providers = ["apple", "emoji-one", "emojidex", "emojipedia", "facebook", "google", "htc", "lg", "messenger", "microsoft", "mozilla", "samsung", "twitter"]
    base_url = "https://raw.githubusercontent.com/loicpirez/EmojiExtractor/master/emojipedia.org"
    image_name = char.codepoints.map { |c| c.to_s(16).rjust(4, '0') }.join('-').gsub(/-(fe0f|200d)\b/, '')

    providers.each do |provider|
      image_url = "#{base_url}/#{provider}/#{image_name}.png"
      return image_url if url_exists?(image_url)
    end
  end

  def url_exists? url
    begin
      uri = URI.parse url
      request = Net::HTTP.new uri.host, uri.port
      request.use_ssl = true
      result = request.request_head uri.path
      result.code == "200"
    rescue
      false
    end
  end

  def insert_emoji_image content
    emoji_chars = []

    content.each_char do |char|
      if is_emoji_char?(char)
        emoji_chars << char
      end
    end

    emoji_chars.each do |emoji_char|
      content.gsub! emoji_char, "<img src=#{emoji_image_url emoji_char} style='vertical-align:middle; width: 18px; height: 18px;' >"
    end

    content.html_safe
  end
end
  • Trong db/seeds.rb tạo 1 số bài post có nội dung chứa các emoji.
Post.create title: "title", content: "🧤🧥🧦👗👘👚👛👜👝🛍️<br>🎒👞👟👠👡👢👑👒🎩🎓"
Post.create title: "title", content: "🧦👗🧥👘👚👛🧥?"
Post.create title: "title", content: "😄😜😔🇰🇷😂😀😃😄😁😆🐶🐱🐭🐹🐰🍏🍎🍐🍊🍋⚽️🏀🏈⚾️🎾🚗🚕🚙🚌🚎"
Post.create title: "title", content: "🧥😊🌏😀😆😗🐵🦊🐴🍇🍎🍅🚎"
  • Gọi hàm insert_emoji_image(content) và kiểm tra kết quả thu được.
  • Trước khi gọi hàm
  • Sau khi gọi hàm

f. Source code tham khảo:


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.