用于jQueryUI自动完成的Rails应用程序中的CORS

时间:2014-03-06 13:41:34

标签: jquery ruby-on-rails json jquery-ui cors

我有一个Rails应用程序,我使用jQuery UI Autocomplete在搜索时建议产品名称 - 这一切都正常。但是我们已经推出了一个单独的论坛应用程序,它位于子域中,我也希望在那里提供相同的功能。

我在论坛上设置了jQuery UI,并且演示代码(数据以内联方式存在)工作正常。但是当我将源切换到我的rails应用mysite.com/products/names时,Chrome报告请求已被取消 - 这当然是因为跨网站请求,这意味着我必须使用JSONP或设置跨源资源共享。 / p>

在Rails IRC聊天室聊天后,建议我使用CORS,所以这是我选择的选项。

我已将此添加到我的应用程序控制器:

before_action :allow_cross_domain_access

def allow_cross_domain_access
  if request.headers["HTTP_ORIGIN"]
  # better way check origin
  # if request.headers["HTTP_ORIGIN"] && /^https?:\/\/(.*)\.some\.site\.com$/i.match(request.headers["HTTP_ORIGIN"])
    headers['Access-Control-Allow-Origin'] = '*'
    headers['Access-Control-Expose-Headers'] = 'ETag'
    headers['Access-Control-Allow-Methods'] = 'GET, POST, PATCH, PUT, DELETE, OPTIONS, HEAD'
    headers['Access-Control-Allow-Headers'] = '*,x-requested-with,Content-Type,If-Modified-Since,If-None-Match,Auth-User-Token'
    headers['Access-Control-Max-Age'] = '86400'
    headers['Access-Control-Allow-Credentials'] = 'true'
  end
end 

我将此作为js的起点:

$(function() {
    url = "http://www.mysite.com/products/names"
    $( "#search_bar" ).autocomplete(
    {
        crossDomain: true,
        type: "GET",
        dataType: "json",
        source: url,

    })
});

我需要离开这里的任何想法?作为参考,这里是来自docs的JSONP演示代码:
http://jqueryui.com/autocomplete/#remote-jsonp

  <script>
  $(function() {
    function log( message ) {
      $( "<div>" ).text( message ).prependTo( "#log" );
      $( "#log" ).scrollTop( 0 );
    }

    $( "#city" ).autocomplete({
      source: function( request, response ) {
        $.ajax({
          url: "http://ws.geonames.org/searchJSON",
          dataType: "jsonp",
          data: {
            featureClass: "P",
            style: "full",
            maxRows: 12,
            name_startsWith: request.term
          },
          success: function( data ) {
            response( $.map( data.geonames, function( item ) {
              return {
                label: item.name + (item.adminName1 ? ", " + item.adminName1 : "") + ", " + item.countryName,
                value: item.name
              }
            }));
          }
        });
      },
      minLength: 2,
      select: function( event, ui ) {
        log( ui.item ?
          "Selected: " + ui.item.label :
          "Nothing selected, input was " + this.value);
      },
      open: function() {
        $( this ).removeClass( "ui-corner-all" ).addClass( "ui-corner-top" );
      },
      close: function() {
        $( this ).removeClass( "ui-corner-top" ).addClass( "ui-corner-all" );
      }
    });
  });
  </script>

我有什么想法可以让它适应CORS吗?

编辑:我尝试过的......

(1)尝试使用JSONP(不确定如何使用CORS)。在我将500 Internal Server Error更改为name_startsWith之前,这给了我term。现在通过开发人员工具中的Chrome网络标签查看响应,我在响应中得到了我的建议(例如:["name1", "name2", "name3"],并在预览标签下显示为:

0: "name1"
1: "name2"
2: "name3"

我想我需要调整success,以便在搜索栏中显示这些建议:

 <script>
  $(function() {
    $( "#search_bar" ).autocomplete({
      source: function( request, response ) {
        $.ajax({
          url: "http://www.mysite.com/products/names?jsonp_callback=?",
          dataType: "jsonp",
          data: {
            term: request.term
          },
          success: function( data ) {
            response( $.map( data.geonames, function( item ) {
              return {
                label: item.name,
                value: item.name
              }
            }));
          }
        });
      },
      minLength: 2,
      select: function( event, ui ) {
        log( ui.item ?
          "Selected: " + ui.item.label :
          "Nothing selected, input was " + this.value);
      },
      open: function() {
        $( this ).removeClass( "ui-corner-all" ).addClass( "ui-corner-top" );
      },
      close: function() {
        $( this ).removeClass( "ui-corner-top" ).addClass( "ui-corner-all" );
      }
    });
  });
  </script>

以下是我在Rails应用程序中使用的coffeescript:

initialize = ->
  $('#search_bar').autocomplete
    source: $('#search_bar').data('autocomplete-source')
    select: (event, ui) ->
      $(this).parents("form").submit()
    focus: (event, ui) ->
       $('#search_bar').val(ui.item.value)

$(document).ready initialize

这是转换为JS:

jQuery(function() {
  return $('#search_bar').autocomplete({
    source: $('#search_bar').data('autocomplete-source'),
    select: function(event, ui) {
      return $(this).parents("form").submit();
    },
    focus: function(event, ui) {
      return $('#search_bar').val(ui.item.value);
    }
  });
});

理想情况下,我希望它以与在父应用程序中相同的方式执行。我需要离开这里的任何想法吗?

1 个答案:

答案 0 :(得分:1)

正如IRC讨论的那样,

$( "#breed" ).autocomplete({
      source: function( request, response ) {
        $.ajax({
          url: "http://yourservername.com/dogs/names",
          dataType: "jsonp",
          data: {
            featureClass: "P",
            style: "full",
            maxRows: 12,
            term: request.term
          },
          success: function( data ) {
            //console.log(data);
            response( $.map( data, function( item ) {
                return  item; 
            }));
          }
        });
      },
...

你的JSON实际上没有“对象”,只是一个数组..因此每个项目都可以作为项目返回..当你更改术语名称时,你也必须在这里更改参数。

Fiddle是通过IRC发送的,用JSON数据说明工作代码。

参考文献:http://jqueryui.com/autocomplete/#remote-jsonp