GoogleChartAPI Wrapper(QR コード)

RailsQR コードを出力する必要がありました。要求は以下の3点。

  • 普通のビュー内でも使いたい
    • Helper でQR コードAPI用のURL を生成して、それをimage_tag に渡せばおk
  • QR コードだけポップアップする機能も欲しい
    • Controller でsend_data + ビューでlink_to(..., :popup => [...])
  • PC で表示できればok
    • 携帯にQR コードを表示する場合、DoCoMoPNG 画像を扱えないので、GoogleChartAPI を使った後にGIF に変換したりする必要がある

Helper 内でもControler 内でも使いたいので簡単なモジュールを作成。

使い方

普通にビューで使う場合
  • application_helper.rb
def qrcode_url(str, size = 150)
  qrcode = ChartUtility::GoogleChart::QRCode.new(size)
  qrcode.url = str
  qrcode.to_url
end
  • example.erb.html
<%= image_tag(qrcode_url('http://d.hatena.ne.jp/')) %>
QR コードだけポップアップさせる場合
  • example_controller.rb
def qrcode
  qrcode = ChartUtility::GoogleChart::QRCode.new(150)
  qrcode.url = 'http://d.hantena.ne.jp/'
  send_data(qrcode.to_data, :type => 'image/png', :disposition => 'inline')
end
  • example.erb.html
<%= link_to 'QR コード', {:action => 'qrcode'}, {:popup => ['QRCode', 'height=150, width=150']} %>

ソースコード

require 'net/http'
require 'nkf'
require 'uri'

Net::HTTP.version_1_2

module ChartUtility
  module GoogleChart
    class Base
      attr_reader :type, :size

      def self.base_uri
        URI('http://chart.apis.google.com/')
      end

      def initialize(type, size)
        @type = type
        @size = size.kind_of?(Integer) ? "%sx%s" % [size, size] : size
      end

      def to_uri(options = {})
        construct_uri.to_s
      end

      alias_method :to_url, :to_uri

      def to_data
        data = ''

        begin
          uri = construct_uri
          http = Net::HTTP.new(uri.host)
          http.open_timeout = 5
          http.read_timeout = 5

          http.request_get(uri.request_uri) do |res|
            data = res.body
          end
        rescue TimeoutError => ex
        ensure
          return data
        end
      end

      private

      def construct_params
        {
          :cht => @type,
          :chs => @size
        }
      end

      def construct_uri
        uri = self.class.base_uri
        uri.path = '/chart'
        uri.query = construct_params.
                    sort_by{|k, v| k.to_s }.
                    map{|k,v|
                      "#{k}=#{URI.encode(NKF.nkf("-w", v.to_s)).gsub(/%20/,"+").gsub(/%7C/,"|")}"
                    }.join('&')
        uri
      end
    end

    class QRCode < Base
      attr_accessor :url, :choe

      def initialize(size)
        super('qr', size)
      end

      private

      def construct_params
        choe = @choe || 'UTF-8'
        super.merge(:chl => @url, :choe => choe)
      end
    end
  end
end