javascript in a rails :url parameter - ruby-on-rails

I want to create a drop_receiving_element where the :url contains javascript. Currently I just created a helper function and hard-coded the element in like so:
def create_classification_droppable(droppable_id, classification)
"<script type='text/javascript'>
//<![CDATA[
Droppables.add('#{droppable_id}', {accept:'lead', onDrop:function(element){new Ajax.Request('/leads/' + (element.id.split('_').last()) + '.js', {asynchronous:true, evalScripts:true, method:'put', parameters:'lead[classification]=#{classification}&authenticity_token=' + encodeURIComponent('#{form_authenticity_token}')})}})
//]]>
</script>"
end
That's pretty hackish and ugly, though. Ideally I'd like to do something like:
drop_receiving_element('some_class',
:accept => 'some_other_class',
:url => formatted_whatever_path( SOMETHING_BASED_ON_WHATEVER_IS_BEING_DROPPED ) )
Or
formatted_whatever_path(:id => "some_javascript", :js)
Unfortunately, this doesn't seem possible because the url is escaped further down the call chain (in url_for, I believe). What are the alternatives?

What version of rails are you using? If you're on 2.3.8 then your "escaping" may simply be because of the "string addition bug":
https://rails.lighthouseapp.com/projects/8994/tickets/4695-string-added-to-rails_helpers-gets-html-escaped
You can fix it either by finding ingenious hacks around it (eg encasing your string in "#{my_string}" to re-evalute it) or by downgrading to 2.3.5.

Related

How to upgrade the :update=>'div_id' option of remote_form_for from Rails 2 to Rails 3?

I can't figure out how to upgrade this code from Rails 2 to Rails 3:
<% remote_form_for(item, :update => 'div_id') do |f| %>
...
I tried this:
<%= form_for :item, :remote => true, :url => { :controller => "items", :action => "create" }, :update => 'div_id' do |f| %>
...
It creates the new item but it fails in updating the content within <div id="div_id"></div> tags. It seems Rails 3 no longer supports the ":update" option for a remote form_for. Any suggestion?
You could use RJS, but that's being deprecated too (and for good reason). The simplified, best-practices way to handle this in Rails 3+ is as follows (assuming jQuery):
# your_view.html.erb
<div id="receiver-id"></div>
<%= form_for :some_model, :remote => true, :id => 'form-id' do |f| %>
...
<% end %>
# application.js (or any other .js loaded on the page)
$(function(){
$('#form-id').bind('ajax:success', function(xhr, data, status){
$('#receiver-id').html(data);
});
});
The ajax:success hook gets called by the jquery-ujs (aka jquery-rails, aka rails-ujs) remote link/form handler. See for yourself. There are lots of other callbacks/hooks available for you to use, too. If you wanted to make this even more flexible, you could use live instead of bind, and bind to a class that dictates where the ouput goes (e.g. "sidebar") and then all remote links/forms with the sidebar class would have their HTML response go to div#sidebar.
The most straightforward way to do this would be to write a javascript view template, e.g. create.js.erb which would look something like this:
$('#div_id').html("<%= escape_javascript(render(#item)) %>");
(depending on your setup, of course, I'm assuming an #item variable and an associated _item partial)
Edit:
coreyward is right. This is the RJS way which is more of the old fashioned Rails 2.x "Rails way". It's probably more familiar, but has issues. Your specific case is one of them, actually, as typically you might bind to an HTML element to update using the record's id (e.g. div #item_1), and in the create case there is no id available beforehand, complicating matters.
Binding via clientside JS eliminates this issue. RJS works in something of a vacuum, making assumptions about the state of the client's HTML and having no access to it.
I know the question is old but I when migrating to Rails 3 I found a pretty good way of doing this, so I thought I would post it here in case anyone else is in a similar solution.
In layouts/update_page.js.erb I put this file:
$j('#<%=#update_div_id||"list_div"%>').html('<%= escape_javascript render(:partial => (#partial_div||"index"), :locals => #local_hash) %>');
This is mainly used for searches that use remote, so in the index action in the controller, I just added the following code.
respond_to do |format|
format.html
format.js {render 'layouts/update_page'}
end
Since remote is being used, it will always try to use javascript first, so it will render the update_page.js.erb file from above. For us, we almost always use the div#list_div on our index pages, so we update that by the default, however if you need to update something different, you can pass in #update_div_id, and if you need to render a different page, you can pass in #partial_div.
To clarify, for a lot of things, it is probably better practice to use the callbacks, but I found this to be a much easier way, when we had to migrate over nearly 100 of these calls.

Rails: Forcing form tag to use an HTTPS action

Trying to use the form_tag helper in rails to submit to an SSL address. Currently, my code looks like this:
form_tag(form_action_path) do
# This spits out:
<form action="form_action_path" method="post">
If I try this:
form_tag(form_action_path, :protocol => 'https', :only_path => false)
# It spits out:
<form action="form_action_path" method="post" protocol="https" only_path="false>
That is of course, not a valid or worthwhile result. How can I make the form tag helper render out an https action path?
Thanks.
It turns out that I was using the wrong syntax.
Instead of
form_tag(form_action_path, :protocol => 'https')
I needed
form_tag(form_action_url(:protocol => 'https'))
The difference being, apparently, that form_action_path generates something like "/path/to/action" and form_action_url generates "http://url.com/path/to/action."
You can use something like SSL_Requirement with your create/update actions. It seems SSL_Requirement is older (not that it needs to be updated, it's not terribly complicated), but there may be a newer gem/plugin that people prefer now.

Ruby on Rails3: How do I invoke javascript before an ajax event is fired with remote => true?

<%= link_to( {:controller => 'board',
:action => 'take_turn',
:id => #board.id,
:x => col,
:y => row} , :remote => true, :onClick => "return links_disabled;") do %>
<div class="ttt_square">
</div>
<% end %>
in rails2, there were :before, and :complete params, but I have not found any documentation for this in rails3
As I understand it, this is one of the consequences of Rails 3 using UJS (unobstrusive javascript). Rails 3 enables you to keep the javascript away from e.g. a link-tag. Instead of the link-tag specifying what should be done via javascript, you make the javascript observe the link-tag.
You achieve this by binding a function to a certain event of an object, eg. binding the ajax:before event of the link-tag to a function.
In this blog post the author explains how to do it, in his case with JQuery.
As far as I understand, in Rails 3 you bind the callback events to the element on the client side, and they are fired by rails.js at the appropriate times.
$('#myform').bind('ajax:success', function(){
alert('I succeeded');
})
If I remember well, there is no more support in Rails3.
You could use native jQuery function:
ajaxStart()
http://api.jquery.com/ajaxStart/
See details here: http://www.simonecarletti.com/blog/2010/06/unobtrusive-javascript-in-rails-3/
My version (jquery-rails 0.2.6) supports ajax:before, loading, success, complete, failure, and after. The parameters to the success/failure functions are not the same which has tripped me up in the past. But the following works for me:
$('a').bind('ajax:loading', function() {
alert('here');
});
If your link element was created after the initial page load, you might need to bind using 'live':
$('a').live('ajax:loading', function() { alert('...'); });
I would also double-check that your onclick handler is not interfering.

:remote => true with url_for, How does one do this?

I am trying to make an entire div tag clickable. The code I am trying to use is below, and when I add the
:remote => true
bit it throws Too many args error, 2 for 1.
Code:
<div id="foo" onclick="window.location = '<%= url_for foo_controller_path(:someparam => #left), :remote => true %>'"></div>
url_for doesn't accept the :remote => true argument, it's usually the link_to method that you would send it to.
Is there a reason you can't make your <div> a link instead? For all intents and purposes it is functioning as a link, so you should mark it up as such, we call that semantic mark-up.
If you really wanted to do this it would probably be best to use jquery (or prototype, if that's your cup of tea) to perform the action unobtrusively... it makes it easier to do the ajax request too. Are you trying to update something on your page after the link is clicked, or just do nothing?
Also the 'window.location' is telling the javascript on the page to redirect. You wouldn't use that if you wanted to make the request remotely.
Using jquery you could do it like this if you want to stick with a div
%(function(){
$('#foo').click(function(){
$.get(
url: $(this).data('request-path'),
success: function(data){
alert('success sir! controller responded with ' + data);
}
);
});
});
And use this in your view:
<div id='foo' data-request-path='<%= url_for foo_controller_path(:someparam => #left) %>'></div>
But if you changed it to a link tag you could do this instead...
= link_to("", url_for(foo_controller_path(:someparam => #left)), :remote => true, :id => 'foo')
And it ought to just work. Then you can style this link the way that you were trying to style your div tag.
This is more semantic and less code for you to worry about. If you need to update something in the dom afterwards you can add this jquery (if you're using jquery, and rails3):
$('#foo').bind('ajax:success', function(data){
alert('successful request! data was: ' + data);
});
I didn't necessarily test all of this but it should be a good starting point... I'm not a big fan of putting onclick handlers into tags. It tends to work nicer when you bind events using jquery.
If you want to be able to do what i've described but you're in rails 2, you can get the rails3 jquery script from here: https://github.com/rails/jquery-ujs
Note that you'll also need that script if you're using rails 3 and want jquery instead of prototype (like me!). Rails 3.1 will come bundled with jquery instead of prototype I hear, by default.
And change the :remote => true in that url_for to "data-remote" => true (for rails 2, with rails 3 you can use the symbol syntax and it makes the 'data-remote' attribute for you.
Let me know if something didn't quite work or you need clarification. Or even if you hate my ideas alltogether :p

Rails keeps changing my string "?" into "%3F"

Basicaly I just want to insert this + "?direction=desc" in helper method.
But once it parses it comes out like this..
/organizations/search?order_by=contactable%3Fdirection%3Ddesc
Anyone know a way around this?
My Helper Method:
def search_sort(name, sort_by, order = 'asc')
link_to(name, url_for(:overwrite_params => { :order_by => sort_by + "?direction=desc" :page => nil }), :class => 'selected save_pushstate')
...
I know what you're thinking. Just add :order into it. The problem being is that I 'm using an AJAX history saver from #175 of railscasts.
$(".save_pushstate").live("click", function() {
$.setFragment({"order_by" : $.queryString($(this).attr('href')).order_by});
//$.setFragment({"direction" : $.queryString($(this).attr('href')).direction});
return false;
});
And it rewrites my url to just one "fragment". I can't have two! So I decided that if I can just add the direction param in the href hard-coded, it could deal with this whole mess.
Try:
+ "?direction=desc".html_safe
Edit:
Since you're using rails 2.3.5, try this:
def search_sort(name, sort_by, order = 'asc')
link_to(name, url_for(:overwrite_params => { :order_by => sort_by + "?direction=desc" :page => nil }, :escape => false), :class => 'selected save_pushstate')
...
Note the ":escape => false" in url_for.
Edit2:
After reading this:
http://www.ruby-forum.com/topic/80381
Specifically this excerpt:
I think this is where the confusion is
arising. There are two different kinds
of escaping going on.
It sounds like you're talking about
the URL encoding that uses '%xx' to
represent special characters.
However, the html_escape function does
something completely different. It
takes a string and turns '&' into
'&' and '<' into '<', etc., so
that it can go into HTML without being
interpreted as literal '&'s and '<'s.
Escaping special characters in URLs
using the '%xx' scheme is mandatory,
otherwise they are not valid URLs.
I've realized that the 'escaping' that you see happening is url encoding, and it shouldn't affect your query/sorting, etc. You can test it out by taking the encoded url and typing it into your browser.
:escape => false disable html escaping, which means dangerous characters get converted to display codes, such as '&' into '&' and '<' into '<', etc.,
And the "?" in your append should be "&":
+ "&direction=desc"
Hope this helps. =)

Resources