RailsGoogleMap
Rails view helpers that drop an embedded Google Map into a page from an address or a lat/lng pair.
The point of the gem is that it works with or without a Google Maps API key. With a key it uses the official Maps Embed API and you get zoom, map type and language control. Without one it falls back to Google's keyless embed endpoint, which needs no key and no billing account — handy for a staging box, a side project, or a page that just needs to show where you are.
<%= google_map_for("Thamel, Kathmandu") %>
Three ways in, depending on how much of the markup you want to own:
| | |
| --- | --- |
| google_map_embed_url(query) | just the URL — build your own markup |
| google_map_for(query, ...) | an <iframe> tag, optionally wrapped in a div |
| render_google_map(query, ...) | a partial you can copy into your app as ERB or Slim and edit |
Installation
Add it to your Gemfile:
gem "rails_google_map"
Then:
bundle install
Or install it directly:
gem install rails_google_map
Requirements
| Supported | |
|---|---|
| Ruby | 2.5.0 and up (verified on 2.5.1) |
| Rails (ActionView) | 5.0 through 8.x |
The suite is verified against the ends of that range: Ruby 2.5.1 with Rails 5.0 and 5.2, and Ruby 3.3 with Rails 8.1.
Installing on Ruby 2.5: use Bundler. The RubyGems that ships with Ruby 2.5
(2.7.x) ignores a dependency's required_ruby_version when resolving, so a bare
gem install rails_google_map reaches for the newest ActionView and fails on a
Ruby 3.2+ dependency. Bundler resolves it correctly, as does RubyGems 3.0+
(gem update --system '~> 3.0').
Configuration
Configuration is optional — skip it entirely and the keyless fallback is used.
To use the Maps Embed API, create config/initializers/rails_google_map.rb:
RailsGoogleMap.configure do |config|
config.api_key = ENV["GOOGLE_MAPS_EMBED_KEY"]
config.zoom = 15 # default zoom level
config.map_type = "roadmap" # "roadmap" or "satellite"
config.width = "100%" # default iframe width
config.height = "450" # default iframe height
config.language = nil # e.g. "en", "ne" — omitted when nil
# used by render_google_map and the partial
config.wrapper_class = "google-map" # class on the surrounding div
config.map_class = nil # class on the iframe
config.partial = "rails_google_map/map"
end
If you don't set api_key at all, the gem picks up GOOGLE_MAPS_EMBED_KEY or
GOOGLE_MAPS_API_KEY from the environment, so an initializer is often unnecessary.
Keep the key out of source control, and restrict it to the Maps Embed API and to your own HTTP referrers in the Google Cloud console — an embed key travels to the browser inside the iframe URL and is public by nature.
Usage
In a Rails app the helpers are mixed into every view automatically.
google_map_for
<%= google_map_for("Thamel, Kathmandu") %>
<%= google_map_for(@business.address, height: "300", zoom: 17) %>
<%= google_map_for(lat: 27.7172, lng: 85.3240) %>
<%= google_map_for("Thamel", class: "office-map", title: "Our office") %>
The first argument is an address, or a "lat,lng" string. Alternatively pass
lat: and lng: (long: also works). When both an address and coordinates are
given the address wins — lat/lng columns tend to be unreliable, and often a
whole table shares one default pin.
Recognised options:
| Option | Default | Notes |
|---|---|---|
width |
"100%" |
iframe width |
height |
"450" |
iframe height |
zoom |
15 |
Embed API only; ignored without a key |
map_type |
"roadmap" |
Embed API only; "roadmap" or "satellite" |
language |
nil |
Embed API only |
api_key |
configured key | override the key for one call |
lat / lng |
— | used when no address is given |
wrapper |
nil |
true for the configured wrapper class, a CSS class, or a Hash of div attributes |
Any other option is passed straight through as an iframe attribute (class,
title, data, …).
By default it returns a bare <iframe>. Pass wrapper: to get the surrounding
div without reaching for the partial:
<%= google_map_for("Thamel", wrapper: true) %>
<%= google_map_for("Thamel", wrapper: "map-box", class: "partners-map") %>
<%= google_map_for("Thamel", wrapper: { class: "map-box", data: { controller: "map" } }) %>
google_map_for returns nil when there is nothing to show — a blank address, or
coordinates that are missing or 0,0. So a caller can guard on it:
<% if (map = google_map_for(@business.address, lat: @business.latitude, lng: @business.longitude)) %>
<div class="google-map"><%= map %></div>
<% end %>
embed_google_map
The same thing with a plain options hash, if that reads better at the call site:
<%= embed_google_map(address: @business.address, height: 300) %>
<%= embed_google_map(lat: 27.7172, long: 85.3240) %>
render_google_map — the full markup, from a partial you can edit
google_map_for builds its tag in Ruby, so the markup is fixed. When you want to
own the markup, render_google_map renders a partial instead — wrapper div and
all:
= render_google_map(@business.map_query, title: t("partners.map_of", name: @business.name), map_class: "partners-map")
<%= render_google_map(@business.map_query, title: t("partners.map_of", name: @business.name), map_class: "partners-map") %>
Both produce:
<div class="google-map">
<iframe src="https://www.google.com/maps/embed?origin=mfe&pb=!1m2!2m1!1sThamel%2C+Kathmandu"
class="partners-map" title="Map of Thamel" width="100%" height="450"
style="border:0;" loading="lazy"
referrerpolicy="no-referrer-when-downgrade"
allowfullscreen frameborder="0"></iframe>
</div>
Like google_map_for, it returns nil when there is nothing to map, so the
surrounding if is optional.
Options: title, wrapper_class, map_class, width, height, plus the URL
options (zoom, map_type, language, api_key) and lat/lng. Anything else
is handed to the partial as an extra local, which is how a partial of your own
receives its data:
<%= render_google_map(@business.address, partial: "maps/card", label: "Find us") %>
Editing the markup
The gem ships the partial as ERB, which renders fine in a Slim app — Rails picks the handler per template. To change the markup, copy it into your app:
rails generate rails_google_map:views # app/views/rails_google_map/_map.html.erb
rails generate rails_google_map:views --format slim # app/views/rails_google_map/_map.html.slim
App view paths win over an engine's, so the copy takes over with no further configuration. The Slim copy is the markup you probably came here for:
- if url.present?
div class=wrapper_class
iframe src=url class=map_class title=title width=width height=height style="border:0;" loading="lazy" referrerpolicy="no-referrer-when-downgrade" allowfullscreen=true frameborder="0"
Or point at a partial of your own and leave the gem's alone:
RailsGoogleMap.configure { |config| config.partial = "shared/google_map" }
Your partial receives url, title, wrapper_class, map_class, width and
height as locals.
google_map_embed_url
Returns just the URL, for when you want to write the markup yourself:
("Thamel, Kathmandu")
# => "https://www.google.com/maps/embed?origin=mfe&pb=!1m2!2m1!1sThamel%2C+Kathmandu"
("Thamel, Kathmandu", zoom: 18) # with an API key configured
# => "https://www.google.com/maps/embed/v1/place?key=...&q=Thamel%2C+Kathmandu&zoom=18&maptype=roadmap"
It returns nil for a blank query.
Geocoding
If you want to build a richer map with the Maps JavaScript API instead of an iframe, the gem can turn an address into coordinates. This one does require an API key, with the Geocoding API enabled:
RailsGoogleMap::Geocoder.coordinates_for("Thamel, Kathmandu")
# => { lat: 27.7154, lng: 85.3123 }
Raises RailsGoogleMap::ConfigurationError when no key is configured, and
RailsGoogleMap::Geocoder::GeocodeError when the address can't be resolved or the
API call fails.
Outside Rails
google_map_embed_url and google_map_for need no booted Rails app — include the
helper anywhere. (render_google_map does need one, since it renders a template.)
require "rails_google_map"
class MapPresenter
include RailsGoogleMap::MapHelper
end
MapPresenter.new.google_map_for("Thamel, Kathmandu")
Keyless mode: what you give up
The keyless endpoint takes the place in pb, not in q — /maps/embed?q= answers
with a blank page, and /maps?q=...&output=embed merely redirects to the pb form.
It is an undocumented endpoint, so treat it as best-effort: it shows the place, but
zoom, map_type and language are ignored, and Google could change it. Configure
an API key for anything you depend on.
Development
After checking out the repo, run bin/setup to install dependencies. Then run
rake spec to run the tests. You can also run bin/console for an interactive
prompt.
To check the gem against a particular Rails release, set RAILS_VERSION:
RAILS_VERSION=5.0.0 bundle update railties && bundle exec rake spec
RAILS_VERSION=5.2 bundle update railties && bundle exec rake spec
bundle update railties && bundle exec rake spec # newest Rails
Gemfile.lock is not checked in, precisely so the same Gemfile can resolve under
Ruby 2.5 and Ruby 3.3.
To install this gem onto your local machine, run bundle exec rake install. To
release a new version, update the version number in version.rb, then run
bundle exec rake release, which creates a git tag, pushes commits and the tag, and
pushes the .gem file to rubygems.org.
The gemspec builds the file list from git ls-files, so a new file must be
git added or it will not be packaged, even though it works fine locally.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/sthaB-kash/rails_google_map. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.
License
The gem is available as open source under the terms of the MIT License.
Code of Conduct
Everyone interacting in the RailsGoogleMap project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.