I have associated models. Boat & Location Model. I am trying to reach to Boat Model from Jquery code but I could not do it. The thing; I return all the locations to Jquery as listing
and it contains address, boat_id etc. So listing.address
works, listing.boat_id
works but listing.boat.year
(for instance) does not work. It gives an error of; Boat is not defined because it is not rails code, right?. But I could not find a way to pass it. It should be smth like <%= listing.Boat.model %>
.
I wonder that might because of the js function uses parse.HTML
. Here is the function, which inserts given listings to the dom;
/*
*Insert given listings to the dom
*/
function insert_listing( index , listing ){
//create html for each listing using listing template function (options), and attach hover event listener which highlights the
//related marker when the listing is hovered (BECAUSE OF HERE??)
var html = $($.parseHTML(settings.listing_template( listing ))).wrap( settings.listing_wrapper ).parent().attr( 'data-mid' ,
index ).addClass( settings.listing_class ).mouseenter( function(){
var mid = $(this).attr('data-mid');
$.each(markers , function( index , marker ){
if( Number(marker.get('mid')) === Number( mid) ){
marker.setIcon( settings.highlighted_icon );
}
})
}).mouseleave(function(){
var mid = $(this).attr('data-mid');
$.each(markers , function(index , marker){
if(Number(marker.get('mid')) === Number( mid)){
marker.setIcon( settings.icon );
}
})
});
$(settings.listings_el).append( html );
}
Here are the associations;
Boat has_one :location
Location belongs_to :boat
Here is the jquery from html.erb file
<script>
(function ( $ ) {
$('#map-canvas').mapSearch({
request_uri: 'locations/show.json',
initialPosition: [ <%= @initlat %> , <%= @initlng %> ], #THIS WORKS
filters_form : '#filters',
listing_template : function(listing){
return '<div class="listing">'
+ '<h3>'+listing.address + '</h3>'
//<%= listing.Boat.model %> DOES NOT WORK
//<%= listing.boat.model %> DOES NOT WORK
+ '<div class="row">'
+ '<div class="col-sm-2">'
+ '<img class="thumbnail img-responsive" src="http://dummyimage.com/150x150/000/fff.jpg">'
+ '</div>'
+ '<div class="col-sm-5">'
+ '<p><strong>Address : </strong>' + listing.address+ '</p>'
+ '<p>'+listing.address+', '+listing.address+' '+listing.address+'</p>'
+ '<p>Reg Year: ' + listing.address+'</p>'
+ '</div>'
+ '<div class="col-sm-5">'
+ '<p><strong>Demo</strong> '+listing.address+'</p>'
+ '<p><strong>Demo</strong> '+listing.address+'</p>'
+ '</div>'
+ '</div>'
+ '</div>';
},
marker_clusterer : true
});
}( jQuery ));
</script>
I do not know if relevant this is the locations_controller, which sends data to jquery;
class LocationsController < ApplicationController
def index
if params[:search].present?
location = Geocoder.search(params[:search])
@locations =location[0]
else
@locations = Location.all.first
end
@initlat = @locations.latitude
@initlng = @locations.longitude
end
def show
#I ll process these later
ne_lat = params[:ne_lat].to_f
ne_lng = params[:ne_lng].to_f
sw_lat = params[:sw_lat].to_f
sw_lng = params[:sw_lng].to_f
mylatlong2 = Location.all
locs = {'results' => mylatlong2}
respond_to do |format|
format.html
format.json {render json: locs}
end
end
end
So actually in the rails console, Location.last.Boat.year
works for instance. Thank you for your help. I appreciate!.
PS: This is what I get from get request (controller);
{"results":[{"id":15,"address":"Ataköy Marina, 34140, Bakırköy, İstanbul, Türkiye","longitude":28.874432,"latitude":40.971388,"location_type":null,"boat_id":250,"created_at":"2015-05-17T11:36:29.245Z","updated_at":"2015-05-17T11:36:29.245Z","distance":0.060815068242947884,"bearing":135.0},{"id":16,"address":"Ataköy Marina, İstanbul, Türkiye","longitude":28.874432,"latitude":40.971388,"location_type":null,"boat_id":251,"created_at":"2015-05-21T21:27:43.366Z","updated_at":"2015-05-21T21:27:43.366Z","distance":0.060815068242947884,"bearing":135.0},{"id":1,"address":null,"longitude":28.87443200000007,"latitude":40.971388,"location_type":null,"boat_id":null,"created_at":"2015-05-12T08:01:08.899Z","updated_at":"2015-05-12T08:01:19.769Z","distance":0.06081506824595426,"bearing":135.0},{"id":2,"address":null,"longitude":28.87443200000007,"latitude":40.971388,"location_type":null,"boat_id":null,"created_at":"2015-05-12T08:01:26.659Z","updated_at":"2015-05-12T08:02:14.615Z","distance":0.06081506824595426,"bearing":135.0},{"id":3,"address":null,"longitude":28.87443200000007,"latitude":40.971388,"location_type":null,"boat_id":null,"created_at":"2015-05-12T08:02:32.089Z","updated_at":"2015-05-12T08:03:11.074Z","distance":0.06081506824595426,"bearing":135.0},{"id":4,"address":null,"longitude":28.87443200000007,"latitude":40.971388,"location_type":null,"boat_id":null,"created_at":"2015-05-12T08:03:14.706Z","updated_at":"2015-05-12T08:03:50.343Z","distance":0.06081506824595426,"bearing":135.0},{"id":5,"address":"Ataköy Marina, 34140, Bakırköy, İstanbul, Türkiye","longitude":28.87443200000007,"latitude":40.971388,"location_type":null,"boat_id":242,"created_at":"2015-05-12T08:03:56.194Z","updated_at":"2015-05-12T08:03:56.194Z","distance":0.06081506824595426,"bearing":135.0},{"id":6,"address":"Ataköy Marina, 34140, Bakırköy, İstanbul, Türkiye","longitude":28.87443200000007,"latitude":40.971388,"location_type":null,"boat_id":243,"created_at":"2015-05-12T08:07:03.799Z","updated_at":"2015-05-12T08:07:03.799Z","distance":0.06081506824595426,"bearing":135.0},{"id":7,"address":"Ataköy Marina, 34140, Bakırköy, İstanbul, Türkiye","longitude":28.87443200000007,"latitude":40.971388,"location_type":null,"boat_id":244,"created_at":"2015-05-12T08:08:25.252Z","updated_at":"2015-05-12T08:08:25.252Z","distance":0.06081506824595426,"bearing":135.0},{"id":8,"address":"Ataköy Marina, 34140, Bakırköy, İstanbul, Türkiye","longitude":28.87443200000007,"latitude":40.971388,"location_type":null,"boat_id":245,"created_at":"2015-05-12T08:20:38.188Z","updated_at":"2015-05-12T08:20:38.188Z","distance":0.06081506824595426,"bearing":135.0},{"id":9,"address":"Ataköy Marina, 34140, Bakırköy, İstanbul, Türkiye","longitude":28.87443200000007,"latitude":40.971388,"location_type":null,"boat_id":246,"created_at":"2015-05-12T08:21:34.724Z","updated_at":"2015-05-12T08:21:34.724Z","distance":0.06081506824595426,"bearing":135.0},{"id":10,"address":"Ataköy Marina, 34140, Bakırköy, İstanbul, Türkiye","longitude":28.87443200000007,"latitude":40.971388,"location_type":null,"boat_id":247,"created_at":"2015-05-12T08:22:49.400Z","updated_at":"2015-05-12T08:22:49.400Z","distance":0.06081506824595426,"bearing":135.0},{"id":11,"address":"Fenerbahçe Yat Limanı, Kadıköy, Türkiye","longitude":29.037873999999988,"latitude":40.970286,"location_type":null,"boat_id":248,"created_at":"2015-05-12T08:23:43.187Z","updated_at":"2015-05-12T08:23:43.187Z","distance":7.03002425919155,"bearing":135.0},{"id":13,"address":"Fenerbahçe Yat Limanı, Kadıköy, Türkiye","longitude":29.037874,"latitude":40.970286,"location_type":null,"boat_id":249,"created_at":"2015-05-12T14:59:01.117Z","updated_at":"2015-05-12T14:59:01.117Z","distance":7.030024259192001,"bearing":135.0},{"id":14,"address":"Fenerbahçe Yat Limanı, Kadıköy, Türkiye","longitude":29.037874,"latitude":40.970286,"location_type":null,"boat_id":null,"created_at":"2015-05-17T11:36:03.798Z","updated_at":"2015-05-17T11:36:05.476Z","distance":7.030024259192001,"bearing":135.0}]}
and the js code gets it as listing. So I thought; <%= listing.boat.model %>
should work but gives error;
NameError in LocationsController#index
undefined local variable or method 'listing' for #<#<Class:0x007f9665a25758>:0x007f96658c93a0>
EDIT 1:
This is the full js file;
(function ( $ , window , undefined) {
$.fn.mapSearch = function ( options ) {
var el , settings , markers = [] , params , extra_params = [] , marker , markerClusterer, mapOptions , map , infowindow;
el = this[0];
/*
*Default settings for the plugin.
*/
settings = $.extend({
/*
*Number: Initial zoom level of the map.
*/
zoom: 6,
/*
*Array: Initial position coordinates of the map [latitude , longitude].
*/
initialPosition: [40, -100],
/*
*String: URL where the plugin will make ajaz request for json data
*/
request_uri : '',
/*
*String: ID of the element you want to insert listings in
*/
listings_el : '#ms-listings',
/*
*String: ID of the element you want to insert pagination in
*/
pagination_el : '#ms-pagination',
/*
*Function: Template function that receives a listing as parameter and returns HTML for it
*/
listing_template : function(listing){
return '<div class="listing">'
+ '<h3>'+listing.name + '</h3>'
+ '<p><strong>Address : </strong>' + listing.address+ '</p>'
+ '<p><strong>Women owned:</strong> '+listing.women+'</p>'
+ '<p><strong>Accept Govt Credit card:</strong> '+listing.gcc+'</p>'
+ '</div>';
},
/*
*String: Wrapper around each listing
*/
listing_wrapper : '<div></div>',
/*
*Function: Receives entire response as parameter and returns page number identifier in the response
*/
page_number : function(data){
return 3/*data.meta.page BURASI DEĞİŞECEK!!!!!!*/;
},
/*
*Function: Receives a listing as parameter and returns an array of latitude and longitude pair
*/
listing_latlng: function(listing){
return [listing.latitude , listing.longitude];
},
/*
*Function: Receives a listing as parameter and returns Content for infowindow of each marker
*/
infowindow_content : function(listing){
return '<div>' + listing.name + '<div>';
},
/*
*String : Class to be added to map container
*/
map_class : 'ms-map',
/*
*String : Class to be added to listings container
*/
listings_class : 'ms-results',
/*
*String : Class to be added to single listing container
*/
listing_class : 'ms-listing',
/*
*String : Class to be added to pagination links
*/
pagi_link_class : 'ms-pagination-button',
/*
*String : Text that appears on link to next page
*/
next_btn_text : 'Next',
/*
*String : Text that appears on link to previous page
*/
prev_btn_text : 'Previous',
/*
*String : Class to be added to show loading indicator
*/
loading_class : 'loading',
/*
*String : Path to marker icon to be used for each listing
*/
icon : "<%= asset_path 'normal.png' %>", //Icon to be used on map
/*
*String : Path to highlighted marker icon to be used for each listing
*/
highlighted_icon : "<%= asset_path 'highlight.png' %>",
/*
*String : Identifier of the listings array in response data
*/
results_key : 'results',
/*
*Boolean : False for no filters, form ID for using filters
*/
filters_form : false,
/*
*Boolean : To enable marker clusters, set this to true, otherwise false
*/
marker_clusterer : false,
/*
*Boolean : To enable search box, set this to true, otherwise false
*/
search_box : true,
/*
*String : Class to be added to search box
*/
searchbox_class : 'form-control',
searchbox_placeholder : 'Search for a location',
}, options );
/*
*Adding Plugin Classes
*/
$( settings.listings_el ).addClass( settings.listings_class );
$( el ).addClass( settings.map_class );
/*
*Initializing the map
*/
mapOptions = {
center: new google.maps.LatLng( settings.initialPosition[0] , settings.initialPosition[1] ),
zoom: settings.zoom,
streetViewControl: false,
panControl: true,
panControlOptions: {
position: google.maps.ControlPosition.RIGHT_BOTTOM
},
zoomControlOptions: {
style: google.maps.ZoomControlStyle.LARGE,
position: google.maps.ControlPosition.LEFT_BOTTOM
},
};
map = new google.maps.Map( el, mapOptions );
/*
*Add searchbox if enabled in options
*/
if( settings.search_box ){
if(typeof google.maps.places === "object"){
$( el ).prepend( '<input style="top:25px !important;" type="text" id="search-form">' );
var input = (document.getElementById('search-form'));
$('#search-form').addClass( settings.searchbox_class ).prop('placeholder' , settings.searchbox_placeholder);
map.controls[google.maps.ControlPosition.TOP_CENTER].push(input);
var searchBox = new google.maps.places.SearchBox(input);
google.maps.event.addListener(searchBox, 'places_changed', function() {
var place = searchBox.getPlaces();
if(place.length > 0){
map.panTo(place[0].geometry.location);
}
});
}else{
alert('Google Places library not found')
}
}
/*
*Initializing the InfoWindow for markers
*/
infowindow = new google.maps.InfoWindow();
/*
*Initializing clusterer if needed
*/
if(settings.marker_clusterer && typeof MarkerClusterer === 'function'){
markerClusterer = new MarkerClusterer(map, markers, {gridSize: 50, maxZoom: 15});
}
/*
*Adding an event listener for every time the user moves or zooms the map, we refresh the listings search
*/
new google.maps.event.addListener( map , 'idle' , function(){
params = get_bounds();
request_listings( extra_params );
});
/*
*Utility function: To get the bounds of the map
*/
function get_bounds(){
return {
sw_lat : map.getBounds().getSouthWest().lat(),
sw_lng : map.getBounds().getSouthWest().lng(),
ne_lat : map.getBounds().getNorthEast().lat(),
ne_lng : map.getBounds().getNorthEast().lng()
};
}
/*
*Function to make an ajax request to server for data
*Most of the other functions are called inside this one.
*/
function request_listings( new_params ){
//checking if the request url is provided
if(settings.request_uri != ''){
//Add loading indicator class
$(el).addClass( settings.loading_class );
$(settings.listings_el).addClass( settings.loading_class );
//make the ajax request with all the parameters as get variables
$.get(settings.request_uri+ '?' + $.param( $.extend(params , new_params) ), function(data){
//deleting old markers
deleteMarkers();
//removing old listings
$(settings.listings_el).empty();
//processing the returned data. Adding listings to the page and create markers
$.each(data[ settings.results_key ] , function( index , value ){
insert_listing( index , value );
addMarker( index , value );
});
//remove the previous pagination and add new one
$(settings.pagination_el).empty().prepend(create_pagination(settings.page_number(data)));
//bind click events to pagination buttons
$('.'+settings.pagi_link_class).click(function(){
extra_params['page'] = $(this).data('href');
$.fn.mapSearch.update(extra_params);
});
//add markers to the map
if(settings.marker_clusterer && typeof MarkerClusterer === 'function'){
markerClusterer.clearMarkers();
markerClusterer.addMarkers(markers);
}else{
showMarkers();
}
//remove loading class
$(el).removeClass( settings.loading_class );
$(settings.listings_el).removeClass( settings.loading_class );
});
}
}
//Handle the filters form.
processFilters();
/*
*Attach the infowindow created previously to a marker that is clicked, receives a mcontent string and marker as parameter
*/
function makeInfoWindowEvent( contentString, marker ) {
google.maps.event.addListener( marker, 'click', function() {
infowindow.setContent( contentString );
infowindow.open( map, marker );
});
}
/*
*Creates a marker from given listing and adds to the markers array
*/
function addMarker( index , listing ) {
var latlng = settings.listing_latlng( listing );
var marker = new google.maps.Marker({
position: new google.maps.LatLng( latlng[0], latlng[1] ),
title : listing.name,
mid : index,
icon : settings.icon,
});
if(!settings.marker_clusterer){
marker.setMap(map);
}
//Attach infowindow event to the marker
makeInfoWindowEvent(settings.infowindow_content( listing ), marker );
//add to array
markers.push(marker);
}
//Set markers on the map
function setAllMap(map) {
for (var i = 0; i < markers.length; i++) {
markers[i].setMap(map);
}
}
//Remove markers from map
function clearMarkers() {
setAllMap(null);
}
//Show all markers present in array
function showMarkers() {
setAllMap(map);
}
/*
*Function : Receives current page number as parameter, returns HTML for pagination
*/
function create_pagination(page_number){
var prev = page_number > 1 ? '<li><a href="#" class="'+ settings.pagi_link_class +'" data-href="'+ (page_number - 1) +'">'+ settings.prev_btn_text +'</a></li>' : '';
var next = '<li><a href="#" class="'+ settings.pagi_link_class +'" data-href="'+ (page_number + 1) +'">' + settings.next_btn_text + '</a></li>';
return $(prev + next).wrapAll('<ul></ul>').parent().addClass('pagination');
}
/*
*Attach an event listener to filters form
*Whenever form values are changed, update the map and listings
*/
function processFilters(){
if(settings.filters_form != false && typeof settings.filters_form === 'string'){
$(settings.filters_form + ' :input').change(function(){
var filters = $(settings.filters_form).serializeArray();
var params = [];
for(var i in filters){
params[filters[i].name] = filters[i].value;
}
$.fn.mapSearch.update(params);
});
}
}
/*
*Delete all markers from array
*/
function deleteMarkers() {
clearMarkers();
markers = [];
}
/*
*Insert given listings to the dom
*/
function insert_listing( index , listing ){
//create html for each listing using listing template function (options), and attach hover event listener which highlights the
//related marker when the listing is hovered
var html = $($.parseHTML(settings.listing_template( listing ))).wrap( settings.listing_wrapper ).parent().attr( 'data-mid' ,
index ).addClass( settings.listing_class ).mouseenter( function(){
var mid = $(this).attr('data-mid');
$.each(markers , function( index , marker ){
if( Number(marker.get('mid')) === Number( mid) ){
marker.setIcon( settings.highlighted_icon );
}
})
}).mouseleave(function(){
var mid = $(this).attr('data-mid');
$.each(markers , function(index , marker){
if(Number(marker.get('mid')) === Number( mid)){
marker.setIcon( settings.icon );
}
})
});
$(settings.listings_el).append( html );
}
/*
*A utility method for updating the map with some new parameters
*/
$.fn.mapSearch.update = function(new_params){
extra_params = new_params;
params = get_bounds();
request_listings( extra_params );
delete extra_params['page'];
}
}
})( jQuery );
You are most likely trying to use javascript variable in ruby.
This kind of confusion is one many reasons to avoid intermingling your client side and server side code.
Instead you can use data attributes and ajax to pass data to javascript.
<div id="map-canvas" data-initlat="<%= @initlat %>"></div>
Or another example:
<body data-assets-path="<%= assets_path %>">.
In your case you need to make sure that whatever action request_listings
calls delivers the JSON data needed to render the listing.