はじめまして、ホスティング事業部のムームードメイングループエンジニア @kimromi です。先日の7/20(木)にムームードメインで「ショッピングカート機能」の提供を開始しました。
ムームードメインとは
2004年1月にローンチされ今年で14年目になるドメイン統合サービスです。ドメインの販売や更新、移管、DNS、メールサービスなどの提供など行っており、今ではドメインお申し込み数362万件を突破しています。
サービス開始以来、PHPでの開発が進められてきましたが、近年はスマートフォン用のサイトやLP、その他一部の機能はRuby on Railsでの開発が進められています。今回のショッピングカート機能の開発はトップページを除いたすべてのページをRuby on Railsで開発しました。その他Web StorageやJavaScriptフレームワークのVue.jsを使用して開発しましたのでその一部をご紹介いたします。
ショッピングカート情報の保持
ショッピングカートに入れたドメイン名や契約年数の情報はLocal Storageにデータを保持しています。
検討したものとしては以下がありました。
- Session
- SessionIDをキーにしてデータベースに保存
- Cookie
- Web Storage
- Session Storage
- Local Storage
Local Storageに決めた理由
カートに入れたときに通信が発生しない
Sessionやデータベースに保持だとカートへの追加、削除のたびに通信が必要なので、レスポンスやネットワークが不安定な場合を考慮し通信が発生しない方法を取りました。
保存できるデータ量が大きい
ブラウザによって差はありますが保存できるデータ量は、Cookieは約4KBでWeb Storageは約5MB〜と非常に大きいです。またCookieはサーバ通信時に毎回HTTPヘッダに付与されて送信されます。そのトラフィックを削減できるためWeb Storageを選択しました。
永続的にデータを保持できる
Session Storageはブラウザのウィンドウやタブを閉じるまでしか保持できず、一度画面を離脱して再度訪れたときにデータが消えているのでショッピングカートという機能の性質上使えませんでした。Local Storageは永続的に保持できるため選択しました。
上記の理由からLocal Storageを選択しましたが、永続的にデータを保持できJavaScriptから簡単にアクセスできるという性質上、セキュリティ的に危険のある認証情報や個人情報は絶対に置かないようにしています。
ショッピングカート情報の永続化
Local Storageに保持したショッピングカート情報ですが、実際に申し込む時にはサーバー側に送信してデータベースに永続化する必要があります。タイミングとしてはログイン後にカート内の情報表示し契約年数など決定したあとに行なっています。
データを送信している様子
Local Storageに保持している情報を画面に展開してPOSTで送信するでもよいのですがそれだと工夫がないので、JSONのWebAPIを用意して送信する方式を取っています。WebAPIの認証にはJWT(JSON Web Token)を使用しています(詳細はこちら)。詳しくは以下のような流れで永続化しています。
- ログインしたときにJWTのトークンを
jwt_token
という名前でCookieにセットする(HttpOnly、Secure属性はON) - 画面から契約年数など決定したタイミングでWebAPIを実行する
- WebAPI側はHTTPヘッダのCookieをチェックしアカウント認証する
- 認証が通ればPOSTされたカートの情報をデータベースに保存する
Ruby on RailsのWebAPIにJWTの認証機構を導入するのに便利なKnock gemがありましたのでこちらを採用して導入しています。こちらのgemはJWTのトークンの認証はHTTPヘッダのAuthorization
での認証しか対応していないため、独自にjwt_token
という名前のCookieで認証できるように拡張しています。拡張しているコードはこのような感じです。
# overwrite https://github.com/nsarno/knock/blob/master/lib/knock/authenticable.rb#L10
def token
params[:token] || token_from_request_headers || token_from_request_cookie
end
def token_from_request_cookie
request.cookies['jwt_token']
end
Vue.jsの導入
トップページのモーダルやショッピングカートの詳細設定ページでJavaScriptフレームワークのVue.jsを使用しました。
Vue.jsを使ってajaxで価格を計算している様子
Single Page Applicationのための使用ではなく、jQueryで書くと複雑になりそうな部分にVue.jsを使用しました。Vue.jsを採用した理由としては以下です。
社内にドキュメント翻訳者がいる
弊社から2名、@inouetakuya、@hypermktがVue.jsの日本語ドキュメントの翻訳を行なっています。わからなかったことはすぐに質問できるという環境は願ってもない環境であり、導入の大きな要因となりました。
社内での導入実績が増えてきた
先日発表された、ロリポップ!マネージドクラウドのフロントエンド部分はVue.jsのサーバーサイドレンダリングで実装されています。またグーペやロリポップ!の一部機能で使用されたりと導入実績が増えてきています。
学習コストが低い
今回のショッピングカート対応においてはエンジニアとデザイナーが協業で進めており、Ruby on RailsのViewテンプレートに直接Vue.jsのディレクティブ(v-on
などv-
で始まるVue.jsで処理することを宣言する属性)を書けるのが非常に導入しやすい部分でありました。「そのidとclass、JavaScriptで使用しているから消さないでください!」などの無駄なコミュニケーションが発生しませんでした。
また日本語ドキュメントも大変見やすく、今回デザイナー向けにVue.jsの共有は都合上できなかったのですがドキュメントを読んでいただき理解できたようで、デザイナーからVue.jsの動作に関するプルリクエストもでてきたほどでした。
導入方法
現在Rails4.2であるため、Rails5.1からのWebpackerを使用せず独自にyarnのタスク(yarn build
)でwebpackするように準備しています。Sprocketsからは完全に切り離さずwebpackにてビルド済みのjsファイルをassets:precompile対象のディレクトリに置いて動作させるようにしました。
デプロイはCapistranoを使用していますので、assets:precompileの前にyarn build
してwebpackするタスクを追加しています。
namespace :js do
task :webpack do
on roles(:app) do
within release_path do
execute :yarn, :build
end
end
end
end
# deploy:updatedでassets:precompileされるためその前にwebpack
before 'deploy:updated', 'js:webpack'
デザイナーとの協業
前章にてデザイナーとの協業について少し触れましたが、デザイナーの方でも今回ムームードメインを作り変えていくにあたり、Fractalを使用したスタイルガイドを構築して開発を進めました。デザイナーがスタイルガイド上で実装している間にエンジニアはRails側の実装をしたりと、作業のコンフリクトを最小限に抑えて開発することができました。詳しくはデザイナーの方より詳しい記事が出ると思います。
今後のやっていき
今回のショッピングカート対応ですが、ドメイン契約にあたって必要な選択項目をできるだけ減らしたりお支払い方法を自動で選択し契約までのステップを減らしたりと、ユーザーエクスペリエンス向上も考えられたものになっています。しかし一度に購入できるドメイン数やお支払い方法などにまだ制限があったりと機能として完全でないので現在も鋭意開発継続中です!
今後もチームとしてより良い技術を取り入れ、お客様に最高のサービスを提供していきます。ムームードメインの飛躍にぜひご期待ください!