robb
robb

Reputation: 294

Ajax on rails 4

I have an app that allows users to like a post. When someone likes the post, the post request works but the view isn't updated unless I refresh the page. I'm stuck on this one. This is what I have so far:

Javascript

$('.favorite').on('click', function() {
  var $heart = $(this).find('.fa');
  $heart.removeClass('fa-heart-o').addClass('fa-heart');
  // POST request to server to create favorite in db
  $.post('/favorites', {
    favorite: { post_id: $(this).attr('data-id') }
  },
  function(data) {
    console.log(data);
  });
});

The controller

def create
  post = Post.find_by_id(favorite_params[:post_id])
  if current_user.favorite_posts.include? post
    render json: {}, status: :bad_request
  else
    @favorite = current_user.favorites.new(favorite_params)
    if @favorite.save
      render json: @favorite
    else
      render json: { errors: @favorite.errors.full_messages }, status: :unprocessable_entity
  end
end

end

This is the view

<% if current_user.favorite_posts.include? post %>
  <span class="fa fa-heart"> <%= post.favorites.count %></span>
<% else %>
  <span class="fa fa-heart-o"> <%= post.favorites.count %></span>
<% end %>

Any help is appreciated. Thanks.

Upvotes: 4

Views: 154

Answers (3)

Arvind
Arvind

Reputation: 2781

Do this:-

var new_count;
new_count = function() {
  # your script
};



$(document).ready(new_count);
$(document).on('page:load', new_count);

This issue seems due to turbolink checkthis

Upvotes: 6

Richard Peck
Richard Peck

Reputation: 76774

There are two solutions to this:

  1. Invoke the view change with your in-browser ajax
  2. Use the Rails UJS functionality to run the view change on the server

I think your biggest problem is you don't have any functionality to change your view upon a successful request. The two options above are what you have to get it working, so I'll detail them for you here:


Ajax

Ajax will send a request for you; you still have to manage its response & functionality:

$.post('/favorites', { favorite: { post_id: $(this).attr('data-id') }},
.done( function(data) {
  /* Manipulate your view here */
  $("span.fa").text(data);
  console.log("Success");
});

You must remember that Ajax is just an asynchronous request. That is, Javascript will act like a micro-browser, sending data to the server on your behalf.

It will then receive a response from the server (presumably containing the data you want)... it's your job to then manipulate your view with this data.


JS

The other method you could use involves the Rails UJS system. That is, you can fire javascript ERB templates after your controller action is fired.

This would give you the ability to manipulate your view as you need, without editing your current javascript:

$.post('/favorites', { favorite: { post_id: $(this).attr('data-id') }}
  .done( function(data) { console.log(data); });


#app/controllers/favourites_controller.rb
class FavouritesController < ApplicationController
   def create
     ...
     respond_to do |format|
        if @favorite.save
          format.js #-> invokes /views/favourites/create.js.erb
          format.json { render json: @favorite }
        else
          format.js
          format.json { render json: { errors: @favorite.errors.full_messages }, status: :unprocessable_entity }
  end
end

You'll then be able to use app/views/favourites/create.js.erb to manipulate your view:

#app/views/favourites/create.js.erb
$("span.fa").hide();

Upvotes: 2

Dutow
Dutow

Reputation: 5668

Instead of

function(data) {
  console.log(data);
  });

You should update your view. You probably should check for errors, and if there is none, update the content's of your span, using a jQuery selector $( "... span.fa" ).text(new_count).

With this approach, you can calculate the value of new_count as (previous_count_in_the_span + 1), but you might want to return a count value in your response, if it won't cause a performance problem.

Upvotes: 2

Related Questions