The controller Actions
def search_leads
#search = Sunspot.search(Lead) do |searcher|
searcher.all do
fulltext params[:email], :fields => :email
fulltext params[:name], :fields => [:first_name, :last_name]
end
searcher.paginate(:page => params[:page], :per_page => 10)
end
#leads = #search.results
respond_to do |format|
if (params[:email].present? || params[:name].present? ) and (current_user.credits > 0)
format.html { redirect_to search_leads_path }
format.js { }
else
format.html { redirect_to new_search_path }
end
end
end
search_leads.js.erb
$(".search_results").html("<%= escape_javascript(render :partial => 'search/search_results') %>");
$('#paginator').html('<%= escape_javascript(paginate(#search.hits, :remote => true).to_s) %>');
HTMl
<div id="paginator">
<%= paginate #search.hits, remote: true %>
</div>
Pagination buttons appear in results, but i am not able to scroll through pages. When clicking on next pages, no call goes to solr.
Everything is ok, the issue is remote: true on paginate, just update like below
Remove remote: true from paginate and it will be on the partial e.g search_results.html.erb
<%= paginate #search.hits %>
and the main file e.g search_leads.html.erb add this script
<script type="text/javascript">
$(document).ready(function() {
$('.pagination > a').attr('data-remote', 'true');
});
</script>
the .pagination > a is selector if this not working then just find the selector from browser console then use this.
I think this line does not require, remove this
$('#paginator').html('<%= escape_javascript(paginate(#search.hits, :remote => true).to_s) %>');
and on the search_leads.js.erb this script also OK
$(".search_results").html("<%= escape_javascript(render('search/search_results')) %>");
Related
I am trying to load comments by paginating them on a blog post via AJAX and the will_paginate gem.
The problem I'm facing is that it's not segmenting the total amount of comments for that post to different pages, it is simply loading duplicate comments of the initial render or "first page of comments".
application.js:
// LOAD MORE POSTS (BLOG INDEX)
$( document ).ready(function() {
if ($('#paginate-load-more-button').size() > 0) {
$('#paginate-load-more-button .pagination').hide()
$('#load-more-posts').show().click(function() {
more_posts_url = $('#paginate-load-more-button .pagination .next_page a').attr('href');
$this = $(this);
$this.html('<img src="images/ajax-loader.gif" alt="" title=" Loading..." /> ').addClass('disabled');
$.getScript(more_posts_url, function() {
if ($this) {
$this.text('Load more posts').removeClass('disabled');
}
});
});
};
});
Posts > show.js.erb:
$('#listing-load-more-button').append("<%= j render(partial: 'comments/comment', collection: #post.comments) %>");
<% if #comments.next_page %>
$('#paginate-load-more-button .pagination').replaceWith('<%= j will_paginate #comments %>');
$('#paginate-load-more-button .pagination').hide();
<% else %>
$('#paginate-load-more-button .pagination, #load-more-posts').remove();
<% end %>
The partial 'comments/comment' that is being rendered, is simply each individual comment entry with a reply form.
Posts > show.html.erb:
<div id="listing-load-more-button">
<%= render(partial: 'comments/comment', collection: #post.comments) %>
</div>
<div id="paginate-load-more-button">
<%= will_paginate #comments %>
</div>
<% if #comments.next_page %>
<div class="center">Load Comments</div>
<% end %>
PostsController:
def show
...
#comments = Comment.paginate(page: params[:page], per_page: 3).order('created_at DESC')
respond_to do |format|
format.html
format.js
end
end
I've also tried using #comments = #post.comments.paginate(page: params[:page], per_page: 3).order('created_at DESC') instead as I learned from this question/answer but it still doesn't seem to work properly.
Thank you for the help!
You are rendering collection: #post.comments (that's not the paginated relation), you should render collection: #comments.
In my app there is a list of items which you can upvote. I want to make these votes with AJAX calls.
This is the view:
<ul class="list-groups">
<% #questions.each do |question| %>
<li class="list-group-item">
<%= link_to question.description, question_path(question) %>
<%= form_for(question, :url => url_for(:controller => 'vote', :action => 'vote'), method: :post, html: { class: 'form-inline' }) do |f| %>
<%= f.submit 'Up vote', class: "btn btn-default" %>
<%= f.hidden_field :id, :value => question.id %>
<% end %>
</li>
<% end %>
</ul>
And this the method that does it:
class VoteController < ApplicationController
respond_to :json
def vote
question_id = params[:question][:id]
user_id = current_user.id
vote = Vote.where(["question_id = :q", { q: question_id }]).where(["user_id = :u", { u: user_id }])
respond_to do |format|
if vote.nil?
#vote = Vote.new
#vote.question_id = question_id
#vote.user_id = user_id
#vote.save
format.html { render '/home/index' }
format.json { render :json => { :status => 'ok' } }
else
format.html { render '/home/index' }
format.json { render :json => { :status => 'failed', :msg => 'You already voted' } }
end
end
end
end
If I don't include this format.html { render '/home/index' } I am getting this error:
ActionController::UnknownFormat in VoteController#vote
But I don't want to render the page again, I am just loading the pieces of html that will change after the action with jQuery and ajax.
How can I respond only with the json?
Use respond_with instead of respond_to in your controller action.
respond_with do |format|
respond_to at the top of your controller is designed to work with respond_with in your controller action, whereas respond_to in your controller action ignores the respond_to that you've defined at the top of your controller.
Also make sure you are making a remote call, instead of a normall one if you want your request to go through AJAX.
<%= form_for(question, :url => url_for(:controller => 'vote', :action => 'vote'), method: :post, remote: true, html: { class: 'form-inline' }) do |f| %>
Note the remote: true part that is added as an argument to the form_for helper.
You need to include remote: true in form_for in order to make the call requests AJAX instead of HTML.
<%= form_for(question, :url => url_for(:controller => 'vote', :action => 'vote'), remote: true, method: :post, html: { class: 'form-inline' }) do |f| %>
Check out the Working with JavaScript in Rails documentation for more information.
I have a form:
<% form_tag({:controller => "/faq", :action => 'search_ajax'}, :update => "help_results", remote: true) do %>
that is going to the search_ajax action which is supposed to update the help_results div. That action is supposed to render a partial at the end, but I for sure am having syntax issues:
def search_ajax
#categories = HelpCategory.find(:all)
if params[:query].not_blank? && params[:query] != "Search for help about..."
#query = params[:query]
#terms = params[:query].split.map {|t| "%#{t.downcase}%" }
options = {
:allow_partial_match => true,
:order => 'fulltext_match_score DESC',
}
#results = SearchableText.search_model(HelpItem, #query, options).uniq
#results = {"Search Results" => #results} if !#results.blank?
#complicated_query = HelpItem.is_complicated_query?(#query)
#search_included = true
else
#results = HelpItem.all.group_by {|item| item.category.name rescue "Misc"}
#search_included = false
end
render :partial => "results"
respond_to do |format|
format.js do
render :partial => 'results'
end
format.html do
render :partial => 'results'
end
end
end
Some of the respond_to area is commented out. I am getting the error message:
ActionController::DoubleRenderError in FaqController#search_ajax
I know that if I add the remote => true helper into my form that the controller action needs to respond to js. I'm pretty sure this is a syntax error. The respond_to also comes at the end of my controller action.
Remove the
render :partial => "results"
Above the respond_to block
Rails newbe here. I've got links that do ajax query to server:
<%= link_to g.name, g, :class => 'link link-to-gallery', :remote => true %>
JS view that loads data from partial:
$('#content').html('<%= escape_javascript render("layouts/galleries/show") %>');
And controller that operates with models and renders html and js:
class GalleriesController < ApplicationController
def show
#galleries = Gallery.all
#gallery_to_show = Gallery.find(params[:id])
respond_to do |format|
format.html
format.js
end
end
end
Ajax works fine, but I try to put callback after ajax completed:
jQuery(function() {
$(".link-to-gallery").bind("ajax:complete", function() {
alert(1)
});
});
and alert never shows. What am I doing wrong? Rails version is 3.2.11, Ruby version is 1.9.3p194
Update: When I'm using this code
jQuery(function() {
$(".link-to-gallery")
.on("ajax:before", function () {
alert("before")
})
.on("ajax:complete", function() {
alert("complete")
});
});
"before" alert fires but only once. If I press again I gain nothing. But ajax still works.
I think the problem is with your controller method that is not responding the async call with a success status message, 200.
Try this
def show
#galleries = Gallery.all
#gallery_to_show = Gallery.find(params[:id])
respond_to do |format|
format.html { :status => 200 }
format.js { :status => 200 }
end
end
If that doesn't work, try this.
def show
#galleries = Gallery.all
#gallery_to_show = Gallery.find(params[:id])
respond_to do |format|
format.html { :status => :ok }
format.js { :status => :ok }
end
end
It seems that I'm lame but smart enough to fix this. I had these links:
<%= link_to g.name, g, :class => 'link link-to-gallery', :remote => true %>
in the partial which gets re-rendered after ajax. So the callback functions that were attached to these links were flushed away after ajax. So I put link out of this partial and it works now.
In a Rails 3.2 index view I am rendering two partials.
<%= render :partial => 'users/user', :locals => {:users => #happy_users} %>
<%= render :partial => 'users/user', :locals => {:users => #sad_users} %>
and in the partial
<% users.each do |user| %>
Show some fields
<% end %>
<%= will_paginate users %>
The pagination is not working.
If I alter will_paginate to take an instance variable, pagination works (but the wrong collection)
<%= will_paginate #users %>
How can I pass locals to will_paginate when the partial is called?
(I realize that I'll also need to pass :param_name to get this working with two collections. For now I'm just trying to get one instance working.)
The partial is rendered via index.js.erb
$(".ajaxable-users").html('<%= escape_javascript(render("users/user")) %>');
And the controller looks like
def index
#users = User.scoped.paginate(:page => params[:page], :per_page => 5)
#happy_users = User.happy_scope.paginate(:page => params[:page], :per_page => 5)
#sad_users = User.happy_scope.paginate(:page => params[:page], :per_page => 5)
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #users }
format.json { render :json => #users }
format.js
end
end
Thanks for any ideas.
you need to make sure the controller knows which page link of which listing you press. we do this by passing a param to will_paginate page link generator.
you need to make sure your js updates the correct html tag when refreshing the pagination of either listing. we do this by wrapping the pagination in a mood-dependent :) div tag.
since we share the partial we need to make sure mood as well as correct collection is set in controller and passed to partial as local from index views (both html and js).
finally make sure your ajax remote picks up after you redraw pagination (this is a bonus)
so, to set controller instance vars depending on request mood parameter
note that this code also spares you some db calls, since if you just pagintae sad users you do not need to retrieve happy ones or all).
I ommit #users for simplicity, its never used
I suspect happy scope for sad users is only a typo
.
# controller
def index
#mood = params[:mood]
#mood_users = #happy_users = User.happy_scope.paginate(:page => params[:page], :per_page => 5) if #mood.blank? || #mood == 'happy'
#mood_users = #sad_users = User.happy_scope.paginate(:page => params[:page], :per_page => 5) if #mood.blank? || #mood == 'sad'
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #users }
format.json { render :json => #users }
format.js
end
end
make sure we dispatch the right locals to partials:
# index.html.erb
<%= render :partial => 'users/user', :locals => {:users => #happy_users, :mood => 'happy' } %>
<%= render :partial => 'users/user', :locals => {:users => #sad_users, :mood => 'sad' } %>
make partial mood sensitive allowing for distinct div tag id. also put mood in request url.
# users/user partial
<div id='<%= "#{mood || ''}users"%>'>
<% users.each do |user| %>
Show some fields
<% end %>
<%= will_paginate users, :params => { :mood => mood } %>
</div>
this js allows for refreshing different collections in different divs depending on which pagination link was pressed.
# index.js.erb
$("#<%= #mood %>users").html('
<%= escape_javascript(render(partial: "users/user", locals: { users: #mood_users, mood: #mood })) %>
');
For unobtrusive ajax links for pagination you need.
Ruby - Rails 3 - AJAXinate Paginate and sorting
# in a generic js
$(document).ready(function () {
$(".pagination").find("a").livequery(function () {
$(this).attr("data-remote", true);
});
});
Note that the solution should even work if javascript is not enabled and we fall back on html. In this case both sections should be redisplayed allowing for different pages.
MODIFIED CODE TO ALSO HANDLE GRACEFUL JS FALLBACK TO HTML
controller
# controller
def index
#mood = params[:mood]
#happy_page = #mood == 'happy' ? params[:page] : params[:happy_page]
#sad_page = #mood == 'sad' ? params[:page] : params[:sad_page]
#mood_users = #happy_users = User.happy_scope.paginate(:page => #happy_page, :per_page => 5) if !request.xhr? || #mood == 'happy'
#mood_users = #sad_users = User.happy_scope.paginate(:page => #sad_page, :per_page => 5) if !request.xhr? || #mood == 'sad'
#mood_users = #users = User.scoped.paginate(:page => params[:page], :per_page => 5) if #mood.blank?
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #users }
format.json { render :json => #users }
format.js
end
end
forward new view vars to partial local
# index.html.erb
<%= render :partial => 'users/user', :locals => {:users => #happy_users, :mood => 'happy', :happy_page => #happy_page, :sad_page => #sad_page } %>
<%= render :partial => 'users/user', :locals => {:users => #sad_users, :mood => 'sad', :happy_page => #happy_page, :sad_page => #sad_page } %>
we only need to pass this here to not get undefined method in partial.
# index.js.erb (fixed HTML syntax)
$("#<%= #mood %>users").html('
<%= escape_javascript(render(partial: "users/user", locals: { users: #mood_users, mood: #mood, :happy_page => #happy_page, :sad_page => #sad_page })) %>
');
this will then persist happy pages in param if sad page link is clicked, and vica versa.
# users/user partial
<div id='<%= "#{mood || ''}users"%>'>
<% users.each do |user| %>
Show some fields
<% end %>
<%= will_paginate users, :params => { :mood => mood, :happy_page => happy_page, :sad_page => sad_page %>
</div>
First, create in controller two diferent methods for each list for example fill_list1 and fill_list2 there are independent of method for create the main page for example index
Each list method must render a partial without layout for example
render :partial=>'fill_list1', :layout => false
The main page must call partials in view for first time.
when you click in paginate control you must hack click for call ajax next pagination items list
$('list1 a').live('click', function(event){
event.preventDefault();
$.ajax(
{url:URLFORCALLMETHODLIST,
success: function(content) {
DIVLOCATIONLIST.html(content);
},
async:false,
});
});
Try passing proper locals in the index.html.erb:
$(".ajaxable-users").html('
<%= escape_javascript(render("users/user", locals: { users: #users })) %>
');