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 キーを取得

  1. Google Cloud Console にログインし、プロジェクトを作成(または既存プロジェクトを選択)
  2. 左メニュー → APIs & Services → LibraryMaps JavaScript API を有効化
  3. Credentials → Create credentials → API key をクリックし、キーを生成
  4. Key restriction に以下を設定(必須)
    - Application restrictions: HTTP referrers (web sites)https://your-domain.com/*
    - API restrictions: Maps JavaScript API のみ許可

取得したキーは .env ファイルに GOOGLE_MAPS_API_KEY=YOUR_KEY として保存し、figarodotenv-rails で環境変数として読み込めるようにします。

ステップ 2:Rails 側のセットアップ

2‑1. Gemfile に依存関係を追加(Webpacker または importmap)

Ruby
# Gemfile gem 'dotenv-rails', groups: [:development, :test]
Bash
bundle 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

マイグレーション例:

Bash
rails 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.jsdocument.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_KEYwebpacker.ymlenvironmentENV['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.rbscript-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 を利用したユーザー現在地表示など、より高度な機能に挑戦してみてください。

参考資料