Railsで短縮URLを発行する

長い招待URL画像

TimeCrowdでは招待URLを発行してメンバーを招待することが出来ます。その際に相手に招待URLを連絡するのですが、あまりに長いので文章内に埋め込むとインパクトが強すぎるという要望がありました。

そこで今回は招待URLに対して短縮URLを使用して見やすい形にしたいと思います。

無事に台湾でドラゴンボートの試合を終えて帰国した旅してきたエンジニアの三宅です。

Shortenの導入

今回はShortenというgemを利用して機能を実装することにしました。

Installationを参照しながら進めます。

# Gemfile
gem 'shortener'
bin/rails generate shortener
bin/rake db:migrate
Running via Spring preloader in process 16007
== 20180706014530 CreateShortenedUrlsTable: migrating =========================
-- create_table(:shortened_urls)
   -> 0.0302s
-- add_index(:shortened_urls, :unique_key, {:unique=>true})
   -> 0.0293s
-- add_index(:shortened_urls, :url, {:length=>2083})
rake aborted!
StandardError: An error has occurred, all later migrations canceled:

Mysql2::Error: Specified key was too long; max key length is 3072 bytes: CREATE  INDEX `index_shortened_urls_on_url`  ON `shortened_urls` (`url`(2083))
/Users/kotamiyake/code/ruffnote/timecrowd/db/migrate/20180706014530_create_shortened_urls_table.rb:29:in `change'
-e:1:in `'
ActiveRecord::StatementInvalid: Mysql2::Error: Specified key was too long; max key length is 3072 bytes: CREATE  INDEX `index_shortened_urls_on_url`  ON `shortened_urls` (`url`(2083))
/Users/kotamiyake/code/ruffnote/timecrowd/db/migrate/20180706014530_create_shortened_urls_table.rb:29:in `change'
-e:1:in `'
Mysql2::Error: Specified key was too long; max key length is 3072 bytes
/Users/kotamiyake/code/ruffnote/timecrowd/db/migrate/20180706014530_create_shortened_urls_table.rb:29:in `change'
-e:1:in `'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)

マイグレーションでエラーが発生してしまいました。

どうやらカラムインデックスの最大キー長が長すぎるようです。

MySQLでは基本的には単一カラムインデックスの最大キー長は767バイトまで作成できます。特定の条件ではインデックスの最大キー長を3072バイトまで拡張することができます。

TimeCrowdでは最大キー長3072バイトまで拡張しているのですが、それでも足りなかったようです。

マイグレーションファイルを見てみましょう。

class CreateShortenedUrlsTable < ActiveRecord::Migration[4.2]
  def change
    create_table :shortened_urls do |t|
      # we can link this to a user for interesting things
      t.integer :owner_id
      t.string :owner_type, limit: 20

      # the real url that we will redirect to
      t.text :url, null: false, length: 2083

      # the unique key
      t.string :unique_key, limit: 10, null: false

      # a category to help categorize shortened urls
      t.string :category

      # how many times the link has been clicked
      t.integer :use_count, null: false, default: 0

      # valid until date for expirable urls
      t.datetime :expires_at

      t.timestamps
    end

    # we will lookup the links in the db by key, urls and owners.
    # also make sure the unique keys are actually unique
    add_index :shortened_urls, :unique_key, unique: true
    add_index :shortened_urls, :url, length: 2083
    add_index :shortened_urls, [:owner_id, :owner_type]
    add_index :shortened_urls, :category
  end
end

urlのlengthがカラム長、キー長共に2083文字となっています。

TimeCrowdでは文字コードにutf8mb4を採用しているので、カラム長、キー長を768文字にする必要があります。

幸い招待URLの長さは768文字を超えないので768文字に変更して、再度マイグレーションを実行します。

bin/rake db:migrate
Running via Spring preloader in process 37580
== 20180706014530 CreateShortenedUrlsTable: migrating =========================
-- create_table(:shortened_urls)
   -> 0.0339s
-- add_index(:shortened_urls, :unique_key, {:unique=>true})
   -> 0.0286s
-- add_index(:shortened_urls, :url, {:length=>768})
   -> 0.0217s
-- add_index(:shortened_urls, [:owner_id, :owner_type])
   -> 0.0275s
-- add_index(:shortened_urls, :category)
   -> 0.0278s
== 20180706014530 CreateShortenedUrlsTable: migrated (0.1404s) ================

無事マイグレーションに成功しました。

短縮URLを使ってアクセス

まずは短縮URLからリダイレクトするためのルーティングを設定します。

get '/s/:id' => 'shortener/shortened_urls#show'

例ではルート直下に設定していましたが、短縮URLということでnamespaceとして/s/で区切ることにしました。

それでは次に短縮URLを発行してみたいと思います。

pry(main)> shortened_url = Shortener::ShortenedUrl.generate("https://timecrowd.net")
pry(main)> shortened_url.unique_key
=> "5wr8x"

では開発環境を使って短縮URLにアクセスしてみます。

http://localhost:3000/s/5wr8x

TimeCrowdトップページ画像

正常にリダイレクトすることが確認できました。

実際の画面で表示すると以下のようになります。

短縮URL画像

だいぶスッキリしましたね!

これで今までの長々としたURLをチャットやメールに添付する必要はなくなります。

まだこちらの機能はリリースしていませんが、近々リリースできるよう鋭意開発中ですので乞うご期待ください!

参考記事

第32回 InnoDBインデックスの最大キー長について:MySQL道普請便り|gihyo.jp … 技術評論社
http://gihyo.jp/dev/serial/01/mysql-road-construction-news/0032

 

 

 

 

TimeCrowdに戻る