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.
Related
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.
I have a trouble with kaminari pagination and bootstrap styles.
Pagination works fine, but styles are broken.
Is there any way to fix it? or is there any other style sheets for kaminari pagination?
here is a screenshot http://imageshack.us/photo/my-images/59/kaminari.png/
Browser Google Chrome
= paginate #activities, :theme => 'twitter-bootstrap'
You can also run
rails g kaminari:views bootstrap
This might be due to missing i18n translations -- they create extra tags which messes up bootstrap pagination.
checkout https://github.com/gabetax/twitter-bootstrap-kaminari-views
I've had the same problem and after some experimentation I ended up with this in my gem file;
gem "kaminari", "~> 0.13.0"
gem "kaminari-bootstrap", "~> 0.1.2"
The page links are working the way I think they are supposed to, although I dont like the way they look.
I get an error message if I use Kaminari 0.14.0, so back it off to 0.13.0.
Also...
I noticed it messes things up if I generate Kaminari views. It is the most stable to use the views that come with the gem, if you can live with them.
If you're using Bootstrap 3 you'll need to do the following. In the console:
rails g kaminari:views bootstrap
Then, replace the contents of app/views/kaminari/_pagination.html.erb with the following:
<%= paginator.render do %>
<ul class="pagination">
<%= first_page_tag unless current_page.first? %>
<%= prev_page_tag unless current_page.first? %>
<% each_page do |page| -%>
<% if page.left_outer? || page.right_outer? || page.inside_window? %>
<%= page_tag page %>
<% elsif !page.was_truncated? %>
<%= gap_tag %>
<% end %>
<% end %>
<%= next_page_tag unless current_page.last? %>
<%= last_page_tag unless current_page.last? %>
</ul>
<% end %>
Replace app/views/_first_page.html.erb with the following (note the change to the class of li and from link_to_unless to link_to):
<li <%= "class=disabled" if current_page.first? %>>
<%= link_to raw(t 'views.pagination.first'), url, :remote => remote %>
</li>
Also replace the contents of _prev_page, _last_page, and _next_page in a similar fashion (you'll just need to change "current_page.first?" to "current_page.last?"
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) %>")
I've got ajax pagination working with the Kaminari gem on my website but I'm having difficulty getting ajax callbacks working
I'm using jquery-1.5.1, rails 3.0.5 and I have the latest rails.js file
My podcasts.html.haml looks as follows
#paginator
= paginate #podcasts, :remote => true
#podcasts
= render #podcasts
My index.js.erb file looks like this:
$('#podcasts').html('<%= escape_javascript render(#podcasts) %>');
$('#paginator').html('<%= escape_javascript(paginate(#podcasts, :remote => true).to_s) %>');
The pagination side of things works fine, and the pages do indeed load via ajax but I want to do some ajax callbacks and I just can't figure out how to get this working.
I've tried adding numerous variations of the following code to my application.js file but with no success at all:
$('#paginator a').bind('ajax:success', function(data, status, xhr) {alert("success!");})
I would expect the code above to fire off an alert once the ajax stuff has finished. Nothing is happening though.
Anyone got any ideas?
PS
The paginate method above, is from the Kaminari gem and it creates the following html:
<div id="paginator">
<nav class="pagination">
Page 1
Page 2
Page 3
</nav>
</div>
I was not able to follow exactly your code, but I made a simple test (jquery 1.5.1, rails 3.0.5), and it works for me:
ajax_controller.rb
class AjaxController < ApplicationController
def get_data
respond_to do |format|
format.js { sleep 1; render :json => "ajax value" }
end
end
end
index.html.erb
<%= link_to "get_data", get_data_path, :remote => true, :id => 'request' %>
<div id="response">
</div>
<%= javascript_tag do %>
$("#response").html("default value");
$("#request").bind("ajax:success", function(e, data, status, xhr) {
$("#response").html(data);
});
<% end %>
routes.rb
get "ajax/index"
get "ajax/get_data", :as => "get_data"
I hope this help.
So here is my form
<% remote_form_for([:admin, Page.new]) do |f| %>
<ol>
<li>
<%= f.label(:title) %>
<%= f.text_field(:title) %>
</li>
<li>
<%= f.label(:parent_page) %>
<%= f.select(:parent_page_id, Page.roots.map { |p| [p.title, p.id] }.unshift(["none", nil])) %>
</li>
</ol>
<div class="modal-controls">
<%= submit_tag("Save") %> or <%= link_to_function("cancel", "R.Pages.hideAdd();") %>
</div>
<% end %>
And my action
def create
#page = Page.create(params[:page])
#languages = Language.all
#languages.each do |language|
#page.page_languages.create(:language_id => language.id)
end
For some reason the submitted for does not call the create.js.rjs template, but instead tries to call create.html.erb, do i need some sort of extra setting with the form?
btw i am using rails 2.3.5
I can't remember the exact default behavior in rails, but have you tried putting a respond_to at the end of your controller action:
respond_to(:html, :js)
Hope this helps.
EDIT
I went back to check on the default behavior for Rails in respect to rendering views. Rails favors convention over configuration in this instance. The default behavior is that Rails automatically renders views with names that correspond to actions. You don't need the respond_to any more if you stick to this convention. Here is the documentation.
Just wanted to update my post with the correct info... glad you figured your problem out.
I had named my template create.rjs.js instead of create.js.rjs, thats why i didnt work