Avant de commencer (template utilisé 🙂 )
Avant de commencer, j’ai lancé le template très basique de rails new avec webpack + postgré
rails new appname --webpack=stimulus -d postgresql
Installer Geocoder
Geocoder est une gem disponible dans la ruby gem (librairie de ruby), permettant ainsi de rajouter les points coordonnées GPS sur un élément. Une adresse est composée avant tout de la longitude et de la latitude. Une fois l’adresse saisie dans un champs par exemple, geocoder pourra ainsi vous ajouter les coordonnées GPS afin de les afficher sur un service de mapping de votre choix. Pour information, il existe plusieurs services comme google maps api, mapbox (version free environ 50 000 requêtes API / mois).
Pour installer la gem, aller dans le gemfile puis ajouter :
# Use geocoder
gem 'geocoder'
Puis nous allons ensuite, lancer dans le terminale :
bundle
Afin de pouvoir installer la gem sur notre application rails :
Générer notre controller + model
Pour générer rapidement un model avec un controller ainsi que toutes les routes du CRUD,nous pouvons utiliser la commande scaffold (à ne pas utiliser pour des projets long terme). L’objectif de cet article étant de vous accompagner sur l’installation de geocoder avec un service de mapping online.
rails g scaffold produit
Vérifier notre schema pour ajouter une adresse
Afin de pouvoir Geocoder, nous allons ajouter un champs adresse ainsi que longitude et latitude à notre table produit afin d’avoir une localisation. Geocoder se chargera par la suite de remplir la colonne longitute et latitude en fonction des données rentrées par le user.
Générer une migration
Nous souhaitons ajouter trois colonnes dans notre table, nous allons alors lancer un fichier de migration. En utilisant la commande :
rails g migration AddColToProductuis :produits longitude:float latitude:float
Une fois le fichier de migration créé, si nous sommes d’accord, lancer un rails db:migrate
rails db:migrate
Ajouter le champs adresse :
Pour ajouter une adresse sur notre formulaire, il vous suffit d’aller dans la view et de rentrer cette ligne :
<%= simple_form_for @produit do |f| %>
<%= f.input :address %>
<%= f.submit %>
Nous avons maintenant un champ adresse dans notre formulaire de création :
Nous allons créer un produit avec une adresse et vérifier notre enregistrement en base de donnée :
Erreur commune, nous devons ajouter les params dans le controller de notre model (produit) :
Adapter notre model pour recevoir une adresse
Pour adapter notre model, il nous faut indiquer à la gem geocoder, dans le model produit :
geocoded_by :address
after_validation :geocode, if: :will_save_change_to_address?
Configurer Geocoder
Pour lancer la configuration automatique de geocoder lancer la commande :
rails generate geocoder:config
Nous devons aussi aller dans le fichier geocoder config afin de modifier la configuration sur les unités de mesure ainsi que sur la langue. Décommenter les lignes + modifier par vos valeurs (voir screen)
Vérifions notre vue :
Vérifions maintenant les données enregistrées dans la DB. Pour cela lancer dans le terminale :
rails c
Voici la data complété par notre gem ! Bravo 🎉 🎊
Connecter un service de mapping
Avant de commencer il vous faudra, vous créer un compte sur Mapbox. Une fois connecté récupérer la clef API qui doit être mise dans le fichier .env de votre application rails.
⚠️ N’oubliez pas de partager votre clef avec vos collaborateurs
Installer le javascript ainsi que le css de votre carte
Pour installer le style et les functions de javascript / css de votre service de mapping Mapbox, il vous faudra ajouter les lignes de codes suivantes dans votre fichier application.html.erb
<link href='https://api.mapbox.com/mapbox-gl-js/v2.11.0/mapbox-gl.css' rel='stylesheet' />
# dans le terminale taper :
importmap pin mapbox-gl
Insérer votre map dans la view
Pour insérer et voir si notre map s’affiche, nous allons installer le code suivant dans la view index de nos produits :
<div style="width: 100%; height: 600px;"
data-controller="map"
data-map-markers-value="<%= @markers.to_json %>"
data-map-api-key-value="<%= METTRE VOTRE CLEF API !!! %>"></div>
Coder le controller pour afficher la map
Pour pouvoir afficher votre map, nous allons devoir aller dans le controlleur de notre view est insérer le code suivant :
@markers = @produits.geocoded.map do |produit|
{
lat: produit.latitude,
lng: produit.longitude
}
Connecter notre map / controller avec du javascript (stimulus framework)
Avant de terminer et de pouvoir afficher notre map avec nos markers, nous allons devoir créer un controller javascript via le framework stimulus afin de rajouter quelques lignes de codes pour afficher notre map avec la localisation de nos produits.
Pour créer notre contrôleur stimulus :
rails g stimulus map
Ajouter notre code pour afficher les markers et la map dans notre controller stimulus
Remplacer et copier / coller tous le code présent dans votre contrôleur stimulus créé :
import { Controller } from "@hotwired/stimulus"
import mapboxgl from 'mapbox-gl'
export default class extends Controller {
static values = {
apiKey: String,
markers: Array
}
connect() {
mapboxgl.accessToken = this.apiKeyValue
this.map = new mapboxgl.Map({
container: this.element,
style: "mapbox://styles/mapbox/streets-v10"
})
this.#addMarkersToMap()
this.#fitMapToMarkers()
}
#addMarkersToMap() {
this.markersValue.forEach((marker) => {
const popup = new mapboxgl.Popup().setHTML(marker.info_window)
new mapboxgl.Marker()
.setLngLat([ marker.lng, marker.lat ])
.setPopup(popup)
.addTo(this.map)
})
}
#fitMapToMarkers() {
const bounds = new mapboxgl.LngLatBounds()
this.markersValue.forEach(marker => bounds.extend([ marker.lng, marker.lat ]))
this.map.fitBounds(bounds, { padding: 70, maxZoom: 15, duration: 0 })
}
}
Dernière étape pour faire fonctionner la pop up
Ajouter dans le controller :
def show
@flats = Flat.all
@markers = @flats.geocoded.map do |flat|
{
lat: flat.latitude,
lng: flat.longitude,
info_window: render_to_string(partial: "info_window", locals: {flat: flat})
}
end
end
Puis vous aller créer un fichier :
_info_window.html.erb
<h2><%= flat.name %></h2>
<p><%= flat.address %></p>