Sunday, May 1, 2011

Escaping HTML entities in the URL of a rails remote_function

Some content in my page is loaded dynamically with the use of this code :

javascript_tag( remote_function( :update => agenda_dom_id, :url => agenda_items_url(options), :method => :get ) )

When it outputs in the browser, it comes out as this :

new Ajax.Updater('agenda', 'http://localhost:3000/agenda_items?company=43841&history=true', {asynchronous:true, evalScripts:true, method:'get'})

The & character in the URL is replaced by & and so the second parameter of the request is discarded.

I made different tests and it looks as if Rails tries to make the HTML entities conversion as soon as it detects that the code is in a script tag. And trying to hardcode the link or the javascript tag didn`t change anything.

Anybody encountered this problem before?

From stackoverflow
  • All javascript characters are escaped (see the source of remote_function). That has some consequences. However in your case I don't see any problem, I have similar cases where this just works.

    Can you describe the problem you have with it?

    PS. I have posted I lighthouse ticket because I have a case where I need to insert javascript: https://rails.lighthouseapp.com/projects/8994/tickets/2500-remote_function-does-not-allow-dynamically-generation-of-url#ticket-2500-2

  • The problem is with the URL that gets generated :

    http://localhost:3000/agenda_items?company=43841&history=true
    

    The history parameter won't get sent correctly since the & character is replaced by a &.

    The funny thing is that when I try it with a link_to_remote instead of the remote_link or when I output the remote_function directly on the page (and not in a script tag), it works as expected and doesn't escape the & character with its HTML entity.

    I'm on Rails 2.1.1 and Firefox. Maybe it has been fixed in the latest version of Rails but switching is not an option right now.

  • I'm on Rails 2.3.2 and I don't have any problem when & is replaced by & amp;

    If you need to fix this in your situation, you could patch the remote_ function update and add a :escape_ url option and set that to false. Put the code below somewhere in your rails environment where it gets loaded.

    module ActionView
    class Base
     def remote_function(options)
      javascript_options = options_for_ajax(options)
    
      update = ''
      if options[:update] && options[:update].is_a?(Hash)
        update  = []
        update << "success:'#{options[:update][:success]}'" if options[:update][:success]
        update << "failure:'#{options[:update][:failure]}'" if options[:update][:failure]
        update  = '{' + update.join(',') + '}'
      elsif options[:update]
        update << "'#{options[:update]}'"
      end
    
      function = update.empty? ?
        "new Ajax.Request(" :
        "new Ajax.Updater(#{update}, "
    
      url_options = options[:url]
      url_options = url_options.merge(:escape => false) if url_options.is_a?(Hash)
      function << (options[:escape_url] == false ? "'#{url_for(url_options)}'" : "'#{escape_javascript(url_for(url_options))}'") ## Add this line to the rails core
      function << ", #{javascript_options})"
    
      function = "#{options[:before]}; #{function}" if options[:before]
      function = "#{function}; #{options[:after]}"  if options[:after]
      function = "if (#{options[:condition]}) { #{function}; }" if options[:condition]
      function = "if (confirm('#{escape_javascript(options[:confirm])}')) { #{function}; }" if options[:confirm]
    
      return function
    end 
    end
    

    end

  • Use the :with option (which must be a valid query string and is not escaped like the :url), like so

    url, query_string = agenda_items_url(options).split('?')
    javascript_tag( remote_function( :update => agenda_dom_id, :url => url, :with => query_string, :method => :get ) )
    

    I'm assuming agenda_items_url is your own helper function and it is outputting the full url without escaping it first.

  • Guys, it's just a default behavior of url_for in views... C'mon, pass :escape => false along with URL params and enjoy unescaped stuff :)

0 comments:

Post a Comment

Note: Only a member of this blog may post a comment.