【概要】
初めて自分主導で Gem を導入するため、ざっと調べてみた。
【本文】
□ shortner とは?
- Rails アプリケーション内で短縮URLを生成できる!
- 短縮 URL を利用した計測もできる!(ユーザー等のモデル毎の計測も!)
- めっちゃ長いパラメータ付きのURLも省略できる!
- アプリケーション内でも外部でも、どこでもリダイレクトするよ!
短縮URLとは
# 長いURLが...
"http://localhost:3000/account_activations/C7EYgDf43N5OOh0S92wJlg/edit?email=user%40example.com"
# 短いURLに...!?
"http://localhost:3000/rd/fisafaf"
■ 概要
- Shortener は 大別して3つの要素で構成される
- Model では、短縮 URL の情報を保存
- Controller では、短縮 URL のアクセスが来たら、元の URL へリダイレクト
- Helper では、controllers と views で短縮 URL を生成
- Shortener のイカす所
- 301 でリダイレクトさせる(ページランクに影響するそうな)。1
- 短縮 URL の英数字は ユニークである。
- 短縮前 URL の使用回数を記録する。
- リンクは、ユーザに関連付けが可能で、特定ユーザとリンク情報との統計情報が取得できる。
- 開発環境
- Ruby: 2.4.9
- Rails: 5.1.2
- 参考: 学習情報 URL
■ 初期設定
○ 1: Gemfile に追加
gem 'shortener'
bash
bundle install
○ 2: generator を実行して短縮URL用のテーブル生成23
bash
rails generate shortener
〜 migratation ファイルを以下の通り変更する〜
rails db:migrate
失敗した場合のlog
# MySQL におけるデフォルトのキー長は、 767 bytes であるため、生成ファイルだとエラーが発生する。
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))
~timestamp~_create_shortened_urls_table.rb
# MySQLの設定によりキー長を 3072bytes まで拡張できるが、デフォルト値を使用する。
...
- t.text :url, null: false, length: 2083
+ t.text :url, null: false, length: 767
...
- add_index :shortened_urls, :url, length: 2083
+ add_index :shortened_urls, :url, length: 767
...
○ 3: ルーティング設定
routes.rb
...
+ get 'rd/:id', to: "shortener/shortened_urls#show", as: "shortend"
...
○ 4: 短縮URLを生成
bash
Shortener::ShortenedUrl.generate("https://www.tbs.co.jp/anime/machikado/")
=> #<Shortener::ShortenedUrl:0x00005593275cf228
id: 1,
owner_id: nil,
owner_type: nil,
url: "https://comic-fuz.com/series/1583",
unique_key: "d91z2",
category: nil,
use_count: 0,
expires_at: nil,
created_at: Sun, 08 Mar 2020 04:31:43 UTC +00:00,
updated_at: Sun, 08 Mar 2020 04:31:43 UTC +00:00>
token = Shortener::ShortenedUrl.find(1).unique_key
=> "d91z2"
Rails.application.routes.url_for(host: "localhost:3000", controller: "shortener/shortened_urls", action: :show, id: token)
=> "http://localhost:3000/rd/d91z2"
○ 5: 短縮URLにアクセスしてみると...
bash
# `use_count`の通りアクセス数がカウントされる
Shortener::ShortenedUrl.find(1)
=> #<Shortener::ShortenedUrl:0x0000562cdbe787c8
id: 1,
owner_id: nil,
owner_type: nil,
url: "https://comic-fuz.com/series/1583",
unique_key: "d91z2",
category: nil,
use_count: 1,
expires_at: nil,
created_at: Sun, 08 Mar 2020 04:31:43 UTC +00:00,
updated_at: Sun, 08 Mar 2020 04:31:43 UTC +00:00>
○ 6: その他
bash
# Railsアプリケーション内のルーティングへも設定可能
Shortener::ShortenedUrl.generate("/login")
# unique_key を元に登録済みのURLを検索可能
Shortener::ShortenedUrl.fetch_with_token(token: "d91z2")
■ 設定変更
○ unique_key の長さを変更
- デフォルトでは
5
であるが、設定ファイルを生成して、次の通り長さを変更できる。 - しかし、767bytes制限では大きく設定できない(15で失敗確認)。
config/initializers/shortener.rb
Shortener.unique_key_length = 10
○ token が一致しない場合のリダイレクト先を変更
config/initializers/shortener.rb
Shortener.default_redirect = "https://www.nintendo.co.jp/switch/acbaa/index.html"
○ unique_key の生成文字を変更
config/initializers/shortener.rb
# デフォルトがこれ
Shortener.charset = :alphanum
# ライブラリ内にある他の設定
## alphanum: ('a'..'z').to_a + (0..9).to_a,
## alphanumcase: ('a'..'z').to_a + ('A'..'Z').to_a + (0..9).to_a
# 新たに数字やハイフン等を追加できる...らしいが失敗する...
Shortener.charset = ("a".."z").to_a + (0..9).to_a + ["-", "_"]
■ short_url の可用性
- 短縮 URL を生成する方法として、ヘルパーメソッドも定義されている。
- console で試す場合は、事前に次の通りincludeしておくこと
include Shortener::ShortenerHelper
include Rails.application.routes.url_helpers
default_url_options[:host] = "localhost:3000"
- 参考として、ライブラリのコードを次の通り記載する。
# shortener/app/helpers/shortener/shortener_helper.rb
def short_url(url, owner: nil, custom_key: nil, expires_at: nil, fresh: false, category: nil, url_options: {})
short_url = Shortener::ShortenedUrl.generate(
url,
owner: owner,
custom_key: custom_key,
expires_at: expires_at,
fresh: fresh,
category: category
)
if short_url
if subdomain = Shortener.subdomain
url_options = url_options.merge(subdomain: subdomain)
end
options = { controller: :"/shortener/shortened_urls", action: :show, id: short_url.unique_key, only_path: false }.merge(url_options)
url_for(options)
else
url
end
end
# shortener/app/models/shortener/shortened_url.rb
def self.generate!(destination_url, owner: nil, custom_key: nil, expires_at: nil, fresh: false, category: nil)
# if we get a shortened_url object with a different owner, generate
# new one for the new owner. Otherwise return same object
if destination_url.is_a? Shortener::ShortenedUrl
if destination_url.owner == owner
destination_url
else
generate!(
destination_url.url,
owner: owner,
custom_key: custom_key,
expires_at: expires_at,
fresh: fresh,
category: category
)
end
else
scope = owner ? owner.shortened_urls : self
creation_method = fresh ? 'create' : 'first_or_create'
scope.where(url: clean_url(destination_url), category: category).send(
creation_method,
custom_key: custom_key,
expires_at: expires_at
)
end
end
○ サブドメイン付きでリダイレクト用URLが作成可能
bash
short_url("https://yahoo.co.jp/", url_options: { subdomain: "organization", host: "localhost:3000", protocol: "http" } )
=> "http://organization.localhost:3000/rd/BCDWTVbXwa"
○ 特定のモデルとも関連付けが可能
user.rb
# 関連付けして...
class User < ActiveRecord::Base
has_shortened_urls
end
bash
# 生成する!
Shortener::ShortenedUrl.generate("https://comic-fuz.com/series/1583", owner: user)
short_url("https://comic-fuz.com/series/1583", owner: user)
=> #<Shortener::ShortenedUrl:0x00005600092337f0
id: 6,
owner_id: 1,
owner_type: "User",
url: "https://comic-fuz.com/series/1583",
unique_key: "IUYIpUvD9O",
category: nil,
use_count: 0,
expires_at: nil,
created_at: Sun, 08 Mar 2020 07:33:10 UTC +00:00,
updated_at: Sun, 08 Mar 2020 07:33:10 UTC +00:00>
User.first.shortened_urls.first.url
=> "https://comic-fuz.com/series/1583"
○ unique_key を独自に設定可能
- 使用時は
unique_key_length
の設定等に注意すること。
bash
short_url("https://comic-fuz.com/series/261", custom_key: 'Original')
=> "http://localhost:3000/rd/Original"
○ 短縮URLの有効期限を設定可能
- 切れたらデフォルト設定のURLへ遷移
bash
short_url("https://comic-fuz.com/series/261", expires_at: 1.minutes.since)
○ 短縮URLの再生製が可能
- デフォルトで、短縮URLはユニークであるが、
fresh: true
オプションで、再生製が可能となる。
bash
short_url("https://comic-fuz.com/series/261", fresh: true)
○ 生成される token に使用不可の文字列を設定可能である。
- 例えば、
http://localhost:3000/rd/terms
と別のURLがルーティングしていた場合、token がその値に生成されたら、ルーティングが競合してしまう。 - そのため、生成してはいけない token を設定可能である。(本記事ではディレクトリを切っているので、競合する心配はない)
config/initializers/shortener.rb
Shortener.forbidden_keys.concat %w(terms promo)
○ クローラー等に対する短縮URLカウント
- デフォルトでは、クローラー等の訪問をカウントしている。
- 次の通り設定することで、無視することができる。
config/initializers/shortener.rb
Shortener.ignore_robots = true
まだ機能があるけど割愛