[Rails 6] Embed Google Map in the app and add a marker to the entered address. [Confirmation of details]

The Google Map API should be easy to implement, but I'm addicted to many swamps, so I'll pay close attention to it.

environment

Rails 6.0.0 Ruby 2.6.5 EC2 Amazon Linux2 Nginx mariaDB Capistrano

function

Enter your address48b7ab460e405caaf463dd4963cd52af.png Address is saved in DB, latitude and longitude are calculated automatically f57e6c8b1a108791d56e024334075861.png

It shows. d801305aebecc331b0cfd2a2bb7970d2.jpg

Embed Google Map in your app

<a href="https://cloud.google.com/maps-platform/?hl=ja&utm_source=google&utm_medium=cpc&utm_campaign=FY18-Q2-global-demandgen-paidsearchonnetworkhouseads-cs-maps_contactsal_saf&utm_content=text-ad-none-none- DEV_c-CRE_320617583922-ADGP_Hybrid% 20% 7C% 20AW% 20SEM% 20% 7C% 20BKWS% 20 ~% 20Google% 20Maps% 20API% 20BMM-KWID_43700039913979172-kwd-313687189577-userloc_1009304 & utm_term = KW_% 2%B -ST_% 2Bgoogle% 20% 2Bmap% 20% 2Bapi & gclid = CjwKCAjwlbr8BRA0EiwAnt4MThq955XhyzUb7M1GK-21Aiqd5XdDq1JGzLDPjnyvFrBJ-dxCQAyDORoCjAQAv "Google Page"

Google Map API is one of the services of Google Cloud, and it is operated from the console called Google Cloud Platform. First, get the API Key of Google Map javascript API there.

Go to Google Cloud Platform

☆ If you do not have a Google account, please register here first. Google account registration After creating an account (if you have one) go to the console https://console.cloud.google.com/

Create a project and get API Key → Map display

https://qiita.com/nagaseToya/items/e49977efb686ed05eadb The flow is written here in an easy-to-understand manner.

This time, in addition to this, you can record, save, and output any address.

Geocording It is a function that calculates the latitude and longitude and finds a specific position. We use gem's Geocoder and Google Cloud's Geocoding API service. You can get location information with just gem, but you can get it at "Tokyo Station", but you can't get it with the specific address "○○○○ ー ◯◯, 〇〇-ku, Tokyo". You may or may not be able to get it. Therefore, we will also make it possible to use the better-performing Geocoding API.

code

Suppose the model has been created. (Example Performances model)

① Create migration file (add column)

% rails g migration AddColumnsToPerformances

-Entered address address column -Latitude and longitude columns automatically calculated by geocode

class AddColumnsToPerformances < ActiveRecord::Migration[6.0]
  def change
    add_column :performances, :address, :string
    add_column :performances, :latitude, :float
    add_column :performances, :longitude, :float
  end
end
% rails db:migrate

You can change the column with rollback, but the data will be lost, so I think it's better to add_column (add column) as much as possible!

② Create input form

You can save only the address.

<%= form_with(model: @performance, local: true) do |f| %>
***Excerpt***
<label for="group-name">Street address(Google Map display)</label>
<span class="indispensable-any">Any</span>
<%= f.text_area :address,class:"new-performance-box", id:"gmap", placeholder:"Copy and paste your Google Map address" %>  
***Excerpt***

③ Controller

Specify the address with the strong parameter.

performances_controller.erb


before_action :set_performance, only: [:View to display]

def create
   @performance = Performance.new(performance_params)
   if @performance.valid?
     @performance.save
     redirect_to "/users/#{current_user.id}"
   else
     render :new
   end
end

def view to display
    @performance = Performance.new(performance_params)
end

private

def set_performance
   @performance = Performance.find(params[:id])
end

def performance_params
 params.require(:performance).permit(:address).merge(user_id: current_user.id)
end

④ View

CSS is described separately. zoomControl: false, mapTypeControl: false, fullscreenControl: false, treetViewControl: false, Is a map display option that turns off the zoom button and so on.

<div id='map'>
<script>
let map
function initMap(){
  map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: <%= @performance.latitude %>, lng: <%= @performance.longitude %>},
    zoom: 15,
       zoomControl: false,
       mapTypeControl: false,
       fullscreenControl: false,
       streetViewControl: false,
  });

  marker = new google.maps.Marker({
    position: {lat: <%= @performance.latitude %>, lng: <%= @performance.longitude %>},
    map: map
  });
   geocoder = new google.maps.Geocoder()
}
</script>
  <script src="https://maps.googleapis.com/maps/api/js?key=<%= ENV['GOOGLE_MAP_API'] %>&callback=initMap" async defer></script>
</div>

* Please be careful about the notation of key = <% = ENV ['GOOGLE_MAP_API']%>! Here, just the position of = is different, but everything will not work ... </ b>

⑤ Model

Now geocord will calculate the latitude and longitude and save it in the column.

performance.rb


geocoded_by :address
after_validation :geocode, if: :address_changed?

* If :: address_changed? Is not available, it may not work, so be careful! I had to write this </ b>

⑥ Description for using Geocording API

% rails generate geocoder:config

/config/initializes/geocoder.rb



Geocoder.configure(
  # Geocoding options
  # timeout: 5,                 # geocoding service timeout (secs)
  lookup: :google,         # name of geocoding service (symbol)
  # ip_lookup: :ipinfo_io,      # name of IP address geocoding service (symbol)
  # language: :en,              # ISO-639 language code
  use_https: true,           # use HTTPS for lookup requests? (if supported)
  # http_proxy: nil,            # HTTP proxy server (user:pass@host:port)
  # https_proxy: nil,           # HTTPS proxy server (user:pass@host:port)
  api_key: 'YOUR_API_KEY',               # API key for geocoding service
  # cache: nil,                 # cache object (must respond to #[], #[]=, and #del)
  # cache_prefix: 'geocoder:',  # prefix (string) to use for all cache keys

  # Exceptions that should not be rescued by default
  # (if you want to implement custom error handling);
  # supports SocketError and Timeout::Error
  # always_raise: [],

  # Calculation options
  units: :km # :km for kilometers or :mi for miles
  # distances: :linear          # :spherical or :linear
)

Things to check when things go wrong

・ Setting environment variables ・ View description ・ Model method ・ Geocorder.rb

%rails c
[1] pry(main)> Geocoder.coordinates("〒150-0043 2-1 Dogenzaka, Shibuya-ku, Tokyo")
=> [35.6591376, 139.7007901]

Try to output while changing the contents with -If Google Map javascript and API key of Geocoding API are combined, create another API and try to separate them. -Environment variable setting in the production environment

[ec2-user@〜〜〜〜〜〜〜]$ sudo vim /etc/environment

After setting variables exit → restart

[ec2-user@〜〜〜〜〜〜〜]$ env | grep YOUR_API_KEY

Confirm with -Try restarting from the EC2 server (I finally confirmed it in the production environment)

Recommended Posts