无法访问来自 Jquery 的关联模型

Can not reach to associated models from Jquery

我有关联的模型。船和位置模型。我正在尝试从 Jquery 代码访问 Boat Model,但我做不到。事情;我 return Jquery 的所有位置作为 listing 并且它包含地址,boat_id 等。所以 listing.address 有效,listing.boat_id 有效但 listing.boat.year(例如)不起作用。它给出了一个错误; Boat 未定义,因为它不是 rails 代码,对吧?。但是我找不到通过它的方法。它应该像 <%= listing.Boat.model %>.

我想知道可能是因为js函数使用了parse.HTML。这是将给定列表插入 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 );
        }

这是协会; 船 has_one :location 位置 belongs_to :boat

这是 html.erb 文件中的 jquery

<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>

我不知道与此相关的是 locations_controller,它将数据发送到 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

所以实际上在 rails 控制台中,例如 Location.last.Boat.year 有效。谢谢您的帮助。我很感激!

PS: 这是我从 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}]}

并且 js 代码将其作为列表获取。所以我认为; <%= listing.boat.model %> 应该可以,但会报错;

NameError in LocationsController#index
undefined local variable or method 'listing' for #<#<Class:0x007f9665a25758>:0x007f96658c93a0>

编辑 1:

这是完整的js文件;

(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 );

您很可能试图在 ruby 中使用 javascript 变量。

这种混淆是避免混合客户端和服务器端代码的众多原因之一。

相反,您可以使用数据属性和 ajax 将数据传递给 javascript。

<div id="map-canvas" data-initlat="<%= @initlat %>"></div>

或者另一个例子:

<body data-assets-path="<%= assets_path %>">.

在您的情况下,您需要确保 request_listings 调用的任何操作都提供呈现列表所需的 JSON 数据。