Rails 3 rendering partial with javascript from remote: true call - ruby-on-rails-3

I have a remote: true call in my Rails 3 app controller HotelsController, which executes show_map action. Pretty simple.
<%= link_to "Map", show_hotel_map_path(#hotel.id), remote: true %>
<div id="hotel_map"></div>
show_hotel_map action is pretty basic
def show_hotel_map
#hotel = Hotel.find(params[:id])
respond_to do |format|
format.html
format.js
end
end
show_hotel_map.js.erb is meant to render a partial map within JQuery-UI dialog with rendered Google Maps map
$("#hotel_map").dialog({
autoOpen: true,
height: 'auto',
width: 'auto',
modal: true,
closeOnEscape: true,
position: 'center',
resizable: false,
title: "Map",
open: function(){
$("#hotel_map").html("<%= escape_javascript(render partial: "map") %>")
}
});
_map.html.erb partial does nothing but executes render_map helper
<%= render_map %>
render_map helper does all the stuff with rendering a map with Gmaps4Rails gem
module HotelsHelper
def render_map
if #hotel.address.latitude && #hotel.address.longitude
map = #hotel.address.to_gmaps4rails
else
geo = Gmaps4rails.geocode("#{#hotel.continent.name}, #{#hotel.country.name}, #{#hotel.location.name}")[0]
map = [{lat: geo[:lat], lng: geo[:lng]}].to_json
end
gmaps(:markers => { :data => map, :options => { :draggable => true } })
end
end
The problem is that Gmaps4Rails gem renders some javascript for proper Google Maps handling, but apparently this javascript is being truncated by escape_javascript call from show_map.js.erb view. So when I click "Map" link, JQuery-UI dialog is being rendered, but it does not have any payload, since no Javascript was executed. render_map helper works perfectly by itself, so I guess that's not a problem with Gmaps4Rails gem. Is there any workarounds so I can execute that javascript? I can think of few hacks, but maybe there is more Rail-ish way to do it?
Thank you!

Okay, to whom it may concern, I solved it using UJS technique described in Gmaps4Rails wiki
https://github.com/apneadiving/Google-Maps-for-Rails/wiki/Using-with-UJS
It is not very DRY but I guess there's not many other options.

Related

rails observe_form and prototype: return '$A($(form).getElementsByTagName('*'))'

I have observe_form in my view:
<%= observe_form 'new_lead', :url => { :action => 'update_price' }, :frequency => 0.1 %>
, _update_price.rjs partial and this method in controller:
def update_price
unless request.xhr?
redirect_to :controller => 'index'
else
set_price_group
render :partial => "update_price",
:locals => { :services => params[:service],
:spectr => params[:spectr] }
end
end
I'm upgrading rails_2 app to rails_3.
On rails_2 it's no errors, but when I upgrade project to rails3
I have javascript error in 3484 line of prototype.js:
"$(...).getElementsByTagName is not a function ".
getElements: function(form) {
return $A($(form).getElementsByTagName('*')).inject([],
function(elements, child) {
if (Form.Element.Serializers[child.tagName.toLowerCase()])
elements.push(Element.extend(child));
return elements;
}
);},
And 'update_price' does not calling periodically.
I don't know is it problem related to rails upgrading or just problem with JS :(
How can I fix this problem?
Rails 3.1 uses jQuery instead of Prototypejs. You can get back the prototype functionality by using something like https://github.com/rails/prototype-rails
Related How to swap jquery for prototype in Rails 3.1
Than if somebody have an error:
TypeError: document.on is not a function
Changing prototype.js 1.6.x to 1.7 will solve it ;)

Rails 3 Uploadify + Paperclip File Data Is Never Sent

I'm using Rails 3.1 with Paperclip and trying to implement Uploadify for multiple file uploads on a single page. I tried following various samples, including: Rails3-Paperclip-Uploadify
Currently I have a Upload model which has a one to many relationship with my UploadImage model - This is what I had setup so far for my view:
UploadImages/new.html.erb
<%= javascript_include_tag "http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js" %>
<%= javascript_include_tag "swfobject.js", "jquery.uploadify.v2.1.0.js" %>
<script type="text/javascript" charset="utf-8">
<%- session_key = Rails.application.config.session_options[:key] -%>
$(document).ready(function()
{
// Create an empty object to store our custom script data
var uploadify_script_data = {};
// Fetch the CSRF meta tag data
var csrf_token = $('meta[name=csrf-token]').attr('content');
var csrf_param = $('meta[name=csrf-param]').attr('content');
// Now associate the data in the config, encoding the data safely
uploadify_script_data[csrf_token] = encodeURI(encodeURI(csrf_param));
$('.uploadify').uploadify
({
uploader : '/uploadify/uploadify.swf',
cancelImg : '/uploadify/cancel.png',
multi : true,
auto : false,
onComplete : function(event, queueID, fileObj, response, data)
{
var dat = eval('(' + response + ')');
$.getScript(dat.upload);
},
scriptData : {
'_http_accept': 'application/javascript',
'format' : 'json',
'_method': 'post',
'<%= session_key %>' : encodeURIComponent('<%= u cookies[session_key] %>'),
'authenticity_token': encodeURIComponent('<%= u form_authenticity_token %>'),
'upload_id' : '<%= #upload.id %>'
}
});
});
</script>
<%= form_for #upload.upload_images.build, :html => { :class => "upload", :multipart => true } do |f| %>
<%= f.file_field :image, :class => "uploadify" %>
<%= submit_tag "Submit Upload", :disable_with => "Uploading", :class => "submit"%>
<% end %>
I see the uploadify flash button, I select a few files and submit but this is all I see in my params:
{"utf8"=>"✓",
"authenticity_token"=>"K1bSH/FO0Hjdum0aiNU45mHJXezXTiCgh9XVmk1jrZM=",
"commit"=>"Submit Upload", "action"=>"create",
"controller"=>"upload_images"}
As you can see there is no file data being sent and even the scriptData that I specify doesn't get sent, I noticed that other people's code uses the script parameter for the uploadify function. In PHP frameworks they point it to the .php file which handles the saving. I'm using Paperclip so I wasn't sure how to implement this... perhaps this is my problem? Let me know if you need any additional details.
I found the answer by looking at this question: uploadify rails 3 nothing happens after the file is chosen
I had to attach some events to my submit button and add the script parameter to the uploadify function as I surmised.
So for starters in my config/routes.rb I needed to add:
post "upload_images/create"
And in my view I added:
$('#submit').click(function(event){
event.preventDefault();
});
$('#submit').click(function(event){
event.preventDefault();
$('.uploadify').uploadifyUpload();
});
and finally I added the script param to my initial uploadify function call:
script : '/upload_images/create'
After many hours of beating my head against it's finally working and making sense! Hope this helps somebody else.

Using jquery tokeninput and acts_as_taggable_on

I've implemented the framework outlined in this post: How to use jquery-Tokeninput and Acts-as-taggable-on with some difficulty. This is working insofar as prepopulating with the appropriate theme and ajax search, but when I enter a new tag, it is immediately deleted when the text area loses focus. I'm not sure what I'm doing wrong. Here's some of my relevant code:
User Model (does the tagging):
class User < ActiveRecord::Base
[...]
# tagging
acts_as_tagger
Item Model (accepts a tag):
class Item < ActiveRecord::Base
attr_accessible :title, :tag_list
#tagging functionality
acts_as_taggable_on :tags
Item Controller:
def tags
#tags = ActsAsTaggableOn::Tag.where("tags.name LIKE ?", "%#{params[:q]}%")
respond_to do |format|
format.json { render :json => #tags.collect{|t| {:id => t.name, :name => t.name }}}
end
end
On my form partial:
<%= f.input :tag_list, :label => "Tags", :input_html => { :class => "text_field short", "data-pre" => #item.tags.map(&:attributes).to_json }, :hint => "separate tags by a space" %>
my routes:
get "items/tags" => "items#tags", :as => :tags
resources :items
[almost there!!!]
the js on the form [note: the id of the element is assigned dynamically]:
<script type="text/javascript">
$(function() {
$("#item_tag_list").tokenInput("/art_items/tags", {
prePopulate: $("#item_tag_list").data("pre"),
preventDuplicates: true,
crossDomain: false,
theme: "facebook"
});
});
</script>
If you still want to use Jquery TokenInput and add tags there are different ways to do it.
1.
This is actually from my same question; the newest answer: How to use jquery-Tokeninput and Acts-as-taggable-on
This could go in your controller.
def tags
query = params[:q]
if query[-1,1] == " "
query = query.gsub(" ", "")
Tag.find_or_create_by_name(query)
end
#Do the search in memory for better performance
#tags = ActsAsTaggableOn::Tag.all
#tags = #tags.select { |v| v.name =~ /#{query}/i }
respond_to do |format|
format.json{ render :json => #tags.map(&:attributes) }
end
end
This will create the tag, whenever the space bar is hit.
You could then add this search setting in the jquery script:
noResultsText: 'No result, hit space to create a new tag',
It's a little dirty but it works for me.
2.
Check out this guy's method: https://github.com/vdepizzol/jquery-tokeninput
He made a custom entry ability:
$(function() {
$("#book_author_tokens").tokenInput("/authors.json", {
crossDomain: false,
prePopulate: $("#book_author_tokens").data("pre"),
theme: "facebook",
allowCustomEntry: true
});
});
3.
Not to sure about this one but it may help: Rails : Using jquery tokeninput (railscast #258) to create new entries
4.
This one seems legit as well: https://github.com/loopj/jquery-tokeninput/pull/219
I personally like the first one, seems easiest to get and install.

jquery-ujs ajax events are not handled

I'm trying to implement ajaxy signup with rails 3. I'm using jquery-ujs and remote form. I access the signup form with $.get request, and it is displayed correctly. This signup form is remote:
form_for #user, :remote => true, :html => {"data-type" => "html"} do |f|
In my application.js, if the ajax request for getting the form is successful, I'm trying to bind handler for ajax events from unobtrusive javascript:
var load_remote_form = function(evt) {
var href = $(this).attr('href');
// load form template
$.get(href, {}, function(data) {
$('body').append(data);
$('form[data-remote]').bind("ajax:beforeSend", function(e) {
console.log("Caught beforeSend!");
});
});
evt.preventDefault();
};
$(document).ready(function() {
$('a#signup').click(load_remote_form);
});
Chrome's development tools show that the event "ajax:beforeSend" is binded, but it is never handled (I have nothing in the javascript console when I send the form, though in rails log I see that the request is processed correctly and the response is send). I can bind other events to the same selector (form[data-remote]), like click, and they are handled correctly.
Ajax events binded through .live are not handled as well. But if the form is rendered as part of the layout (i.e. it is on stand-alone page like http://localhost:3000/signup/), binded "ajax:beforeSend" is handled correctly.
My controller (just for a case, it may be badly written, but I'm pretty sure it works):
class UsersController < ApplicationController
layout :layout_for_type
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
session[:user_id] = #user.id
flash[:notice] = "You have successfully registered."
redirect_to root_url
else
if request.xhr?
render :action => 'new', :status => :unprocessable_entry, :layout => false
else
render :action => 'new'
end
end
end
def layout_for_type
request.xhr? ? nil : "application"
end
end
What am I doing wrong? May be there is a better approach for implementing such "double-ajaxed" forms?
Silly me. I've completely overlooked another potential source of problems. I had
javascript_include_tag :all
in my application layout, and that caused including both jquery.js and jquery.min.js into my page. It turned out to be the cause of that strange behavior. Removing jquery.min.js did the trick. Hope that might be useful for someone someday.

What's the alternative of :before & :after of rails 2.3.* in Rails 3?

I am using remote form in Rails 3. It works fine but I want to show / hide spinner during ajax request.
In rails 2.3.* we use :before & :after in remote form to show/hide spinner
What should I do in Rails 3, as remote form of Rails 3 doesn't contain such options.
Here is a working solution I tried:
In my view file, I use :onSubmit to show a spinner:
<% form_for("", #search,
:url => {:action => "search"},
:html => {:id => "search_form",
:onSubmit => "$('search-loader').show();"},
:remote => true) do |f| %>
In my search action, I added one line to hide it:
render :update do |page|
...
page << "$('search-loader').hide();"
end
It works great..!
Well, I'm using jQuery, and I'm doing the following, trying to be unobtrusive:
Add this, right before your </head> tag:
= yield :document_ready
Then in your application_helper.rb:
def document_ready(content)
html = %{ $(function(){#{content}})}
content_for(:document_ready){ javascript_tag(html) }
end
This allows you to load and run javascript once your document is loaded.
On top of the view containing your form add:
- document_ready("hide_button_show_spinner('your_button_id')")
In application.js
function hide_button_show_spinner(element_id) {
$('#'+element_id).bind('click', function() {
$('#'+element_id).after("<img src='/path/to/your/spinner.gif' class='ajax_loader' id='"+element_id+"_ajax_loader' style='display: none'/>")
$('#'+element_id).hide();
$('#'+element_id+'_ajax_loader').show();
});
}
This will hide the button and show the spinner once the button is clicked. You may need to adapt this to your specific case.
You can then show the button and hide the spinner in your javascript response (the .js.erb file that you render from the action called by the ajax request).