Reputation: 2715
I'm trying to figure out how to get a map to display the address a user creates.
I have an address model and a projects model.
The associations are:
Address:
belongs_to :addressable, :polymorphic => true
Project:
has_many :addresses, as: :addressable
accepts_nested_attributes_for :addresses, reject_if: :all_blank, allow_destroy: true
In address.rb, I have:
def full_project_address_formal
[self.first_line, middle_line, last_line, country_name].compact.join("<br>").html_safe
end
I also then have:
def first_line
[unit, street_number, street.titlecase].join(' ')
end
def middle_line
if self.building.present?
end
end
def last_line
[city.titlecase, region.titlecase, zip].join(' ')
end
def country_name
country = self.country
ISO3166::Country[country]
end
In my show page, I then have:
<%= @project.addresses.first.project_address %>
All of that works to display the project address.
I then want to display a map.
I have installed these gems:
gem 'geocoder'
gem 'gmaps4rails'
gem 'underscore-rails'
gem 'countries'
gem 'country_select'
In my application.js, I have:
//= require gmap3.min
//= require underscore
In my address.rb, I have:
geocoded_by :full_project_address_formal # can also be an IP address
after_validation :geocode
In my address controller I have (I don't know why - I copied it from another post on SO - although my address model does have latitude and longitude in the schema):
def index
@addresses = Address.all
authorize @addresses
@hash = Gmaps4rails.build_markers(@addresses) do |address, marker|
marker.lat address.latitude
marker.lng address.longitude
end
end
I'm completely lost for what to do next. I've tried at least 30 different ways of trying to display the address in a map.
<strong>PROJECT HQ</strong>
<ul class="map-list medium-text">
<%= @project.addresses.first.project_address %>
<!-- <li><span data-icon=""></span>[email protected]</li> -->
</ul>
</div>
</div>
<div class="two-cols-column">
<div id="map">
</div>
</div>
In my main.js file, I have:
if (dp.fn.gmap3) {
var target_map = dp('#map');
var lat = target_map.data('lat');
var lng = target_map.data('lng');
target_map.gmap3({
marker: {
latLng: [lat, lng],
draggable: false
},
map: {
options: {
zoom: 12,
scrollwheel: false,
disableDefaultUI: true,
styles:
[{"featureType": "landscape.man_made", "elementType": "geometry", "stylers": [{"color": "#f7f1df"}]}, {"featureType": "landscape.natural", "elementType": "geometry", "stylers": [{"color": "#d0e3b4"}]}, {"featureType": "landscape.natural.terrain", "elementType": "geometry", "stylers": [{"visibility": "off"}]}, {"featureType": "poi", "elementType": "labels", "stylers": [{"visibility": "off"}]}, {"featureType": "poi.business", "elementType": "all", "stylers": [{"visibility": "off"}]}, {"featureType": "poi.medical", "elementType": "geometry", "stylers": [{"color": "#fbd3da"}]}, {"featureType": "poi.park", "elementType": "geometry", "stylers": [{"color": "#bde6ab"}]}, {"featureType": "road", "elementType": "geometry.stroke", "stylers": [{"visibility": "off"}]}, {"featureType": "road", "elementType": "labels", "stylers": [{"visibility": "off"}]}, {"featureType": "road.highway", "elementType": "geometry.fill", "stylers": [{"color": "#ffe15f"}]}, {"featureType": "road.highway", "elementType": "geometry.stroke", "stylers": [{"color": "#efd151"}]}, {"featureType": "road.arterial", "elementType": "geometry.fill", "stylers": [{"color": "#ffffff"}]}, {"featureType": "road.local", "elementType": "geometry.fill", "stylers": [{"color": "black"}]}, {"featureType": "transit.station.airport", "elementType": "geometry.fill", "stylers": [{"color": "#cfb2db"}]}, {"featureType": "water", "elementType": "geometry", "stylers": [{"color": "#a2daf2"}]}]
}
}
});
}
I"m lost and stuck. Does anyone know how to get from where I am to the point where I can take an address and produce a map in my show?
A SECOND ATTEMPT. HAVING WATCHED THIS YOU TUBE VIDEO: https://www.youtube.com/watch?v=R0l-7en3dUw&feature=youtu.be
I'm still stuck, but not sure how to approach solving this problem. My complete address setup is now:
gems:
gem 'geocoder'
gem 'gmaps4rails'
gem 'underscore-rails'
gem 'countries'
gem 'country_select'
application.js
//= require underscore
//= require gmaps/google
vendor/assets/javascript/ underscore.js
I copied and pasted the entire underscore production version. In the video, that appears to be 1 uncommented line. I couldn't find that. Instead, I have a long page of gibberish.
address model:
class Address < ActiveRecord::Base
geocoded_by :full_address # can also be an IP address
before_save :capitalise_address
before_save :upcase_zip
# --------------- associations
belongs_to :addressable, :polymorphic => true
# --------------- scopes
# --------------- validations
validates_presence_of :street_number, :street, :zip, :country
# --------------- class methods
def first_line
[unit, street_number, street.titlecase].join(' ')
end
def middle_line
if self.building.present?
end
end
def last_line
[city.titlecase, region.titlecase, zip].join(' ')
end
def country_name
country = self.country
ISO3166::Country[country]
end
def full_address
[self.first_line, middle_line, last_line, country_name].compact.join("<br>").html_safe
end
after_validation :geocode#, if self.full_address.changed?
end
address controller:
def index
@addresses = Address.all
authorize @addresses
@hash = Gmaps4rails.build_markers(@addresses) do |address, marker|
marker.lat address.latitude
marker.lng address.longitude
end
end
I don't know why this is in an index action. I"m trying to use a projects/show action. I've not understood the reasons for the above step.
projects show:
<div id="map">
<%= render partial: "address" %>
</div>
views/projects/_address.html.erb
<script src="//maps.google.com/maps/api/js?v=3.18&sensor=false&client=&key=&libraries=geometry&language=&hl=®ion="></script>
<script src="//google-maps-utility-library-v3.googlecode.com/svn/tags/markerclustererplus/2.0.14/src/markerclusterer_packed.js"></script>
<script src='//google-maps-utility-library-v3.googlecode.com/svn/tags/infobox/1.1.9/src/infobox_packed.js' type='text/javascript'></script> <!-- only if you need custom infoboxes -->
Not sure if this file is supposed to have any html in it. following this tutorial ( https://github.com/apneadiving/Google-Maps-for-Rails), I've no clue as to how the maps (even if it is working, would know what address to use.
app/assets/javascripts/addresses.js
handler = Gmaps.build('Google');
handler.buildMap({ provider: {}, internal: {id: 'map'}}, function(){
markers = handler.addMarkers(<%=raw @hash.to_json %>);
handler.bounds.extendWith(markers);
handler.fitMapToBounds();
});
not sure if Im supposed to put the above inside script tags
I'm lost. At this point, I have an error that says:
ExecJS::RuntimeError at /projects/26
SyntaxError: [stdin]:13:32: unexpected <
I don't know where to look for the error because I don't know what anything is supposed to look like. I'm lost and stuck. I have read the google api documentation (it assumes knowledge of js at a level that I don't have) and all of the geocoder and gmaps4rails wiki documentation.
A THIRD ATTEMPT
I found this wiki resource, which gives template js and html. http://apneadiving.github.io
I replace the content of my addresses.js file with:
var handler = Gmaps.build('Google');
handler.buildMap({ internal: {id: 'geolocation'} }, function(){
if(navigator.geolocation)
navigator.geolocation.getCurrentPosition(displayOnMap);
});
function displayOnMap(position){
var marker = handler.addMarker({
lat: position.coords.latitude,
lng: position.coords.longitude
});
handler.map.centerOn(marker);
};
And add make the content of my partial:
<script src="//maps.google.com/maps/api/js?v=3.18&sensor=false&client=&key=&libraries=geometry&language=&hl=®ion="></script>
<script src="//google-maps-utility-library-v3.googlecode.com/svn/tags/markerclustererplus/2.0.14/src/markerclusterer_packed.js"></script>
<script src='//google-maps-utility-library-v3.googlecode.com/svn/tags/infobox/1.1.9/src/infobox_packed.js' type='text/javascript'></script> <!-- only if you need custom infoboxes -->
<div style='width: 800px;'>
<div id="geolocation" style='width: 800px; height: 400px;'></div>
</div>
I get an error that says:
ExecJS::RuntimeError at /projects/26
SyntaxError: [stdin]:2:1: reserved word 'var'
Thanks to Max below, for the help with removing the '.coffee' extension from my js files. Now, there is just a blank space where the map was supposed to be.
Upvotes: 1
Views: 756
Reputation: 394
If I understood you correctly, you want to display a map on a project's show page along with the project's address/addresses.
The @hash variable (from the tutorial) contains the required information to create markers on the map (eg. latitude, longitude etc) and it is used as markers = handler.addMarkers(<%=raw @hash.to_json %>);
which then actually adds the markers with that information.
In your case, since you need the map on project's show page, you should set @hash in show action of the ProjectsController with @addresses set to whatever addresses you want to display on the page - presumably @project.addresses, where @project value is set before @addressses.
I think your lat & lng are stored not in fields/columns named lat & lng but latitude & longitude in which case you need to mention them specifically like this - geocoded_by :full_project_address_formal, latitude: :lat, longitude: :lng
. You should make sure that the values of latitude & longitude fields are indeed present for the addresses in the database to be safe.
def show
@project = Project.find(params[:id])
@addresses = @project.addresses
@hash = Gmaps4rails.build_markers(@addresses) do |address, marker|
marker.lat address.latitude
marker.lng address.longitude
marker.infowindow address.full_project_address_formal
end
end
Once you set the value of @hash in ProjectsController's show action, you can access it inside a script tag in projects/show view. To start with, you can keep the show view simple as this.
<script src="//maps.google.com/maps/api/js?v=3.18&sensor=false&client=&key=&libraries=geometry&language=&hl=®ion="></script>
<script src="//google-maps-utility-library-v3.googlecode.com/svn/tags/markerclustererplus/2.0.14/src/markerclusterer_packed.js"></script>
<script src='//google-maps-utility-library-v3.googlecode.com/svn/tags/infobox/1.1.9/src/infobox_packed.js' type='text/javascript'></script> <!-- only if you need custom infoboxes -->
<div style='width: 800px;'>
<div id="map" style='width: 800px; height: 400px;'></div>
</div>
<script>
handler = Gmaps.build('Google');
handler.buildMap({ provider: {}, internal: {id: 'map'}}, function(){
markers = handler.addMarkers(<%=raw @hash.to_json %>);
handler.bounds.extendWith(markers);
handler.fitMapToBounds();
});
</script>
Hope this helps. If you get stuck somewhere or need assistance, let me know.
Upvotes: 3