I want to apply multiple pagination with Kaminari via Ajax now here is my code for controller
def user_note
#user = current_user
#notes = Bookmark.where('user_id = ? && note is not NULL',current_user.id).order('created_at DESC').page(params[:page_1]).per(4)
#bookmarks = Bookmark.where('user_id = ? && note is NULL',current_user.id).order('created_at DESC').page(params[:page_2]).per(4)
respond_to do |format|
format.html
format.xml{ render :xml => #user}
end end
now for views i have two partials to render this arrays
<div id="bookmarks">
<%= render :partial =>"users/bookmark",:locals => { :bookmark => #bookmarks} %>
</div>
<%= paginate #bookmarks,:remote => true, :param_name => 'page' %>
inner partial is
<% bookmark.each do |bookmar| %>
<%= render :partial => 'show_bookmark.html.erb' , :locals => { :bookma => bookmar} %>
<%end%>
script for pagination update is being handled in a separate file
$('#bookmarks').html('<%= escape_javascript render(:partial =>"users/bookmark",:locals => { :bookmark => #bookmarks}) %>');
$('#paginator').html('<%= escape_javascript(paginate(#bookmarks, :remote => true).to_s) %>');
But by doing every thing it is not updating to state of page neither the contain in the page.
you are missing to pass params at this line
$('#paginator').html('<%= escape_javascript(paginate(#bookmarks, :remote => true).to_s) %>');
i think it should be like this
$('#paginator').html('<%= escape_javascript(paginate(#bookmarks, :remote => true, :param_name => 'page_2').to_s) %>');
and you are also passing wrong param at this line
<%= paginate #bookmarks,:remote => true, :param_name => 'page' %>
it should be like this
<%= paginate #bookmarks,:remote => true, :param_name => 'page_2' %>
and please also check that whether you are sending the response correctly to the JS file or not.
I found this question searching for paginating multiple models on the same page. It's not clear to me how the pagination for the #notes collection is intended to work, but as presented, the solutions will only paginate the #bookmarks collection via AJAX.
There will be issues if you want to maintain pagination for both collections via html OR if you change the js file to render both collections.
I implemented a solution to my similar problem like this:
An html view that renders a template with two partials: one for #notes (including its pagination helper) and another that renders #bookmarks with its pagination helper
Pagination links marked with remote: true
One js view that re-renders the two partials, something like
$('#notes_container').html('<%= j(render partial: 'paginated_notes_list') %>');
$('#bookmarks_container').html('<%= j(render partial: 'paginated_bookmarks_list'); %>');
This is the key: Pagination links that take the current page of the other model as a parameter. This way you do not "lose" which page you are on in the other model.
<%= paginate #notes, param_name: 'page_1', params: {page_2: params[:page_2]} %>
<%= paginate #bookmarks, param_name: 'page_2', params: {page_1: params[:page_1]} %>
Again, I'm not really clear on how the asker's system is supposed to function, but this solution will allow user to page through both models without losing their "place" in the other model via AJAX or html.
Related
I have a simple form:
<%= form_for [current_user, #bookcase], :id => "shelf_update_form", :remote => true, :html => { :multipart => true} do |f| %>
<input id="bookcase_image" class="file" type="file" name="bookcase[image]" size="13">
<% end %>
That automatically uploads when a file has been selected:
$("#shelf_update_form").change(function() {
$("#shelf_update_form").submit();
});
I want the update action to render js view, but by default it renders html instead. I try forcing it to render js like so:
respond_to do |format|
format.js
end
But then I get this error:
NetworkError: 406 Not Acceptable
Even then, my log reports:
Processing by BookcasesController#update as HTML
How can I get it to process as JS instead?
UPDATE:
The view:
triggerAjaxHistory("<%= #href %>", false);
I get the same results with a more generic view, too:
alert("I work now!")
In the controller, do
respond_to do |format|
format.js if request.xhr?
end
Is your view named as .js.erb?
Can you check using firebug in your browser what exactly you are getting as the response? Turn on net logging and look at the response.
Also do you have the following in your layout?
<%= javascript_include_tag :defaults %>
<%= csrf_meta_tag %>
Can you put in logger.info whatever_message commands to make sure you the controller action executes and you go into the correct view?
What happens if you specify the js format specifically in the controller as
class UserController < ApplicationController
respond_to :js, :only => :update, :layout => 'false`
What happens if you specify the format in form_for as :format => :js
Is your form nested within another form?
This is how my view looks (please ignore the opening and closing tags):
#obj1.leaves.each do |l|
<div id = "form">
if <some_condition>
render :partial => 'shared/view1', :locals => { :l => l }
else
render :partial => 'shared/view2', :locals => { :l => l }
end
</div>
end
And the final action on view1 causes view2 to display and vice versa thru ajax. But when view1 or view2 are rendered the local variable 'l' is not recognized anymore and throws an error causing the forms not to display (except on manual page refresh). What do I do to make the forms work and persisting my 'l'?
Thanks for your help in advance.
EDIT: My create.js.erb file for view1 (view2 i actually the destroy method so vice versa):
$("#form").replaceWith("<%= escape_javascript(render('shared/view2')).html_safe %>")
And my actual view:
<%= form_for([l, l.likes.build], :remote => true) do |f| %>
<div class="actions"><%= f.submit "Like" %></div>
<% end %>
(Not an answer.)
#obj1.leaves.each do |l|
partial = <some_condition> ? 'shared/view1' : 'shared/view2'
render :partial => partial, :locals => { :l => l }
end
Locals are just that; local. It's not clear to me what Ajax you're talking about--replaceWith just replaces content, it doesn't make a request. If it's all in the same request, you could make l an instance variable (#l) and see if that clears things up.
I'm using the Kaminari gem for my ruby on rails application (For anybody still using will_paginate, I would recommend to consider switching! Much cleaner and more versatile).
The problem I have is that I want to specify a controller action when doing AJAX pagination, ie. get my pagination to work remotely, as such:
<%= paginate #feeds, :param_name => :page, :remote => true%>
By default, when I set :remote => true, and add the following lines to my "pages" controller home.js.erb file, it works on my homepage. I don't even need to specify which js partial to refer to; it chooses automatically.
$('.synopsis').html('<%= escape_javascript render('exchanges/synopsis', :feeds => #feeds)%>');
$('.paginator').html('<%= escape_javascript(paginate(#feeds, :param_name => :page, :remote => true).to_s)%>')
BUT the catch is that this "synopsis" div is a partial that I render on a lot of different pages in my application. So on pages where the controller isn't my "pages" controller, the remote pagination no longer works.
One solution would be to add these two lines to js.erb files in my many different controllers. But that would be redundant and inelegant.
I would prefer to be able to specify in the "paginate" call, which controller and which action to use for the remote call. Then I think I would write an action like:
def paginate_remotely
respond_to paginate_remotely.js
end
How would I be able to do this? It seems like such a simple question but I haven't been able to figure it out. The following certainly does not work:
<%= paginate #feed_exchanges, :param_name => :exchange_page, :remote => true, :controller => :exchanges, :action => :paginate_remotely %>
For those who are interested, the answer is you have to specify the controller and action under a :params specification, as follows:
<%= paginate #feed_exchanges, :params => {:controller => :exchanges, :action => :paginate_remotely}, :param_name => :exchange_page, :remote => true %>
Don't forget to write define the route for this action in config/routes.rb, and create a js partial, in my case called paginate_remotely.js.erb, containing:
$('.synopsis').html('<%= escape_javascript render('exchanges/synopsis', :feeds => #feeds)%>');
$('.paginator').html('<%= escape_javascript(paginate(#feeds, :param_name => :page, :remote => true).to_s)%>')
Using rails3 and prototype (rails.js)
I have a simple list of products with edit and delete links as images.
When deleting a product, the list is not updated. Refreshing the page shows that the product has indeed been deleted.
/app/views/products/list.rhtml
<div id="product_list">
<%= render :partial => 'list' %>
</div>
/app/views/products/_list.rhtml
<%= link_to image_tag("delete.png"), { :controller => 'products', :action => 'destroy', :id => product }, :method => :delete, :confirm => "Are you sure?", :remote => true %>
/app/controllers/products.rb
def destroy
Product.find(params[:id]).destroy
#products = Product.all
end
/app/views/products/destroy.rjs (not sure what to do with that...)
$(document).ready(function() {
$("#product_list").html("<%= escape_javascript( render(:partial => "list") ) %>");
});
So the remote link seems to work fine.
I'm not sure how to use the ajax callback to update #product_list
I tried to put the following in the head of the page:
$(document).ready(function(){
$('#product_list').bind("ajax:success", function(evt, data, status, xhr){
alert('hello');
})
});
But it's not executed (that's probably not a valid code for prototype) and I wouldn't know anyway what code to put inside so that my list gets updated after destroying a product
Any help (other than "use jQuery") is greatly appreciated!
EDIT: Here is the server log for the delete action (after I moved the javascript above to destroy.js.erb)
Started POST "/products/destroy/3" for 127.0.0.1 at .....
Processing by ProductsController#destroy as JS
Parameters: {"_"=>"", "id"=>"3"}
[1m[36mProduct Load (0.0ms)[0m [1mSELECT `products`.* FROM `products` WHERE (`products`.`id` = 3) LIMIT 1[0m
[1m[35mSQL (0.0ms)[0m BEGIN
[1m[36mSQL (0.0ms)[0m [1mDELETE FROM `products` WHERE (`products`.`id` = 3)[0m
[1m[35mSQL (78.1ms)[0m COMMIT
[1m[36mProduct Load (0.0ms)[0m [1mSELECT `products`.* FROM `products`[0m
Rendered products/destroy.js.erb within layouts/standard (31.2ms)
Completed 200 OK in 312ms (Views: 62.5ms | ActiveRecord: 78.1ms)
Processing by ProductsController#destroy as JS so the remote link works
[36mProduct Load (0.0ms)[0m [1mSELECT products. FROM products* The #products = Product.all is executed
Rendered products/destroy.js.erb within layouts/standard the javascript fie is rendered
So now I guess it's a problem with the javascript code:
$(document).ready(function() {
$("#product_list").html("<%= escape_javascript( render(:partial => "list") ) %>");
});
Is that kind of code supported by prototype? I don't use jQuery...
Found the answer on my own:
/app/controllers/products.rb
def destroy
Product.find(params[:id]).destroy
#products = Product.all
respond_to do |format|
format.js { render :layout=>false }
end
end
/app/views/products/destroy.js.erb
$("product_list").update("<%= escape_javascript(render(:partial => "list")) %>");
Why is there NO tutorial, code example or anything clear about the ajax thingy in rails3?
I had to use code parts from 5 different blogs, forums and casts, and mix them all together until I find the right combination... sigh
on repecmps lines,
just insert :content_type to represent part of content downloaded, like this:
format.js { render :layout=>false, :content_type => 'application/javascript' }
with complete part of repecmps responses:
def destroy
Product.find(params[:id]).destroy
#products = Product.all
respond_to do |format|
format.js { render :layout=>false, :content_type => 'application/javascript' }
end
end
/app/views/products/destroy.js.erb:
$("product_list").html("<%= escape_javascript(render(:partial => "list")) %>");
and, I found this to night.
I think your destroy action is doing too much, as it is destroying the product and list all the products. You could do something like:
/app/controllers/products.rb
class ProductsController < ApplicationController
respond_to :html, :js
def destroy
#product_id = params[:id]
Product.find(#product_id).destroy
respond_with do |format|
format.html { redirect_to posts_path }
end
end
end
/app/views/products/destroy.js.erb
$("#product_<%= #product_id %>").remove()
As long as your product element in the index uses something like dom_id, here's an example:
<ul id="products">
<% #products.each do |product|
<li id=<%= dom_id product %>>...</li>
<% end %>
</ul>
This way your destroy action will only destroy the intended product, and if the client has no JS it fallback the HTML request which will redirect to the products index which will be updated accordingly.
Hum... I'm going to try to help you.
Are you sure after clicking on the delete link, the request is handled as JS ?
Check on the log.
Is you file "app/views/products/destroy.rjs" is rendered ?
Rjs doesn't exist anymore in rails3. The new name is UJS.
Try to rename the file to destroy.js.{haml or erb}
Is it better ?
UPDATED CODE at the bottom
I am creating a story voting app via Simply Rails 2 book. I am getting this error when I click the button to vote up a story:
No route matches "/stories/4-pure-css-icons-showcase"
My routing file looks like this:
Shovell::Application.routes.draw do
get "votes/create"
root :to => "stories#index"
resources :stories do
resources :votes
end
end
votes_controller.rb:
class VotesController < ApplicationController
def create
#story = Story.find(params[:story_id])
#story.votes.create
end
end
create.rsj :
page.replace_html 'vote_score', "Score: #{#story.votes.size}"
page[:vote_score].visual_effect :highlight
show.html.erb:
<h2>
<span id="vote_score">
Score: <%= #story.votes.size %>
</span>
<%= #story.name %>
</h2>
<p>
<%= link_to #story.link, #story.link %>
</p>
<div id="vote_form">
<%= form_tag :url => story_votes_path(#story), :remote => true do %>
<%= submit_tag 'shove it' %>
<% end %>
</div>
story.rb :
class Story < ActiveRecord::Base
validates_presence_of :name, :link
has_many :votes
def to_param
"#{id}-#{name.gsub(/\W/, '-').downcase}"
end
end
I've been working through a number of other errors before this having to do with deprecated code and so forth, so I feel somewhat lost at the moment. It seems like it should just be a routing a issue, but since I've been working through AJAX errors that also have to do with the vote function I wanted to post those files just in case it was more than routing.
It says no route matches "/stories/4-pure-css-icons-showcase" but when I visit "/stories" (my root) and click on the link to take me to "/stories/4-pure-css-icons-showcase" it works fine, however after clicking on the vote button I get this error. As you could probably tell after reading the code, it is suppose to update the vote count and do a :highlight via ajax.
UPDATE:
Changed code (all changes are per Sam's advice):
routes:
Shovell::Application.routes.draw do
resources :votes
root :to => "stories#index"
resources :stories do
resources :votes
end
show.html.erb:
<div id="vote_form">
<%= form_tag :url => new_story_vote_path(#story), :remote => true do %>
<%= submit_tag 'shove it' %>
<% end %>
</div>
votes_controller.rb
class VotesController < ApplicationController
def create
#story = Story.find(params[:story_id])
#story.votes.create
respond_to do |format|
format.html
format.js
end
end
The problem is still exactly the same, but I think (read: hope) we are making progress!
The scenario: My index (/stories) page randomly displays a story from the database, when you click the link it takes you to the story's internal page (ex. /stories/2-sitepoint-forums) on this page it displays the number of votes the story has and has a button to vote for it. When you click the vote button it is suppose to use ajax to update the #story.vote.size and use a :highlight visual effect. However, the problem is that when you click the vote button the page changes to a "Routing Error" page which displays:
No route matches "/stories/2-sitepoint-forums"
Its weird to me because you can in fact be routed to that address and you are from the link on the first page...
Here is the error in the console:
Started POST "/stories/2-sitepoint-forums?url=%2Fstories%2F2-sitepoint-forums%2F
votes%2F2-sitepoint-forums&remote=true" for 127.0.0.1 at 2010-11-08 16:30:17 -08
00
ActionController::RoutingError (No route matches "/stories/2-sitepoint-forums"):
Rendered C:/Ruby192/lib/ruby/gems/1.9.1/gems/actionpack-3.0.0.rc2/lib/action_dis
patch/middleware/templates/rescues/routing_error.erb within rescues/layout (1.0m
s)
Im not sure if this is any more telling, but I thought I'd add it incase.
New:
I have not been able to solve this problem as of yet. Because I still don't feel like I completely understand the issue I have decided to move over to the Ruby on Rails 3 Tutorial Book online and see if I can't figure it out while working through it. Since I was planning to do it next anyway (I have plans to combine both apps later) it appears now is the time.
<%= form_tag :url => new_story_vote_path(#story), :remote => true do %>
<%= submit_tag 'shove it' %>
<% end %>
That should send it to the create action.
def create
#story = Story.find(params[:story_id])
#story.votes.create
respond_to do |format|
format.html
format.js
end
end
And that should take care of your ajax.
take this get "votes/create" out of your routes
and add this
map.resources :votes
I'm not familiar with using form_tag and :remote (as I normally just write jQuery for stuff like this) but a couple of things definitely pop out at me with what you're doing here that may help you resolve the issue.
First of all, I think you can rework the way you set up a vote and thus the way you set up the form for the vote. In the stories controller, for the show action, I'd set up the vote right away:
#vote = Vote.new(:story_id => #story.id)
This lets you set up your form as so:
= form_for(#vote), :remote => true do |f|
= hidden_field f.story_id
= submit_tag "Vote"
This is both a cleaner way of doing things, in my opinion, but also may fix the general issue you are dealing with, because you are now passing data with the form (the hidden field) in your POST request. Rails will behave unexpectedly if you perform AJAX POST requests that do not actually submit data.
In other words, your original form is likely running as an AJAX POST request but it would have worked better as an AJAX GET request, since it is not actually submitting data, it is simply "hitting" an URL.
I am not sure if you found the answer to your problem yet, but I wanted to post for others that may be looking for an answer similar to yours.
The code:
<%= form_tag :url => new_story_vote_path(#story), :remote => true do %>
<%= submit_tag 'shove it' %>
<% end %>
will result in /stories/:story_id/votes/new url with a :post request. It won't work because the new route is a :get method request. If you wanted to go to the new method, you'll need to tell the form to use the get http method.
<%= form_tag :url => new_story_vote_path(#story), :remote => true, :html => { :method => :get } do %>
<%= submit_tag 'shove it' %>
<% end %>
However, I think that you are wanting to route to the create method in your controller. I would do something like:
<%= form_tag :url => story_votes_path(#story), :remote => true do %>
<%= submit_tag 'shove it' %>
<% end %>
This should route correctly to the create method in your VotesController.