Ajax can't work in Rails 3.1 - ruby-on-rails

Base on 'Agile Web Development with Rails, Third Edition', I created a cart with Ajax, but Ajax isn't working for me. My code is as follows:
/store/index.html.erb:
<%= form_tag({:action=>'add_to_cart', :id=>product}, :remote=>true ) do %>
<%= submit_tag "Add to Cart" %>
<% end %>
/layouts/store.html.erb:
<head>
...
<%= javascript_include_tag :defults %>
...
</head>
/controllers/store_controller.rb:
def add_to_cart
...
respond_to do |format|
format.js
end
...
end
add_to_cart.js.rjs
page.replace_html("cart",:partial => "cart", :object=>#cart)
Rails 3.1, Ruby 1.9.3.

js templates are named as name.js.erb in Rails 3.
Let me assume you are going to replace "cart" div in ajax call and you have jQuery.
create add_to_cart.js.erb with the following code.
$("#cart").replaceWith('<%=escape_javascript(render :partial => 'cart', :object=>#cart) %>');

RJS isn't a part of Rails any more. You can use jQuery instead without any additional download required: just don't use the .rjs at the end. If you know CoffeeScript, it's also available here: name your file *.coffee and you are done. Also you can name it *.coffee.erb to allow the ERb to preprocess you file but this feature is allowed by default even for simple *.coffee-files.
UPD:
page.replace_html("cart",:partial => "cart", :object=>#cart)
Should become:
$("#cart").html("<%= j render(#cart) %>")

Related

Ajax call in rails 3.2.3 with will_paginate gem

Im trying to implement an Ajax call with the will_paginate gem, I found this guide http://ramblinglabs.com/blog/2011/11/rails-3-1-will_paginate-and-ajax which seemed like a simple solution, though it includes coffeescript which i am not familiar with, so if anyone has a different solution then please advise..
My code is as follows
My View
<div class="container">
<div class="row">
<div id="userRecipes">
<%= render partial: 'userrecipes' %>
</div>
</div><!--/row-->
My partial (userrecipes)
<% #recipes.each do |r| %>
<div class="span3">
<div class="thumbnail">
<%= image_tag r.avatar.url(:myrecipes) %>
</div>
<h4><%= link_to r.dish_name, r %></h4>
<hr>
<p><%= truncate r.description, :length => 90 %></p>
<p><%= link_to "Edit Recipe", edit_recipe_path(r.id) %></p>
<p><%= link_to "Delete Recipe", recipe_path(r.id), :confirm => "Are you sure?", :method => :delete %></p>
<p><%= link_to "Add to favorites", {:controller => 'favourites', :action => 'create', :recipe_id => r.id}, {:method => :post } %></p>
</div><!--/span3-->
<% end %>
<%= will_paginate #recipes %>
updated userrecipes.js.erb file
$('#userRecipes').html('<%= escape_javascript(render partial: 'userrecipes') %>');
$.setAjaxPagination();
Coffeescript
$ ->
$.setAjaxPagination = ->
$('.pagination a').click (event) ->
event.preventDefault()
loading = $ '<div id="loading" style="display: none;"><span><img src="/assets/loading.gif" alt="cargando..."/></span></div>'
$('.other_images').prepend loading
loading.fadeIn()
$.ajax type: 'GET', url: $(#).attr('href'), dataType: 'script', success: (-> loading.fadeOut -> loading.remove())
false
$.setAjaxPagination()
When i click on the next anchor tag to show the next set of results the page stays as it is and no new content appears
When using the console to see if there are any errors i can see any, the output is
GET http://localhost:3000/my_recipes?page=2&_=1355055997639
Am i missing something here? or is there an issue with my userrecipes.js.erb file because in other Ajax examples i have seen thy are using escape_javascript when rendering the partial?
Edit
Whilst inspecting the response in the console it is also showing that the new recipes to be loaded are being loaded but nothing is happening in the view
Any pointers appreciated
Thanks
Why not try a simpler approach, create a new helper (ex. app/helpers/will_paginate_helper.rb) with the following content:
module WillPaginateHelper
class WillPaginateJSLinkRenderer < WillPaginate::ActionView::LinkRenderer
def prepare(collection, options, template)
options[:params] ||= {}
options[:params]['_'] = nil
super(collection, options, template)
end
protected
def link(text, target, attributes = {})
if target.is_a? Fixnum
attributes[:rel] = rel_value(target)
target = url(target)
end
#template.link_to(target, attributes.merge(remote: true)) do
text.to_s.html_safe
end
end
end
def js_will_paginate(collection, options = {})
will_paginate(collection, options.merge(:renderer => WillPaginateHelper::WillPaginateJSLinkRenderer))
end
end
Then in your view use this tag for ajax pagination:
<%= js_will_paginate #recipes %>
Remember that the pagination links will include existing params of the url, you can exclude these as shown below. This is standard will paginate functionality:
<%= js_will_paginate #recipes, :params => { :my_excluded_param => nil } %>
Hope that solves your problem.
Explanation:
Will_paginate allows you to create your own custom renderer. The WillPaginateJSLinkRenderer is such a custom renderer and this class could be defined anywhere, it doesn't have to be defined inside the helper module. The custom renderer extends the standard renderer (LinkRenderer) and redefines only two methods.
The prepare method is overriden to explicitly remove the cache buster parameter since will_paginate creates the page urls with all parameters that were present when rendering the page and we do not want to reuse the cache buster parameter.
The link method is a copy paste from the original LinkRenderer source code but creates a link with remote: true to make it a JS resquest.
Finally the js_will_paginate method is a standard view helper method to call the normal will_paginate view helper method but adds our custom renderer to the options so that it will be used instead of the normal renderer.
Just in case someone is looking for Rails 4 solution. I liked the answer from Pierre Pretorius, but it failed for me on 4.1.1 with "method undefined" for link_to_function on the line:
#template.link_to_function(text.to_s.html_safe, ajax_call, attributes)
I just replaced the line to:
#template.link_to(text.to_s.html_safe, '#', attributes.merge(:onclick => "#{ajax_call} event.preventDefault();"))
I hope it may help someone.
You are not escaping javascripts in your js.erb, it should be the problem.
$('#userRecipes').html('<%= escape_javascript(render partial: 'userrecipes') %>');
$.setAjaxPagination();
The ajax_will_paginate is a superb method, but unfortunately it was messing up the UI of the paginate. I had employed another javascript method for more flexibility. And I call this method on pageRender.
function checkForAjaxPaginate(controller,make_ajax){
var href = "";
$(".pagination").find("ul").each(function(){
$(this).find("li").each(function(){
$(this).find("a").each(function(){
href = $(this).attr("href");
if(href.indexOf(controller+".js") != -1){
if(make_ajax){
$(this).attr("data-remote","true");
}
else{
$(this).attr("href",href.replace(".js",""));
}
}
});
});
});
}
For more flexibility, you just pass the action name in the "controller" variable and pass true to make_ajax if you want to convert it to ajax. All I am doing is to check if the href link is ".js", and if make_ajax is true, then adding an attr "data-remote=true", which in our ROR app makes it ajax. if make_ajax is not true then am just removing the ".js" so the code does not mess.
I hope this helps
Pierre Pretorius' answer is great, but I had to do a little more to make it work for me that wasn't already clear. Maybe this will be helpful to other beginners.
In addition to making that helper and using the js_will_paginate tag I did this:
After moving the content I was trying to paginate into a partial (_recipes.html.erb in the case above), I also created a show.js.erb file (in this same view alongside the partial) with text similar to this:
$('#recipes').html('<%= escape_javascript(render partial: 'recipes') %>');
Then I had to move the js_will_paginate tag to the partial as well at the bottom (so it would be updated as I paginated through or clicked next/previous). Then I had to wrap the render partial helper in the div id you're targeting in the js file, so in this example:
<div id="recipes">
<%= render partial: "recipes" %>
</div>
This may have been very clear to others, but I wasn't sure which steps from the OP had to remain and which were unnecessary. These steps worked for me. You don't need to add respond_to js in the controller as the helper takes care of that or have a coffeescript file.

How to add action specific asset pipeline items?

I am writing a Rails 3.2.1 application and I have some javascript code I'd like to put in for a single action view. It simply calls a jquery plugin and starts a countdown, but I'd like to write it in coffee script and I feel like the asset pipeline is the correct tool to do this.
Also I need access to the variables passed by the controller such as #question. How would I do this? I have looked into the coffeebeans gem but that only works for :remote=>true forms and links.
Your problem can be solved in different ways.
Add the assets dynamically
Add to our application helper the following method:
module ApplicationHelper
def include_related_asset(asset)
# v-----{Change this}
if !YourApp::Application.assets.find_asset(asset).nil?
case asset.split('.')[-1]
when 'js'
javascript_include_tag asset
when 'css'
stylesheet_link_tag asset
end
end
end
end
Call the helper method in your layout-file:
<%= include_related_asset(params[:controller].to_param + '_' + params[:action].to_param . 'js') %>
Create specific assets for your controller actions. E. g. controller_action.js
Use yield
Add <%= yield :head%> to your layout head
Include your assets from your action views:
<% content_for :head do %>
<%= javascript_include_tag 'controller_action' %>
<% end %>
Please see the Rails guides for further information.
To passing controller data to your javascript, you could do:
<%= javascript_tag do %>
window.error_message = '<%= j error_message %>';
<% end %>
Please see the RailCast Episode #324 for further information.

Ajax on html block in Ruby on Rails 3

I would like to use Ajax in my Ruby on Rails 3 application. Problem is I want the Ajax link to surround a div tag. If possible I'd rather it be with jQuery rather than prototype. How would I accomplish this?
I would like a solution involving some rails type programing something like link_to.
First of all add 'jquery-rails' gem to your Gemfile:
gem 'jquery-rails'
Then run bundle install and rails g jquery:install. That's all. Now you can work with jQuery.
Add a div into your view, for example:
<div id='ajax_div'><%= #article.title %></div>
Now you can include some javascript this way:
$(
function(){
$("#ajax_div").click(function(){
$.ajax(...)
}
}
)
More about $.ajax: http://api.jquery.com/jQuery.ajax/ (you can use either $.post or $.get or $.getScript)
UPD
working with ajax through link_to
<%= link_to some_path, :remote => true do %>
<div id='ajax_div'><%= #article.title %></div>
<% end %>
FROM THE BEGINNING
Let's create new rails application. From scratch. To show how ajax works. I won't test it, so here can be misstypes and mistakes.
rails new ajaxapp
cd ajaxapp
rails g scaffold Comment body:text
rake db:create
rake db:migrate
add gem 'jquery-rails' to Gemfile => bundle install => rails g jquery:install
let's edit comments/index.html.erb:
<h1>Listing comments</h1>
<%= link_to comments_path, :remote => true, :method => :post do %>
<div>Click me to add random comment</div>
<% end -%>
<div id='comments'>
<%= render #comments %>
</div>
_comment partial:
<p>
<%= comment.body %>
</p>
Now we will add app/views/create.js.erb file:
$("#comments").append("<%= escape_javascript( render #comment ) %>")
comments_controller create action:
def create
#comment = Comment.new
#comment.body = (0...50).map{ ('a'..'z').to_a.<<(" ")[rand(27)] }.join
#comment.save
end
that's all. Now run rails s. Go to localhost:3000/comments.

Problem with block helpers and JavaScript templates after Rails 3 upgrade

I have an application I'm upgrading from Rails 2.3 to Rails 3 that uses a combination of helpers and JavaScript templates that is not working after the upgrade. I have the following code in a view partial:
<%= content_for :jstemplates do -%>
<%= "var serviceoverride='#{generate_template(customer_form, :serviceoverrides).html_safe}'" %>
<%= "var clientimage='#{generate_template(customer_form, :customer_images).html_safe}'" %>
<%= "var formula='#{generate_template(customer_form, :formulas).html_safe}'" %>
<% end -%>
That calls a generate_template helper:
def generate_template(form_builder, method, options = {})
escape_javascript generate_html(form_builder, method, options)
end
def generate_html(form_builder, method, options = {})
options[:object] ||= form_builder.object.class.reflect_on_association(method).klass.new
options[:partial] ||= method.to_s.singularize
options[:form_builder_local] ||= :f
form_builder.fields_for(method, options[:object], :child_index => 'NEW_RECORD') do |f|
render(:partial => options[:partial], :locals => { options[:form_builder_local] => f })
end
end
And the view partial is rendered from one of the standard controller views. The problem is that the JavaScript output on the rendered page is always HTML escaped and thus is directly rendered on the page. This worked correctly in Rails 2.3.x and obviously broke in Rails 3, I suspect with the change in behavior of <% %> block style helpers.
My problem is that I cannot get the jstemplates to render unescaped. I've looked into the changes in block style helpers and tried ensuring that all content generating blocks are using <%= %>, using the <%=raw %> function, adding .html_safe to strings and so on. It seems like I'm missing something basic.
Any help would be appreciated.
Chris
I found the answer. I apparently had the raw blocks in the wrong place. This change fixed it:
<%= content_for :jstemplates do -%>
<%=raw "var serviceoverride='#{generate_template(customer_form, :serviceoverrides).html_safe}'" %>
<%=raw "var clientimage='#{generate_template(customer_form, :customer_images).html_safe}'" %>
<%=raw "var formula='#{generate_template(customer_form, :formulas).html_safe}'" %>
<% end -%>

Rails AJAX UJS Question

rails 3.0
<% link_to about_path, :remote => true do %>
About Us<span>Who we are</span>
<% end %>
def about
render :update do |page|
page[:content].replace_html :partial => 'dashboard/about'
end
end
Having issues with AJAX in rails 3.0 Just trying to get it replace the html with a partial one clicked. Any help is greatly appreciated. I am trying to use the new :remote=>true that was implemented in rails 3.0.
Thanks
UPDATE:
Below is the markup I get. Also when I click it, I go to a new screen with a bunch of text and white background. Thanks again.
<a href="/about" data-remote="true"> About Us<span>Who we are</span>
</a>
Even when trying a basic example of ajax.
Hello there
<%= link_to 'something, something_path, :remote=true %>
controller:
def something
render :update do |page|
page[test].visual_effect :blind_up
end
Great Post on an example of using Rails3 + CRUD + UJS.
http://www.stjhimy.com/posts/7

Resources