JQuery + thumbs_up gem render vote count? - javascript

Plugins:
Thumbs Up & JQuery 1.5.2 (needed for another old gem)
I'm trying to render an updated vote count w/o a full HTTP request when a user votes on a post. Currently, it refreshes the page on every vote.
Posts Controller
def vote_up
post = Post.find(params[:id])
current_user.vote_exclusively_for(post)
respond_to do |format|
format.js
format.html {rRedirect_to :back}
end
end
def vote_down
post = Post.find(params[:id])
current_user.vote_exclusively_against(post)
respond_to do |format|
format.js
format.html {redirect_to :back}
end
end
Vote View (each post div has a vote div on the left (digg/reddit style) and content on the right)
<div class="post">
<div class="vote">
<div class="votewrapper">
<span class="votecount">
<%= post.votes_for - post.votes_against %>
</span>
<div class="votebtn">
<%= link_to image_tag('vote.png'), vote_up_post_path(post), :method => :post, :format => :js %>
</div>
</div>
</div>
<div class="postcontent">
all the post content, timestamp stuff, etc...
</div>
</div>
vote_up.erb.js (in the Posts folder).
$(".votecount").html(
"<%= escape_javascript post.votes_for - post.votes_against %>");
I've been stuck on this for a while and would very much appreciate any help ya'll can offer. I've seen the Jquery railscast and looked through other Stackoverflow answers, but I'm still quite noobish at Jquery.

It seems like you'll want to separate out your view code into partials and only refresh one partial when a rating is provided.
For your controller, instead of:
respond_to do |format|
format.js
format.html {redirect_to :back}
end
Do something like:
render :partial => "voutecount"
In your view, move out the votewrapper div into a new file called "_votecount.html.erb" within the same directory, and instead have the render code:
<%= render :partial => "votecount" %>
If you want to block the rating while it's refreshing (recommended), then you may want to ajaxify the call and control it more in the js. So, include your javascript within the view:
<%= javascript_include_tag 'votecount' %>
replace your link_to with good ol' html to have more info:
<img src = "....">
<img src = "....">
And create a new votecount.js in your public/javascripts folder with the following content:
$(function(){
$(".ratelink").click(function(){
var val = $(this).attr('updown');
var theid = $(this).attr('theid');
$("#votewrapper").block({ //blocks rate-rates while processing
message: null,
overlayCSS: {
backgroundColor: '#FFF',
opacity: 0.6,
cursor: 'default'
},
});
if (val == "up") {
$.ajax({
type: 'PUT',
url: "/mymodel/voteup?id="+theid,
success: function(){
$("#votewrapper").unblock();
}
});
} else {
$.ajax({
type: 'PUT',
url: "/mymodel/votedown?id="+theid,
success: function(){
$("#votewrapper").unblock();
}
});
}
})
good luck! :)

Related

Display a notice in rails after an ajax call

Hi I have a status controller where I render js template when a user deletes a status. This is the controller code:
def destroy
#status = Status.where(id: params[:id]).first
if #status.present?
make_subject(#status, Constants::Subject::BREAK)
respond_to do |format|
format.html { redirect_to root_path, notice: 'deleted' }
format.json { head :no_content }
format.js { render layout: false }
end
end
end
In my destroy.js.erb, I have:
$("#clear_status_<%= #status.id %>").fadeOut();
I have a partial which renders flash messages
<div id = "notice_wrapper">
<% if alert %>
<div class = "alerty">
<p> <%= alert %> </p>
</div>
<% elsif notice %>
<div class = "notice">
<p> <%= notice %> </p>
</div>
<% end %>
</div>
Once the status gets deleted successfully I want a notice which informs the user that the status is deleted successfully I want to display that message by rendering this partial.
How can I achieve this?
You can do it with JQuery. If put your own element instead of 'nav' where u want to show notice.
$('nav').after("<div class='alert alert-success'> Successfully Destroyed </div>");
$("#clear_status_<%= #status.id %>").fadeOut.fadeOut(250, function(){
$(this).remove();
});
Also Update your destroy method.
def destroy
#status = Status.find_by(id: params[:id])
if #status.present?
make_subject(#status, Constants::Subject::BREAK)
respond_to do |format|
#format.html { redirect_to root_path, notice: 'deleted' } # yr calling it async to destroy. format.html is needless.
format.json { head :no_content }
format.js
end
end
end
You will need a way to tell in your response if the delete was successful. And if it was, then show your notice.
For this purpose, I'll create a #deleted variable which will be boolean, and will be set to true if delete is successful, otherwise, false.
Following is the controller code:
def destroy
#status = Status.find(params[:id])
#deleted = false
if #status.destroy
#deleted = true
end
respond_to do |format|
format.html
format.json
format.js
end
end
and the destroy.js.erb file, you will have something of this sort:
<% if #deleted %>
$(".notice").html(<%= render 'notice_partial' %>)
<%= escape_javascript(alert("deleted successfully")) %>
<% end %>
$("#clear_status_<%= #status.id %>").fadeOut();

Including Ajax/JS to my voting system in Rails

How do i make it so that it does not refresh the page? instead it will just update the count numbers? Any help would be appreciated!
Stories controller:
def like
like = Like.create(like: params[:like], user: current_user, story: #story)
if like.valid?
flash[:success] = "Your selection was succesful"
redirect_to :back
else
flash[:danger] = "You can only like/dislike a story once"
redirect_to :back
end
end
index.html.erb:
<div class="pull-right">
<%= link_to like_story_path(story, like: true), :method => :put, :remote => true do %>
<i class="glyphicon glyphicon-thumbs-up"></i><%= story.thumbs_up_total %>
<% end %>
<%= link_to like_story_path(story, like: false), :method => :put, :remote => true do %>
<i class="glyphicon glyphicon-thumbs-down"></i><%= story.thumbs_down_total %>
<% end %>
</div>
Story.rb model:
def thumbs_up_total
self.likes.where(like: true).size
end
def thumbs_down_total
self.likes.where(like: false).size
end
The controller should respond_to the js "format", as described in Working with JavaScript in Rails.
Instead of redirect_to :back, respond with a meaningful status code, for example 201 for success (when a new resource has been created) or 400 for a bad request.
See RFC 2616, section 10 - Status Code Definitions.
Then, in your JS, handle the ajax:success event. This is also described in Working with JavaScript in Rails.
Let me show you an example:
First change your StoriesController as follow:
def like
#like = Like.create(like: params[:like], user: current_user, story: #story)
if #like.valid?
respond_to do|format|
format.js
end
else
respond_to do|format|
format.js {render status: 403, js: "alert('You can only like/dislike a story once'"}
end
end
end
And create a file called like.js.erb within your stories view directory with following content.
<% if #like.like %>
var $element = $(".glyphicon.glyphicon-thumbs-up");
<% else %>
var $element = $(".glyphicon.glyphicon-thumbs-down");
<% end %>
var oldCount = parseIn($element.text());
$element.text(oldCount + 1);
With the examples aside, you should at least Rails Guide in order to be able to use ajax effectively in rails. It's not that difficult.

Update ajax content with will_paginate

How can I update my view keeping all existing ajax and will_paginate functionality in place?
I have a page rehome.html.erb
<div id="options">Option Select Here</>
<div class="all_animals">
<%= render #animals %>
</div>
<% unless #animals.current_page == #animals.total_pages %>
<div id="infinite-scrolling">
<%= will_paginate #animals %>
</div>
<% end %>
// WILL_PAGINATE
<script type="text/javascript">
$(function(){
if($('#infinite-scrolling').size() > 0) {
$(window).on('scroll', function(){
//Bail out right away if we're busy loading the next chunk
if(window.pagination_loading){
return;
}
more_url = $('.pagination a.next_page').attr('href');
if(more_url && $(window).scrollTop() > $(document).height() - $(window).height() - 50){
//Make a note that we're busy loading the next chunk.
window.pagination_loading = true;
$('.pagination').text('Loading.....');
$.getScript(more_url).always(function(){
window.pagination_loading = false;
});
}
});
}
});
</script>
This will load all the #animals collection, paginating it to 6 per page, and when I scroll down the page another 6 are loaded etc etc.
Corresponding controller
class PublicController < ApplicationController
before_filter :default_animal, only: [:rehome]
def rehome
respond_to do |format|
format.html
format.js
end
end
private
def default_animal
#animals = Animal.animals_rehome.paginate(:page => params[:page], :per_page => 6)
end
end
rehome.js.erb
$('.all_animals').append('<%= j render #animals %>');
<% if #animals.next_page %>
$('.pagination').replaceWith('<%= j will_paginate #animals %>');
<% else %>
$(window).off('scroll');
$('.pagination').remove();
<% end %>
So when an option is selected from the dropdown an ajax post is made to create a new query which will return a new collection of #animals
$.ajax({
type: 'POST',
url: '/public/rehomed',
data: data_send,
success: function(data) {
//console.log(data);
}
});
Controller
def rehomed
# conditions logic
#animals = Animal.joins(:user).where(conditions).paginate(:page => params[:page], :per_page => 6)
respond_to do |format|
format.js {render json: #animals }
end
end
What I want to do is have the new collection loaded (paginated to 6 per page again) and when I scroll down only show the objects belonging to the new collection of #animals (if there are any).
At the moment the pagination links are not updated as when I scroll down the page the original collection is loaded.
Edit
So I have created a rehomed.js.erb file which is pretty much the same as my rehome.js.erb:
$('.all_animals').empty();
$('.all_animals').append('<%= j render #animals %>');
<% if #animals.next_page %>
$('.pagination').replaceWith('<%= j will_paginate #animals %>');
<% else %>
$(window).off('scroll');
$('.pagination').remove();
<% end %>
and within my rehomed action
respond_to do |format|
format.js
end
So the new collection of animals is loaded, the pagination links are recreated but using the rehomed url, example being:
Before
<a class="next_page" href="/public/rehome?page=2" rel="next">Next →</a>
After
<a class="next_page" href="/public/rehomed?page=2" rel="next">Next →</a>
So when I scroll down I just get the following as the links don't exist and getScript fails
$('.pagination').text('Loading.....');
Edit 2
I have implemented #japed's answer but now after the new collection is rendered the pagination will continue to render the whole collection of the db including repeating the ones that where selected for the new collection, it's repeating itself.
How can I ensure that the correct url is generated for my links?
Will paginate allows you to set the params hash so you should be able to change it to use your other controller action like this:
will_paginate(#animals, :params => { :controller => "public", :action => "rehomed" })

Dynamically Change Div Content in Rails 4.1.4

I've spent almost my entire day trying to figure out how to solve this dilemma but unfortunately a majority of the solutions I've found are related to an outdated Rails version that still allowed "render" to be used in assets.
Here's what I'm trying to do:
My view finds each "Trip" entry and displays each as a thumbnail on the page. When the user clicks on each thumbnail, I would like the additional details (and also associations, each trip has a has_many: weeks) to be rendered in the Div below those thumbnails (replacing the previous content).
I can't seem to get Ajax to work and after several hours of attempting finally learned that "render" can't be used in assets. I would sincerely appreciate any help and along with potential solutions if someone could provide a possible reference guide for Ajax with Rails 4 that would be fantastic because I can't seem to find one.
Here's my code:
View - index.html.erb
<div>
<ul class="thumbnails col-md-offset-2">
<% Trip.find_each do |trip| %>
<li class="col-md-3" style="list-style-type:none;">
<%= link_to image_tag("http://placehold.it/350x350", :border => 0), :class => 'thumbnail', :url=>'/trips/selected_trip/params', :remote => true %>
<h3><%= trip.name %></h3>
</li>
<% end %>
</ul>
<div id="selected_trip">
</div>
</div>
Controller - trips.controller.rb
class TripsController < ApplicationController
before_filter :authenticate_user!
after_action :verify_authorized
def index
#trips = Trip.all
authorize Trip
end
def new
#trip = Trip.new
authorize Trip
end
def create
#trip = Trip.new(trip_params)
authorize Trip
if #trip.save
flash[:notice] = "New trip has been created."
redirect_to #trip
else
#Fill me in
end
end
def edit
#trip = Trip.find(params[:id])
authorize Trip
end
def update
#trip = Trip.find(params[:id])
authorize Trip
#trip.update(trip_params)
flash[:notice] = "Trip has been updated."
redirect_to #trip
end
def show
#trip = Trip.find(params[:id])
authorize Trip
end
def destroy
#trip = Trip.find(params[:id])
authorize Trip
#trip.destroy
flash[:notice] = "Trip has been deleted."
redirect_to trips_path
end
def selected_trip
#trip = Trip.find(params[:id])
#trip.name
respond_to do |format|
format.js
end
end
end
private
def trip_params
params.require(:trip).permit(:name, :description, :status)
end
end
Javascript - trips.js.erb (I know this method doesn't work anymore with render not being available in assets)
$('#selected_trip').html("<%= escape_javascript(render :partial => 'selected_trip', :content_type => 'text/html'%>")
Partial - _selected_trip.html.erb
<p>Success!</p> <!-- Just for testing, will replace with actual content -->
Thanks,
Nate
Edit 11:10PM (it works)-
I've changed my controller to:
def selected_trip
#trip = Trip.find(params[:id])
authorize Trip
render :partial => 'selected_trip', :content_type => 'text/html'
end
and my view to:
<div>
<ul class="thumbnails col-md-offset-2">
<% Trip.find_each do |trip| %>
<li class="col-md-3" style="list-style-type:none;" data-tripID="<%= trip.id %>">
<%= link_to image_tag("http://placehold.it/350x350", :border => 0), selected_trip_trip_path(trip), :class => 'thumbnail', :remote => true %>
<h3><%= trip.name %></h3>
</li>
<% end %>
</ul>
<div id="selected_trip">
</div>
</div>
</div>
<script>
$('a.thumbnail').on('ajax:success', function(evt, data) {
var target = $('#selected_trip');
$(target).html(data);
});
</script>
If you want to avoid rendering from the assets, you can try doing it this way.
I am assuming you know where you need to put the listener in order to catch the AJAX call, and also you can figure out, where you want to place the results when the AJAX comes back with a success status. Then, you want to do something like this:
$('whatever_container_they_can_click').on('ajax:success', function(evt, data) {
var target = $('#selected_trip'); // Find where is the destination
$(target).html(data);
});
Change your controller action to:
def selected_trip
#trip = Trip.find(params[:id])
render :partial => 'selected_trip', :content_type => 'text/html'
end

The AJAX request cannot see the effect without refresh the browser in Rails

I faced the same problem with this guy
I change rjs to js.erb just like him. And we all use <%= button_to 'Add to Cart',line_items_path(:product_id => product) ,:remote=>true %> to send an AJAX request to the controller. format.js to fine and execute create.js.erb. But the cart did not add anything.
log result :
Rendered line_items/_line_item.html.erb (4.3ms)
Rendered carts/_cart.html.erb (8.0ms)
Rendered line_items/create.js.erb (8.8ms)
That's the index.html.erb we send the AJAX request
<% if notice %>
<p id="notice"><%= notice %></p>
<% end %>
<h1>Your Pragmatic Catalog</h1>
<% #products.each do |product| %>
<div class="entry">
<%= link_to image_tag(product.image_url), line_items_path(:product_id => product), html_options = {:method => :post} %>
<h3><%= product.title %></h3>
<%=sanitize product.description %>
<div class="price_line">
<span class="price"><%= number_to_currency(product.price,:precision=>3) %></span>
<%= button_to 'Add to Cart',line_items_path(:product_id => product) ,:remote=>true %>
</div>
</div>
<% end %>
That's the line_items controller function to handle the request
# POST /line_items
# POST /line_items.json
def create
# for exercise only
session[:counter] = nil
#cart = current_cart
product = Product.find(params[:product_id])
#line_item = #cart.add_product(product.id)
respond_to do |format|
if #line_item.save
format.html { redirect_to store_index_path }
format.js
format.json { render json: #line_item, status: :created, location: #line_item }
else
format.html { render action: "new" }
format.json { render json: #line_item.errors, status: :unprocessable_entity }
end
end
end
create.js.erb
$('#cart').html("<%= escape_javascript(render(#cart)) %>");
I fixed the problem.
Thanks to the great article which tell me the ability of firebug to see the source of response from AJAX request.
And JSLint helps me checkout the javascript syntax.
And finally I would like to thanks the Firebug which is such a great tool.
The problem is that the javascript is not being executed if there is any syntax error.
In my problem:
I should use single-quoted instead of double-qouted to wrap the render results. The render results comes out with many HTML with "", and "" which wrap them will cause syntax error in javascript. (double-qouted in double-qouated is not allowed)
So I simply change $('#cart').html("<%= escape_javascript(render(#cart)) %>"); to
$('#cart').html('<%= escape_javascript(render(#cart))%>');
I hope this answer will help the others who also suffer from this nightmare staff.
Help me increase the question rate if this is possible :)
Let's use j() helper method: $('#cart').html("<%=j render(#cart) %>");

Categories