markdown
はじめに (対象読者・この記事でわかること)
この記事は、以下のような読者を想定しています。
- Ruby on Rails で Web アプリ開発の実務経験があり、フロントエンドにもう少しインタラクティブさを持たせたい方
- JavaScript の基本的な文法は理解しているが、Rails との連携に自信がない方
- Google Maps API を使って位置情報を可視化したいが、実装手順がイマイチ掴めていない方
本稿を読むことで、次のことができるようになります。
1. Google Cloud Platform で API キーを取得し、適切な制限を設定する方法
2. Rails プロジェクトに google-maps-js(または純粋な CDN)を組み込み、JavaScript でマップを初期化する手順
3. コントローラ・ビュー間で位置情報(緯度・経度)を安全に受け渡し、マーカーや情報ウィンドウを動的に生成できる
背景として、過去に自社サービスで物件検索機能を実装した際、地図表示が UI のボトルネックになり、実装を外部ライブラリに委託した経験があります。そのときに得た知見をまとめました。
前提知識
この記事を読み進める上で、以下の知識があるとスムーズです。
- Rails(5.2 以上)での MVC の基本的な流れ
- HTML / CSS の基礎、特に <div id="map"></div> のレイアウト制御
- JavaScript(ES6) の基本構文と、Webpacker(または importmap)でのアセット管理
Google Maps を Rails に導入する背景と全体像
Web アプリに地図を組み込む目的は大きく分けて二つあります。
1. ユーザー体験の向上 – 住所検索や近隣情報の提示を視覚的に行えるため、操作が直感的になる。
2. データ可視化 – 複数の位置情報を一括で表示し、分析や意思決定に活用できる。
Rails 側では API キー管理と位置情報データの提供、フロントエンド側では JavaScript がマップの描画・操作を担います。
この二層構造を明確に分離することで、テストや保守が楽になる点が大きなメリットです。
本稿では、Google Maps JavaScript API を CDN 経由で読み込み、Rails の View(ERB)からデータを JSON で埋め込み、app/javascript/packs/map.js でマップ初期化ロジックを実装する流れを中心に解説します。
Rails × Google Maps の実装手順
ステップ 1:Google Cloud Platform で API キーを取得
- Google Cloud Console にログインし、プロジェクトを作成(または既存プロジェクトを選択)
- 左メニュー → APIs & Services → Library で Maps JavaScript API を有効化
- Credentials → Create credentials → API key をクリックし、キーを生成
- Key restriction に以下を設定(必須)
- Application restrictions:HTTP referrers (web sites)→https://your-domain.com/*等
- API restrictions:Maps JavaScript APIのみ許可
取得したキーは .env ファイルに GOOGLE_MAPS_API_KEY=YOUR_KEY として保存し、figaro や dotenv-rails で環境変数として読み込めるようにします。
ステップ 2:Rails 側のセットアップ
2‑1. Gemfile に依存関係を追加(Webpacker または importmap)
Ruby# Gemfile gem 'dotenv-rails', groups: [:development, :test]
Bashbundle install
Webpacker がすでに導入されている前提で、app/javascript/packs/map.js を作成します。(importmap を使う場合は app/assets/javascripts/map.js へ同様のコードを配置)
2‑2. 位置情報用モデル(例: Store)を用意
Ruby# app/models/store.rb class Store < ApplicationRecord # attributes :name, :address, :latitude, :longitude geocoded_by :address after_validation :geocode, if: :address_changed? end
マイグレーション例:
Bashrails g migration AddGeolocationToStores latitude:float longitude:float rails db:migrate
2‑3. コントローラで JSON データを生成
Ruby# app/controllers/stores_controller.rb class StoresController < ApplicationController def index @stores = Store.all @stores_geojson = @stores.map do |s| { id: s.id, name: s.name, lat: s.latitude, lng: s.longitude } end end end
ステップ 3:ビュー側でマップ領域とデータ埋め込み
Erb<!-- app/views/stores/index.html.erb --> <h1>店舗一覧</h1> <div id="map" style="width: 100%; height: 500px;"></div> <script type="application/json" id="stores-data"> <%= raw @stores_geojson.to_json %> </script> <%= javascript_pack_tag 'map', defer: true %>
ポイント: application/json スクリプトタグにデータを埋め込み、map.js で document.getElementById('stores-data').textContent をパースして使用します。
ステップ 4:JavaScript でマップを初期化・マーカー表示
Javascript// app/javascript/packs/map.js import { Loader } from "@googlemaps/js-api-loader"; document.addEventListener('DOMContentLoaded', () => { const apiKey = process.env.GOOGLE_MAPS_API_KEY; // webpack DefinePlugin で注入 const loader = new Loader({ apiKey, version: "weekly", }); loader.load().then(() => { const mapDiv = document.getElementById('map'); const map = new google.maps.Map(mapDiv, { center: { lat: 35.6895, lng: 139.6917 }, // デフォルトは東京 zoom: 10, }); // 埋め込まれた JSON データを取得 const rawData = document.getElementById('stores-data').textContent; const stores = JSON.parse(rawData); stores.forEach(store => { const marker = new google.maps.Marker({ position: { lat: store.lat, lng: store.lng }, map, title: store.name, }); const infowindow = new google.maps.InfoWindow({ content: `<strong>${store.name}</strong>`, }); marker.addListener('click', () => { infowindow.open(map, marker); }); }); }).catch(e => { console.error('Google Maps のロードに失敗しました:', e); }); });
ポイント解説
- @googlemaps/js-api-loader は公式の軽量ローダーで、API キーの注入やエラーハンドリングが楽です。
- process.env.GOOGLE_MAPS_API_KEY は webpacker.yml の environment に ENV['GOOGLE_MAPS_API_KEY'] をマッピングしておく必要があります。
- マーカーごとに InfoWindow を作成し、クリック時に表示させるシンプルなインタラクションです。
ハマった点やエラー解決
| 発生した問題 | 原因 | 解決策 |
|---|---|---|
InvalidKeyMapError がコンソールに表示された |
API キーに HTTP リファラ制限がかかっており、ローカル環境からのリクエストがブロックされた | 開発用に http://localhost:3000/* を許可リストに追加、もしくは制限を一時的に “None” に変更 |
google is not defined エラー |
スクリプトがロードされる前に map.js が実行された |
loader.load().then(...) で確実に API が読み込まれた後に処理を開始 |
| マーカーが全て同じ位置に表示された | データの lat/lng が文字列のまま渡され、数値に変換できていなかった |
parseFloat で明示的に数値化、または JSON に数値として保存 |
| CSP (Content Security Policy) によるブロック | config/initializers/content_security_policy.rb で script-src が Google の CDN を許可していなかった |
policy.script_src :self, :https, "https://maps.googleapis.com", "https://js.api.google.com" を追加 |
解決策の実装例(CSP 変更)
Ruby# config/initializers/content_security_policy.rb Rails.application.config.content_security_policy do |policy| policy.default_src :self, :https policy.script_src :self, :https, "https://maps.googleapis.com", "https://js.api.google.com" policy.style_src :self, :https, :unsafe_inline # 他の設定は省略 end
この設定を追加すると、ブラウザのコンソールに出ていた CSP エラーは解消します。
まとめ
本記事では、Rails アプリに Google Maps を組み込むフロー を以下の順序で解説しました。
- API キー取得と安全な設定
- Rails 側で位置情報をモデル化し JSON に変換
- ビューでマップ領域とデータ埋め込み
- JavaScript ローダーでマップ初期化、マーカー・InfoWindow の実装
主な要点
1. API キーはリファラ制限と API 制限を必ず設定し、.env 経由で管理する。
2. @googlemaps/js-api-loader を使うと非同期ロードとエラーハンドリングが簡潔になる。
3. データは HTML の application/json スクリプトタグに埋め込むと、サニタイズの心配が少なくフロントで安全に取得できる。
この記事を通して、Rails と JavaScript の連携によるインタラクティブ地図表示 の全体像が掴めたはずです。次のステップとして、Marker Clustering、カスタムスタイル、そして Geolocation API を利用したユーザー現在地表示など、より高度な機能に挑戦してみてください。
参考資料
- Google Maps Platform Documentation – JavaScript API
- Rails Guides – Asset Pipeline & Webpacker
- dotenv‑rails Gem – GitHub
- @googlemaps/js-api-loader – npm
- Content Security Policy (CSP) – Rails Guides