2015-01-18 4 views
1

В приложении 4 рельсов я использую link_to для отправки upvote на сообщения через json.Ajax: успех не работает в rails app

Вот что у меня в контроллер сообщений:

def upvote 
    @post = Post.find(params[:id]) 
    @post.liked_by current_user 

    respond_to do |format| 
    format.html {redirect_to :back } 
    format.json { render json: { count: @post.get_upvotes.size } } 
    end 
end 

Вот что у меня есть, на мой взгляд

<%= link_to like_post_path(post), method: :put, class: 'vote', remote: true, data: { type: :json } do %> 
    <%= image_tag('vote.png') %> 
    <%= content_tag :span, post.get_upvotes.size %> 
    <% end %> 


    <script> 

    $(document) 
     .on('ajax:send', '.vote', function() { $(this).addClass('loading'); }) 
     .on('ajax:complete', '.vote', function() { $(this).removeClass('loading'); }) 
     .on('ajax:error', '.vote', function(e, xhr, status, error) { console.log(status); console.log(error); }) 
     .on('ajax:success', '.vote', function (e, data, status, xhr) { 
     $(this).find("span").html(data.count); 
     $(this).find("img").attr("src", '<%= asset_path 'voted.png' %>'); 
     }); 


    </script> 

Когда я нажимаю на ссылку, голосование проходит в формате JSON запрос, я вижу это в своем журнале:

Processing by PostsController#upvote as JSON 

Но по какой-то причине, я отключил javascript, не работает. Ни счетчик, ни значок не обновляются. Как я могу это исправить? Это связано с turbolinks, это связано с тем, где я размещаю javascript?

+0

Выполняется javascript вообще (из точки останова или некоторых вызовов на console.log там) –

ответ

1

В Rails можно выполнить подобную задачу, имея ответ на JavaScript. Добавить в вашем respond_toformat.js похож на format.html тогда имеет вид upvote.js.erb, который выглядит как:

(function() {  

var postId = "#post-<%= @post.id %>"; 

$(postId).find(".vote").find("span").text("<%= @post.get_upvotes.size %>"); 
$(postId).find(".vote").find("img").attr("src", "<%= asset_path "voted.png" %>"); 

})(); 

Я изменил свой призыв .html к .text, так как вы на самом деле не устанавливая какой-либо HTML внутри элемента, нет никаких причин, для звонка .html.

Это сообщение также предполагает, что существует определенный механизм для идентификации ссылки, на которую принадлежит голосование (в примере элемент родительского сообщения имеет идентификатор «post #», где # - идентификатор объекта post).

EDIT

Два изменения, которые я бы сделать, если бы я работал над этим проектом. Сначала я бы привязал путь voted.png к элементу .vote как атрибут данных. data-voted-image-src="<%= asset_path "voted.png" %>". Далее, я бы никогда не передал число в обратном, потому что нет причин для этого. Когда вы нажимаете на голосование, вы можете обрабатывать все на передней панели, считая, что запрос выполнен успешно. Что спасает всю эту потенциальную гадость. Хотя я понимаю, что переход от того, что вы в настоящее время добавляете к атрибуту данных, не является огромным прыжком, я просто нахожу его более семантическим, чем его в JavaScript.

Действие нажмите на ссылку голосов становится:

// Assume all posts have a class 'post' 
// I'm also using 'one' because once they vote they don't need to anymore 
$(".post").find(".vote").one("click", function(e) { 
    var count = parseInt($(this).find("span").text()), 
     votedSrc = $(this).data("voted-image-src"); 
    $(this).find("img").attr("src", votedSrc); 
    $(this).find("span").text(count + 1); 
}); 

Теперь нет ответа от сервера не требуется, и вы можете изменить свой ответ JSON на {success: true} или что-то простое.

+0

* При щелчке по голосованию вы можете обрабатывать все на лицевой стороне, предполагая, что запрос успешный. * Тогда возможно иметь несоответствие между тем, что отображается на странице, и тем, что подсчитывается сервером. Если запрос не удался, сервер не будет обновлять подсчет голосов, но страница увеличит количество голосов. – 7stud

+0

Да. Возможно. Как можно, делая это любым другим способом. Невозможно сохранить синхронизацию клиента на 100%, единственной гарантией является то, что когда вы запрашиваете страницу, данные точны с точки зрения времени и машины. Если у вас есть СПА, тогда вам нужны более последовательные методы для точности в любом случае, такие как веб-сокеты или длительный опрос, чтобы сохранить эти цифры на месте, но даже при длительном опросе я все же предполагал, что ответ был успешным и позволил длинному опросу исправить любые несоответствия , –

+0

@Brandon Buck: Я что-то пропустил здесь, но я думаю, что это побеждает цель модели клиент-сервер. Я имею в виду, что если сервер отправляет успешный ответ, нужно только обновить его. – Rabiees

1

jQuery - это библиотека javascript по умолчанию rails. По умолчанию библиотека javascript по умолчанию была prototype, поэтому старые учебники/документы ее используют. Это то, что Ajax выглядит с JQuery:

приложение/контроллеры/static_pages_controller.rb:

class StaticPagesController < ApplicationController 

    def show_link 
    end 

    def upvote 
    respond_to do |format| 
     format.json {render json: {"count" => "10"} } 
    end 
    end 

end 

приложение/просмотров/static_pages/show_link.html:

<div>Here is an ajax link:</div> 

<%= link_to(
    "Click me", 
    '/static_pages/upvote', 
    'remote' => true, #Submit request with ajax, and put text/javascript on front of Accept header 
    data: { type: :json }) #Put application/json on front of Accept header 
%> 


<div>Upvotes:</div> 
<div id="upvotes">3</div> 

<script> 
$(document).ready(function() { 

    $(this).ajaxSuccess(function(event, jqXHR, ajaxInfo, data) { 

    //var js_obj = JSON.parse(jqXHR.responseText); 
    //$('#upvotes').html(js_obj["count"]); 

    //Apparently, the fourth argument to the handler, data, 
    //already contains the js_obj created from parsing the 
    //json string contained in the response. 

    $('#upvotes').html(data["count"]); 
    }); 

}); 
</script> 

конфигурации/маршруты. гь:

Test1::Application.routes.draw do 

    get 'static_pages/show_link' 
    get 'static_pages/upvote' 
    ... 
end 

URL, чтобы войти в браузере:

http://localhost:3000/static_pages/show_link 

См JQuery документы здесь:

http://api.jquery.com/ajaxSuccess/

Ответ на комментарий:

Вы также можете сделать следующее в контроллере:

def upvote 

    @upvotes = 2 #Set an @variable to the number of upvotes 

    respond_to do |format| 
     format.js {} #By default renders app/views/static_pages/upvote.js.erb 
    end 

    end 

Тогда:

приложение/просмотров/static_pages/upvote.js.erb:

$('#upvotes').html(<%= @upvotes %>) 
+1

Это рельсы, почему бы не использовать ответ JavaScript? –

Смежные вопросы