【Rails】Google map APIの処理の流れ


:::note warn
GoogleマップAPIを実装したので、処理の流れを備忘録として残します。
実装方法の解説ではないため、前提部分は省きます。
※あくまで、処理の流れをメインに記載します。細かい関数やメソッドの意味にはあまり触れませんので、わからないところは調べてください。
:::


### なぜ処理の流れに特化したのか？
私個人の考えですが、実装の仕方を理解するのに処理の流れが一番大事だと感じたからです。
関数の意味やメソッドの使い方も大事ですが、今の時代少し調べたら情報は出てきます。
初学者の私が、実装するのに処理の流れやルールを覚えたら他の理解がしやすかったからです。

##### 今回の内容の前提
・Google cloud platformに登録していること
・請求情報が登録されていること
・Maps Javascript API・Geocoding APIを有効化していること
・ APIキーを.envで定義していること
・gem 'geocoder'が適用されていること
・dotenv-rails,yarn add dotenvがインストールされていること
・ファイルの内容は以下のとおりです
```ruby:config/routes.rb
Rails.application.routes.draw do
  :
  :
  resource :map, only: [:show] 
end
```
```:.env
Maps_API_Key = "自分のAPIキー"
```
```erb:app/views/maps/show.html.erb
<div class="container">
  <div id="map"></div>
</div>

<%= javascript_pack_tag 'map', 'data-turbolinks-track': 'reload' %>
```
```rb:app/views/post_images/index.json.jbuilder
json.data do
  json.items do
    json.array!(@post_images) do |post_image|
      json.id post_image.id
      json.user do
        json.name post_image.user.name
        json.image url_for(post_image.user.profile_image)
      end
      json.image url_for(post_image.image)
      json.shop_name post_image.shop_name
      json.caption post_image.caption
      json.address post_image.address
      json.latitude post_image.latitude
      json.longitude post_image.longitude
    end  
  end
end
```
```js:app/javascript/packs/map.js
// ブートストラップ ローダ
(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})({
  key: process.env.Maps_API_Key
});
//.env.Maps_API_Keyの部分は自分で定義した.envファイルに記述したもの

// ライブラリの読み込み
let map;

async function initMap() {
  const { Map } = await google.maps.importLibrary("maps");
  const {AdvancedMarkerElement} = await google.maps.importLibrary("marker") 

  map = new Map(document.getElementById("map"), {
    center: { lat: 35.681236, lng: 139.767125 },
    zoom: 15,
    mapId: "DEMO_MAP_ID", 
    mapTypeControl: false
  });

  try {
    const response = await fetch("/post_images.json");
    if (!response.ok) throw new Error('Network response was not ok');

    const { data: { items } } = await response.json();
    if (!Array.isArray(items)) throw new Error("Items is not an array");

    items.forEach( item => {
      const latitude = item.latitude;
      const longitude = item.longitude;
      const shopName = item.shop_name;

      const marker = new google.maps.marker.AdvancedMarkerElement ({
        position: { lat: latitude, lng: longitude },
        map,
        title: shopName,
        // 他の任意のオプションもここに追加可能
      });
    });
  } catch (error) {
    console.error('Error fetching or processing post images:', error);
  }
}

initMap()
```
### 処理の流れ

###### /map（GETリクエスト）
ユーザーが/mapにアクセスすると、Railsが対応するコントローラーのアクション（例：MapsController#show）を処理し、関連するHTMLビュー（例：show.html.erb）に遷移します。
###### HTMLビューの読み込み
対応するHTMLビューがレンダリングされます。このビュー内に、JavaScriptファイルを読み込むタグとして、次の記述が含まれています。
```erb
<%= javascript_pack_tag 'map', 'data-turbolinks-track': 'reload' %>
```

###### javascript_pack_tagがJavaScriptファイルを呼び出す
javascript_pack_tagで指定されたmap.jsファイルが読み込まれ、JavaScriptの実行が開始されます。
###### map.js内の処理が実行される
map.js内のコードが順に実行され、まずinitMap()関数が呼び出されます。
###### initMap()関数の処理
initMap関数内でGoogle Maps APIを使ったマップの初期化が行われます。
```js
google.maps.importLibrary("maps")
google.maps.importLibrary("marker")
```
によって、Google MapsとMarker APIの読み込みが行われます。
初期値として設定した位置に基づいて地図オブジェクト（map）が作成されます。
###### tryブロック内の処理
fetchメソッドによって
```js
"/post_images.json"
```
エンドポイントに非同期でアクセスします。
このエンドポイントは、通常RailsのPostImagesControllerのindexアクションで設定されています。indexアクションでformat.jsonが設定されている場合、リクエストに応じてJSON形式のデータが返されます。
###### format.json doブロックの処理
indexアクション内の
```rb
format.json do
```
ブロックが実行され、
```rb
@post_image
```
に代入されたデータ（例：PostImage.all）がindex.json.jbuilderで整形されます。
###### JSONレスポンスの受け取りと変換
fetchで取得したレスポンスは.json()でJavaScriptオブジェクトに変換され、以下のようにデータをitemsに代入します。

const { data: { items } } = await response.json();

###### items.forEachでデータをループ処理
items.forEachを使い、index.json.jbuilderで整形された各post_imageデータに対して処理を行います。
latitude、longitude、shopNameなどの情報を取り出し、Google Maps上にマーカーを表示するためのオブジェクト（AdvancedMarkerElement）を生成してマーカーを地図上に配置します。
###### 画面への反映

すべてのマーカーが地図に追加され、ブラウザのビューに地図とマーカーが表示されます。